Servlet 详细教程
Servlet 详细教程
1. Servlet 程序
1.1 什么是 Servlet
- Servlet 是 JavaEE 规范(接口)之一
- Servlet 是 JavaWeb 三大组件之一,三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器
- Servlet 是运行在服务器上的 Java 小程序,用于 接收客户端发送的数据,同时响应给客户端
1.2 如何手动创建实现 Servlet 接口
首先编写一个类,用于实现 Servlet 接口
重写 service 方法,用于处理客户端请求,同时响应数据
package com.cunyu.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Version : 1.0
* Author : 村雨遥
* Email : cunyu1024@foxmail.com
* Website : https://cunyu1943.github.io
* 公众号 :村雨遥
* Date : 2020/6/4 下午3:08
* Project : JavaLearning
* Package : com.cunyu.servlet
* Class : HelloServlet
* Desc : Hello 启动页
*/
public class HelloServlet extends HttpServlet {
/**
* service 专门用于处理请求和响应的方法
*
* @param req 请求
* @param resp 响应
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Hello Servlet,My first Servlet App!");
}
}
- 完成上述步骤后,去
web.xml
中配置 Servlet 接口的访问地址
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 给 Tomcat 配置 Servlet 程序 -->
<servlet>
<!-- Servlet 程序别名(建议为类名) -->
<servlet-name>HelloServlet</servlet-name>
<!-- Servlet 程序的全类名 -->
<servlet-class>com.cunyu.servlet.HelloServlet</servlet-class>
</servlet>
<!-- 给 Servlet 程序配置访问地址 -->
<servlet-mapping>
<!-- 告诉服务器,当前配置的地址给哪个 Servlet 程序使用 -->
<servlet-name>HelloServlet</servlet-name>
<!-- 配置访问地址,表示地址为 http://ip:port/工程路径/hello -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
- 启动 Tomcat 在浏览器中访问
http://localhost:8080/servletTest/hello
,然后后台就会执行service()
方法
1.3 Servlet 的生命周期
- 执行 Servlet 构造器方法,只在第一次访问时创建 Servlet 程序会调用
- 执行
init
初始化方法,只在第一次访问时创建 Servlet 程序会调用 - 执行
service()
方法,每次访问均调用 - 执行
destory()
销毁方法,Web 工程停止时调用
1.4 如何通过 IDEA 快速创建 Servlet 程序
选中 src
目录或者要生成 Servlet 的包,然后单击鼠标右键,New -> Create New Servlet
,接着填写 Servlet 程序名,所属包以及 Servlet 全类名,同时 取消勾选 Java EE 6 即可,勾选则会生成注解式配置,后续学习过程中才会接触到。
点击生成之后,就会生成 Servlet 程序以及在 web.xml
中的配置。
1.5 整个 Servlet 类的继承体系
2. ServletConfig 类
从类名上就可以看出,ServletConfig 是一个配置信息类。Servlet 程序和 ServletConfig 对象均由 Tomcat 创建,而我们只要使用就可以了。此外,Servlet 程序默认是在第一次访问时就创建了,而 ServletConfig 对象则是每个 Servlet 程序创建时所对应创建。
2.1 ServletConfig 类的三大作用
- 获取 Servlet 程序的别名,即
web.xml
中配置的servlet-name
- 获取初始化参数,即
web.xml
中配置的init-param
- 获取 ServletContext 对象
加入我们的 web.xml
配置如下,然后就可以利用 初始化方法来获取上述三个值:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 给 Tomcat 配置 Servlet 程序 -->
<servlet>
<!-- Servlet 程序别名(建议为类名) -->
<servlet-name>HelloServlet</servlet-name>
<!-- Servlet 程序的全类名 -->
<servlet-class>com.cunyu.servlet.HelloServlet</servlet-class>
<init-param>
<param-name>userName</param-name>
<param-value>root</param-value>
</init-param>
</servlet>
<!-- 给 Servlet 程序配置访问地址 -->
<servlet-mapping>
<!-- 告诉服务器,当前配置的地址给哪个 Servlet 程序使用 -->
<servlet-name>HelloServlet</servlet-name>
<!-- 配置访问地址,表示地址为 http://ip:port/工程路径/hello -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
package com.cunyu.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Version : 1.0
* Author : 村雨遥
* Email : cunyu1024@foxmail.com
* Website : https://cunyu1943.github.io
* 公众号 :村雨遥
* Date : 2020/6/4 下午3:08
* Project : JavaLearning
* Package : com.cunyu.servlet
* Class : HelloServlet
* Desc : Hello 启动页
*/
public class HelloServlet extends HttpServlet {
/**
* service 专门用于处理请求和响应的方法
*
* @param req 请求
* @param resp 响应
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Hello Servlet,My first Servlet App!");
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("初始化方法");
// 获取 Servlet 程序别名 servlet-name
System.out.println("别名:" + config.getServletName());
// 获取初始化参数 init-param
System.out.println("初始化参数:" + config.getInitParameter("userName"));
// 获取 ServletContext 对象
System.out.println(config.getServletContext());
}
}
3. ServletContext 类
3.1 ServletContext 是啥
ServletContext 是一个接口,用于表示 Servlet 上下文对象
ServletContext 对象是一个 域对象
每个 Web 工程只对应 一个 ServletContext 对象实例
每个 ServletContext 在 Web 工程部署启动时创建,然后在 Web 工程停止时销毁
3.2 ServletContext 的作用
- 获取
web.xml
配置中的上下文参数context-param
- 获取当前 Web 工程路径,如
/ServletTest
- 获取工程部署后在服务器的中的绝对路径,包括各种静态资源等路径
- ServletContext 是通过 键值对(Map) 一样存取数据
以下对上述 4 个作用进行实例介绍,首先在 web.xml
加入如下配置,然后通过程序来获取各种参数:
<!--context-param 是上下文参数,属于 Web 工程-->
<context-param>
<param-name>wechat</param-name>
<param-value>cunyu1943</param-value>
</context-param>
<servlet>
<servlet-name>ServletContextServlet</servlet-name>
<servlet-class>com.cunyu.servlet.ServletContextServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletContextServlet</servlet-name>
<url-pattern>/servletContext</url-pattern>
</servlet-mapping>
package com.cunyu.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Version : 1.0
* Author : 村雨遥
* Email : cunyu1024@foxmail.com
* Website : https://cunyu1943.github.io
* 公众号 :村雨遥
* Date : 2020/6/5 上午8:36
* Project : JavaLearning
* Package : ${PACKAGE_NAME}
* Class : ${CLASS_NAME}
* Desc : ServletContext 功能
*/
public class ServletContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取上下文参数 context-param
ServletContext servletContext = getServletContext();
String url = servletContext.getInitParameter("url");
System.out.println("URL 的值是:" + url);
// 2. 获取工程路径
System.out.println("工程路径:" + servletContext.getContextPath());
// 3. 获取工程部署后服务器上的绝对路径
// 其中 / 被解析为:http://ip:port/工程名/ ,映射到 IDEA 代码的 web 目录
System.out.println("工程部署绝对路径:" + servletContext.getRealPath("/"));
// 4. 通过 键值对 存取数据,注意:ServletContext 属于 Web 工程,所以只要工程启动创建之后,Servlet 程序都能访问,直到关停 Web 工程
System.out.println("ServletContext 对象:" + servletContext);
// 存数据
servletContext.setAttribute("password", "1234567");
// 取数据
System.out.println("password 的值是:" + servletContext.getAttribute("password"));
}
}
4. HTTP 协议
4.1 什么是 HTTP 协议
协议 即指两方或多方通过一定协商约定后,大家都要遵守的规则,叫做协议。
而 HTTP 协议 ,即指 客户端和服务器之间互相通信时,发送数据时所需要遵守的规则,HTTP 协议中的数据又叫做 报文。
4.2 请求的 HTTP 协议格式
客户端向服务器发送数据的行为叫做 请求,而服务器向客户端回传数据的行为叫做 响应。
GET 请求
由 请求行 + 请求头 组成,其中 请求行 包括 请求的方式、请求的资源路径以及请求的协议版本号,而 请求头 则是由 key-value
对组成,不同键值对对应不同含义,具体请看如下图实例。GET 请求最常用的地方:
form
标签method=get
a
标签link
标签引入css
Script
标签引入js
img
标签引入图片iframe
引入 HTML 页面- 浏览器中地址栏输入地址后回车
POST 请求
POST 请求和 GET 的最大区别在于 请求头(即发送给服务器的数据),POST 由 请求行 + 请求头 + 请求体 组成,其中请求行与请求头的含义和 GET 请求的含义相同,而 请求头则是 POST 方式独有,具体含义如下,最常用的地方:
form
标签method=post
4.3 响应的 HTTP 协议格式
响应主要由 响应行 + 响应头 + 响应体 共同组成,响应行中又包括 响应的协议和版本号、响应状态码以及响应状态描述符,而 响应头则是同样由不同的键值对组成,响应体中则是回传给客户端的数据,具体看下边的示例:
4.4 常用响应码
响应码 | 说明 |
---|---|
200 | 请求成功 |
302 | 请求重定向 |
404 | 请求服务器已经收到,但需要的数据不存在(请求地址错误) |
500 | 服务器已经收到请求,但服务器内部错误(代码错误) |
4.5 MIME 类型说明
MIME 全称 多功能 Internet 邮件扩充服务 (Multipurpose Internet Mail Extension)
,是 HTTP 协议中的数据类型,格式是 大类型/小类型,并与某种文件扩展名相对应,最常见的 MIME 类型如下:
文件类型 | 文件扩展名 | MIME 类型 |
---|---|---|
超文本标记语言文本 | .html、.htm | text/html |
普通文本 | .txt | text/plain |
RTF 文本 | .rtf | application/rtg |
GIF 图形 | .gif | image/gif |
JPEG 图形 | .jpeg、.jpg | image/jpeg |
au 声音文件 | .au | audio/basic |
MIDI 音乐文件 | .mid、.midi | audio/midi、audio/x-midi |
RealAudio 音乐文件 | .ra、.ram | audio/x-pn-realaudio |
MPEG 文件 | .mpg、.mpeg | video/mpeg |
AVI 文件 | .avi | video/x-msvideo |
GZIP 文件 | .gz | application/x-gzip |
TAR 文件 | .tar | application/x-tar |
5 HttpServletRequest 类
5.1 HttpServletRequest 类的作用
当每次 Tomcat 服务器接收到来自浏览器的请求时,Tomcat 服务器都会把请求过来的 HTTP 协议信息解析好封装到 Request
对象中,然后传递到 service
方法(doGet
和 doPost
)供浏览器使用。而我们则可以通过 HttpServletRequest
对象获取到 所有请求的信息。
5.2 HttpServletRequest 类常用方法
方法 | 说明 |
---|---|
getRequestURI() | 获取请求的资源路径 |
getRequestURL() | 获取请求的统一资源定位符(绝对路径) |
getRemoteHost() | 获取客户端的 ip |
getHeader() | 获取请求头 |
getParameter() | 获取请求的参数 |
getParameterValues() | 获取请求的参数(多个值) |
getMethod() | 获取请求的方式 GET 或 POST |
setAttribute(key, value) | 设置域数据 |
getAttribute(key) | 获取域数据 |
getRequestDispatcher() | 获取请求转发对象 |
5.3 POST 和 GET 请求方式的中文乱码问题
当以 POST 或 GET 方式请求时,遇到中文可能会出现乱码,对应解决方法如下:
- POST 方式:直接将请求体的字符集设置为 UTF-8 即可
- GET 方式:先以 iso8859-1 进行编码,然后再以 UTF-8 进行解码
package com.cunyu.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
* Version : 1.0
* Author : 村雨遥
* Email : cunyu1024@foxmail.com
* Website : https://cunyu1943.github.io
* 公众号 :村雨遥
* Date : 2020/6/6 下午9:18
* Project : JavaLearning
* Package : ${PACKAGE_NAME}
* Class : ${CLASS_NAME}
* Desc : 获取请求参数中文乱码问题
*/
public class ParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// POST 中文乱码,设置请求体字符集 UTF-8,要在获取参数前调用
req.setCharacterEncoding("UTF-8");
System.out.println(req.getParameter("hobby"));
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
// GET 中文乱码
// 先以 iso8859-1 进行编码
// 然后以 UTF-8 进行解码
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
System.out.println("用户名:" + username);
System.out.println("密码:" + password);
}
}
5.4 请求的转发
定义
请求的转发即 当服务器收到来自客户端的请求时,从一个资源跳转到另一个资源的操作。
特点
- 地址栏未变
- 属于一次请求
- 共享 Request 域中的参数
- 可以转发到 WEB-INF 目录下
- 不能访问工程之外的资源
5.5 base 标签的作用
用于设置页面相对路径工作时参照的路径,参照某一地址进行跳转。
<base href="https:cunyu1943.github.io">
5.6 Web 中 / 的不同意义
在 Web 中 / 是一种绝对路径,若 被浏览器解析,则得到的地址是 :http:/ip:port/
;若 被服务器解析,则得到的地址是:http://ip:port/工程路径
。
注意: response.sendRedirect("/");
,表示将 / 发送给浏览器解析,得到 http://ip:port/
6. HttpServletResponse 类
6.1 HttpServletResponse 的作用
同 HttpServletRequest
类一样,当每次来自客户端的请求进来时,服务器都会创建一个 Response
对象,然后传递给 Servlet 程序使用。HttpServletRequest
表示请求过来的信息,HttpServletResponse
则表示所有响应的信息。 当设置服务器返回给客户端信息时,通过 HttpServletResponse
对象进行。
6.2 两个输出流
输出流分为 字节流和字符流,两者对应的方法和功能如下表所示,当我们使用时,只能同时使用其中之一 。
输出流类型 | 方法 | 功能 |
---|---|---|
字节流 | getOutputStream() | 常用于下载(传递二进制数据) |
字符流 | getWriter() | 常用于回传字符串 |
6.3 如何向客户端回传数据及中文乱码
通常我们需要向客户端回传数据,如果是回传字符串等数据,我们可以使用 字符流方法 getWriter()
。
public class ResponseIOServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpSevletResponse resp) throws ServletException, IOException{
// 向客户端回传 字符串 数据
PrintWriter writer = resp.getWriter();
writer.write("response's content!!!");
}
}
但当我们回传中文时,可能会出现乱码问题,为了解决这一问题,通常有两种解决方案:
- 设置服务器字符集为 UTF-8,同时通过响应头设置浏览器也使用 UTF-8 字符集
// 设置服务器字符集
resp.setCharacterEncoding("UTF-8");
// 通过响应头设置浏览器字符集
resp.setHeader("Content-Type", "text/html;charset=UTF-8");
- 同时设置服务器和客户端均使用 UTF-8 字符集,但是必须在获取流对象之前调用,更为推荐
// 同时设置服务器和客户端字符集
resp.setContentType("text/html;charset=UTF-8")
6.4 请求重定向
定义
请求重定向是 指客户端给服务器发送请求,然后服务器回传给客户端一些地址,然客户端去访问。之所以叫做重定向,是因为之前的地址可能已经被废弃。
特点
- 地址栏变化
- 两次请求
- 不共享 Request 域中数据
- 不能重定向到 WEB-INF 目录下资源
- 能访问工程外的资源
实现重定向的两种方式
- 设置响应状态码 302 表示重定向,然后通过设置响应头说明新地址
// 设置响应状态码
resp.setStatus(302);
// 通过设置响应头,说明新地址
resp.setHeader("Location", "https://cunyu1943.github.io");
- 直接使用
sendRedirect()
方法设置新地址即可,更为推荐
resp.sendRedirect("https://cunyu1943.github.io");