一文把Servlet整的明明白白!1️⃣
一、Servlet概述
1.1、Servlet是什么
- Servlet 是 JavaEE 规范之一。规范就是接口。
- Servlet 就 JavaWeb 三大组件之一。三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
- Servlet 是运行在服务器上的一个 java 小程序,它可以接收客户端发送过来的请求,并响应数据给客户端。
简单来说:Servlet 是运行在 Web服务器(如Tomcat服务器)的,使用 Java编写的小应用程序。
1.2、Servlet的示范
public class HelloServlet implements Servlet {
/**
* service 方法是专门用来处理请求和响应的
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello 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">
<!--servlet 标签给 Tomcat 配置 Servlet 程序-->
<servlet>
<!--servlet-name 标签 Servlet 程序起一个别名(一般是类名) -->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class 是 Servlet 程序的全类名-->
<servlet-class>com.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet-mapping 标签给 servlet 程序配置访问地址-->
<servlet-mapping>
<!--servlet-name 标签的作用是告诉服务器,我当前配置的地址给哪个 Servlet 程序使用-->
<servlet-name>HelloServlet</servlet-name>
<!--url-pattern 标签配置访问地址<br/>
/斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
<br/>
/hello 表示地址为:http://ip:port/工程路径/hello
<br/>
-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
1.3、常见错误
1.3.1、url-pattern 中配置的路径没有以斜杠打头
1.3.2、servlet-name 配置的值不存在
二、Servlet生命周期
2.1、Servlet生命周期
Servlet 对象的生命周期:Servlet 创建对象–>初始化操作–> 运行操作–>销毁操作
Web 服务器管理了 Servlet 的生命周期,Servlet 对象整个过程都是 Web 服务器来管理的。
2.2、Servlet 接口中生命周期方法
生命周期方法 | 作用 | 运行次数 |
---|---|---|
构造方法 | 在对象实例化的时候执行 必须有公共的无参数构造方法 |
1次 |
void init(ServletConfig config) | 在初始化的时候执行 | 1次 |
void service(ServletRequest req, ServletResponse res) | 每次请求都会执行 | n次 |
void destroy() | 在服务器正常关闭的时候 | 1次 |
2.3、Servlet的请求流程
localhost:8080/one/hello
# 1. 浏览器发送请求,Tomcat接收到请求并通过结息请求地址来获取到要访问的项目路径和资源路径。
项目路径:/one
资源路径:/hello
# 2. Tomcat会扫描服务器内部的one项目下的所有Servlet,获取每一个Servlet的访问地址,并存储到一个集合中。资源路径作为ket,类的全限定名作为value。
Map<String,String> map = new HashMap<>();
map.put("/one","com.servlet.HelloServlet");
# 3. 将资源路径/one作为key从map中获取value,得到了类的全限定名。
# 4. 他会预先创建一个Servlet实例缓存池(key是Servlet的全限定名,value是Servlet的实例对象),拿着找到的key,去servletmap中寻找,如果找得到说明不是第一次访问,如果找不到,说明是第一次访问。
Map<String,Servlet> servletmap = new HashMap<>();
if(servletmap.get(“全限定名”) == null){
// 第一次访问,执行第5步
} else{
// 第N次,直接执行第7步
}
# 5. 通过反射实例化这个Servlet对象,并放入实例缓存池中。
# 6. Tomcat创建ServletConfig对象,然后调用init方法,传入创建的Servlet对象
# 7. 创建HttpRequest和HttpResponse对象,并调用service方法,传入HttpRequest和HttpResponse对象。
# 8. 等待下一次访问。
2.4、Servlet的继承体系
2.4.1、GenericServlet类
默认实现了 Servlet 和 ServletConfig 这两个接口,它的子类是 HttpServlet,如果我们写的Servlet使用的是 Http 协议。
package cn.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet(urlPatterns = "/demo")
public class DemoServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("我是GenericServlet子类");
}
}
2.4.2、HttpServlet类
package cn.httpservlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/demo02")
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("我是HttpServlet的子类");
}
}
2.4.3、小结
-
GenericServlet 是一个通用的 Servlet,可以用来处理各种协议发出的请求和响应。
-
HttpServlet 是专门用来处理 HTTP 协议发送的请求,现在所有的浏览器发请求都是使用 HTTP 协议,因此以后我们开发 Servlet 只需要继承 HttpServlet 即可,可以按照如下步骤开发:
1. 创建类继承 HttpServlet
2. 重写参数带着 Http 开头的 service 方法:在该方法中处理请求并响应数据。
注意事项:不要在该方法中调用父类的 service 方法(405)
2.5、ServletConfig 类
ServletConfig 类从类名上来看,就知道是 Servlet 程序的配置信息类。
Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责使用。
Servlet 程序默认是第一次访问的时候创建,ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象。
2.5.1、ServletConfig 类的三大作用
- 可以获取 Servlet 程序的别名 servlet-name 的值。
- 获取初始化参数 init-param。
- 获取 ServletContext 对象。
2.5.2、常用方法
ServletConfig接口常用方法 | 说明 |
---|---|
String getInitParameter(“参数名”) | 通过指定的参数名得到参数 |
2.5.3、使用演示
根据不同的编码格式响应数据给浏览器,编码格式作为Servlet的初始化配置参数,在Servlet的service方法中读取初始化配置参数并输出。
public class ServletConfigServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得配置对象
ServletConfig config = this.getServletConfig();
// 获得初始化参数值
String encoding = config.getInitParameter("encoding");
if ("utf-8".equalsIgnoreCase(encoding)){
// 模拟响应数据给浏览器
System.out.println("执行utf-8编码操作");
} else {
// 模拟响应数据给浏览器
System.out.println("执行gbk编码操作");
}
}
}
<servlet>
<!--servlet名字-->
<servlet-name>ServletConfigServlet</servlet-name>
<!--servlet全限定名-->
<servlet-class>com.servlet</servlet-class>
<init-param>
<!--参数名-->
<param-name>encoding</param-name>
<!--参数值-->
<param-value>utf-8</param-value>
</init-param>
</servlet>
<!--servlet的访问地址-->
<servlet-mapping>
<!--servlet名字:必须与上面的servlet名字相同-->
<servlet-name>ServletConfigServlet</servlet-name>
<!--浏览器访问的地址,必须以/打头-->
<url-patten>ServletConfigServlet</url-patten>
</servlet-mapping>
2.6、ServletContext 类
2.6.1、ServletContext概述
ServletContext 是一个接口,它表示 Servlet 上下文对象,**一个 web 工程,只有一个 ServletContext 对象实例。**ServletContext 对象是一个域对象。ServletContext 是在 web 工程部署启动的时候创建。在 web 工程停止的时候销毁。
2.6.2、ServletContext 类的四个作用
- 获取 web.xml 中配置的上下文参数 context-param。
- 获取当前的工程路径,格式: /工程路径。
- 获取工程部署后在服务器硬盘上的绝对路径。
- 像 Map 一样存取数据
2.7、域对象
域对象,是可以像 Map 一样存取数据的对象,叫域对象。这里的域指的是存取数据的操作范围,整个 web 工程。
他的作用是数据共享。
存数据 | 取数据 | 删除数据 | |
---|---|---|---|
map | put() | get() | remove() |
域对象 | setAttribute() | getAttribute() | removeAttribute() |
2.8、 loadOnStartup
让 web 容器启动的时候创建并初始化 Servlet。取值范围1到10,值越小越先加载。默认值是-1:代表第1次访问时创建和初始化
他可以在xml中进行配置:
<load-on-startup>1</load-on-startup>
他还可以利用注解配置的方法:
@WebServlet(urlPatterns = "/response", loadOnStartup =1)
三、请求对象
3.1、HttpServletRequest 对象概述
HttpServletRequest 是一个接口,该接口的实现类对象称为请求对象,请求对象封装了所有的请求信息(请求行,请求头,请求体(请求参数))。
HttpServletRequest 接口包含了大量的方法。由 Tomcat 去实现这个对象,并且在 servlet 启动的时候调用service() 将请求对象传递进来了。我们在 service 方法中直接使用即可。
3.2、HttpServletRequest 对象常用方法
request 与请求行相关方法 | 功能描述 |
---|---|
String getMethod() | 获得请求方式 GET 或 POST |
String getRequestURI() | Uniform Resource Identifier统一资源标识符,代表一个资源名字 |
StringBuffer getRequestURL() | Uniform Resource Locator 统一资源定位符,代表一个可以访问地址 |
String getProtocol() | 获得协议和版本 |
String getContextPath() | 获得上下文路径(项目名path) |
request 与请求头相关方法 | 功能描述 |
---|---|
String getHeader(String headName) | 得到指定的请求头的值 参数:键的名字 返回:相应请求头的值 |
request与请求参数相关方法 | 功能描述 |
---|---|
String getParameter(String name) | 通过参数名得到一项参数值 |
String[] getParameterValues(String name) | 根据参数名得到一组同名的值 复选框,下拉列表多选 |
Enumeration getParameterNames() | 获得所有的参数名 |
Map getParameterMap() | 得到表单所有的参数键和值,封装成Map对象 |
Enumeration接口中方法 | 说明 |
---|---|
boolean hasMoreElements() | 如果还有其它元素,返回true |
E nextElement() | 返回下一个元素 |
package com.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/line")
public class RequestLineServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得请求行信息
System.out.println("得到方法:" + request.getMethod());
System.out.println("统一资源标识符:" + request.getRequestURI());
System.out.println("统一资源定位符:" + request.getRequestURL());
System.out.println("协议和版本:" + request.getProtocol());
System.out.println("当前项目地址:" + request.getContextPath());
// 得到一个请求头
System.out.println("得到host的请求头值:" + request.getHeader("host"));
}
}
3.3、请求参数乱码问题(POST)
3.3.1、请求参数产生乱码的原因
在浏览器发送数据给服务器的时候,使用 utf-8 编码,但服务器解码默认使用 ISO-8859-1 解码:欧洲码,不支持汉字的。
如果是 GET 请求且 Tomcat 版本大于8.0.5,则不需要考虑乱码问题,否则 GET 请求也需要考虑乱码问题。
3.3.2、POST方式乱码解决方案
- 解决方法:request.setCharacterEncoding(“utf-8”) 设置请求参数的编码为UTF-8。
- 代码位置:设置请求的编码这句话一定放在获取请求参数之前。
- 页面的编码:这个编码一定要与页面的编码相同。如果页面使用的是 GBK,则这里也要用GBK。
四、响应对象
4.1、HttpServletResponse对象概述
HttpServletResponse 是一个接口,该接口的实现类对象称为响应对象,用于响应数据(响应行,响应头,响应体)给浏览器。HttpServletResponse 接口包含了大量的方法。由 Tomcat 去实现这个对象,并且在 servlet 启动的时候调用 service() 将请求对象和响应对象传递进来了。我们在 service 方法中直接使用即可。
4.2、响应数据相关方法
响应体相关的方法 | 功能描述 |
---|---|
OutputStream getOutputStream() | 如果服务器端返回的是二进制数据 则使用这个方法,比如图片 |
PrintWriter getWriter() | 如果服务器端返回的是字符的文本数据,使用这个方法 |
@WebServlet(urlPatterns = "/response")
public class ResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得字符打印流对象
PrintWriter out = response.getWriter();
// 响应数据给浏览器显示
out.print("<h1 style='color:red'>hello browser<h1>");
}
}
4.3、响应内容中文乱码问题
4.3.1、乱码原因
因为 Tomcat 中响应体默认的是欧洲码表,ISO-8859-1 不支持中文。
4.3.2、解决办法
4.3.2、方法一
在获得打印流对象之前,通过下面方法设置打印流的编码为utf-8
response方法 | 说明 |
---|---|
response.setCharacterEncoding(“字符集”) | 用于设置响应体的字符集 设置打印流使用的码表 |
@WebServlet(urlPatterns = "/response")
public class ResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置打印流编码
response.setCharacterEncoding("utf-8");
// 获得字符打印流对象
PrintWriter out = response.getWriter();
// 响应数据给浏览器显示
out.print("<h1 style='color:red'>你好 browser<h1>");
}
}
4.3.3、方法二
通过下面方法告诉浏览器返回数据类型和编码
响应对象的方法 | 功能描述 |
---|---|
void setContentType(String type) | 1. 告诉浏览器返回内容类型 2. 设置打印流编码 注意: 必须在获取流之前设置,否则无效 |
@WebServlet(urlPatterns = "/response")
public class ResponseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置打印流编码
// response.setCharacterEncoding("utf-8");
// 告诉浏览器返回内容类型并设置打印流编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流对象
PrintWriter out = response.getWriter();
// 响应数据给浏览器显示
out.print("<h1 style='color:red'>你好 browser<h1>");
}
}
- 点赞
- 收藏
- 关注作者
评论(0)