相关链接:
- IDEA2020版创建Servlet(Web项目)完整教程 - 冷丁_Mitnick - 博客园 (cnblogs.com)
- JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)-CSDN博客
- Servlet的xml配置与注解配置_servlet xml-CSDN博客
- 一天打通Servlet全套教程 哔哩哔哩 bilibili
一、Servlet简介
Servlet(Server Applet),全称Java Servlet。是用Java编写的服务器端程序,其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet工作模式
- 客户端发送请求至服务器;
- 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器;
- 服务器将响应返回客户端。
二、Servlet的体系结构
Servlet由两个Java包组成:javax.servlet和javax.servlet.http。在javax.servlet包中定义了所有的Servlet类都必须实现或扩展的的通用接口和类;在javax.servlet.http包中定义了采用HTTP通信协议的HttpServlet类。其中的一些比较核心的接口和类之间的关系如下,图中提到的方法是在使用该接口或类时必须要实现的:
1. Servlet 接口
Servlet
接口是所有 Servlet 类的根接口。其常用方法如下:
// 初始化 Servlet
public void init(ServletConfig config) throws ServletException;
// 获取 Servlet 的配置信息
public ServletConfig getServletConfig();
// 处理请求
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
// 获取 Servlet 的信息
public String getServletInfo();
// 销毁 Servlet
public void destroy();
2. Serializable 接口
Serializable
接口是 Java 中的标记接口,用于标识类的实例可以被序列化。实现该接口的类表示它们的实例可以被转换为字节序列,以便在网络上传输或保存到文件中。其常用方法如下:
// 序列化对象
private void writeObject(ObjectOutputStream out) throws IOException;
// 反序列化对象
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
3. ServletConfig 接口
ServletConfig
接口提供了 Servlet 配置信息的访问方法。具体来说,它允许 Servlet 访问在部署描述符中配置的初始化参数,以及获取与 ServletContext 相关联的配置信息。其常用方法如下:
// 获取 Servlet 的名称
public String getServletName();
// 获取初始化参数
public String getInitParameter(String name);
// 获取所有初始化参数的名称
public Enumeration<String> getInitParameterNames();
// 获取 ServletContext
public ServletContext getServletContext();
4. GenericServlet 抽象类
GenericServlet
实现了 Servlet
接口,为 Servlet 提供了一些通用的功能,但它本身并不直接处理 HTTP 请求和响应。GenericServlet
的 service()
方法接受通用的 ServletRequest
和 ServletResponse
对象。其常用方法如下:
// 初始化 Servlet
public void init(ServletConfig config) throws ServletException;
// 获取 Servlet 的配置信息
public ServletConfig getServletConfig();
// 获取 Servlet 的名称
public String getServletName();
// 处理请求
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
// 销毁 Servlet
public void destroy();
// 获取初始化参数
public String getInitParameter(String name);
// 获取所有初始化参数的名称
public Enumeration<String> getInitParameterNames();
5. HttpServlet 抽象类
HttpServlet
继承自 GenericServlet
,专门用于处理 HTTP 请求和响应。HttpServlet
提供了对 HTTP 请求方法的更直接的支持,如 doGet()
、doPost()
等。其常用方法如下:
// 处理 HTTP GET 请求
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP POST 请求
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP PUT 请求
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP DELETE 请求
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP HEAD 请求
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP OPTIONS 请求
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP TRACE 请求
protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理 HTTP PATCH 请求
protected void doPatch(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
// 处理通用的 HTTP 请求
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
三、Servlet的生命周期
Servlet 的生命周期指一个Servlet 对象从创建到销毁的过程,其生命周期分为四个阶段:实例化、初始化、处理请求、服务终止。
init()
,service()
,destroy()
是 Servlet 生命周期的方法,分别对应 Servlet 生命周期的后三个阶段,方法中的代码在处于对应的生命周期时被执行。
1. 实例化阶段
当用户第一次向 Servlet 容器发出 HTTP 请求要求访问某个 Servlet 时,Servlet 容器会在整个容器中搜索该 Servlet 对象,如果发现这个 Servlet 对象没有被实例化,便创建这个 Servlet 对象,之后进入初始化阶段;如果找到了该 Servlet 对象的实例,则不去创建而是直接进入运行阶段。
2. 初始化阶段
在创建 Servlet 对象后会调用该对象的 init() 方法完成初始化,随后 Servlet 进入到运行阶段。
注意:在 Servlet 对象的整个生命周期内,它的 init() 方法只会在创建该对象时被调用一次。
3. 运行阶段
这是 Servlet 生命周期中最核心的阶段。在该阶段中,Servlet 容器会为当前的请求创建一个 ServletRequest 对象和一个 ServletResponse 对象(分别代表请求和响应),service() 方法从 ServletRequest 对象中获得用户的详细请求信息并可以检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法处理该请求,处理完成后通过 ServletResponse 对象生成响应结果。
注意:在 Servlet 对象的整个生命周期内,用户每次请求访问 Servlet 时,Servlet 容器都会调用一次 Servlet 的 service() 方法,并且创建新的 ServletRequest 和 ServletResponse 对象。
4. 销毁阶段
当服务器停止时,Servlet 容器需要回收 Servlet 对象所占用的内存,在回收之前,会自动调用该对象的 destroy() 方法做好回收内存前的准备,辟如关闭后台线程。
注意:在 Servlet 对象的整个生命周期内,destroy() 方法只会在销毁该对象被调用一次。Servlet 对象一旦创建就会驻留在内存中一直等待客户端的访问,直到服务器关闭或项目被移除出容器时,Servlet 对象才会被销毁。
四、Servlet的注解配置
1. xml配置
假设一个java EE项目中存在com.example.SimpleServlet.java
这个类,其中的代码如下:
package com.example.SimpleServlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class SimpleServlet extends HttpServlet {
// 处理get请求
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
PrintWriter out = resp.getWriter(); // 实例化out对象。
out.println("<HTML>");
out.println("<HEAD>");
out.println("<TITLE>THE FIRST SERVLET</TITLE>");
out.println("</HEAD>");
out.println("<BODY>");
out.println("<H1>Hello World!</H1>");
out.println("</BODY>");
out.println("</HTML>");
out.close();
}
// 处理post请求
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
this.doGet(req, resp);
}
}
那么如果我们想要通过浏览器对这个 Servlet 类发送请求并进行响应,就要先在项目的xml文件中配置地址映射:
<servlet>
<servlet-name>simple</servlet-name>
<servlet-class>com.example.SimpleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>simple</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
配置好映射后启动项目,我们便可以通过输入网址http://localhost:8080/demo来访问这个Servlet应用。
上面的xml文件中的标签及对应含义如下:
<servlet-name>
:定义的Servlet应用名字;<servlet-class>
:定义的Servlet应用名字所对应的具体Servlet文件;<servlet-mapping>
:地址映射<servlet-name>
:定义的Servlet应用名字;<url-pattern>
:映射的地址。
2. 注解配置
Servlet 的注解配置是一种简化 Servlet 配置的方式,通过在 Servlet 类上使用注解,可以替代传统的在 web.xml 文件中配置 Servlet 的方式。注解配置使得 Servlet 的定义更加直观和简洁,减少了配置的繁琐性。Servlet3.0提供了注解(annotation),我们可以不用在web.xml里面配置servlet,只需要加上@WebServlet注解就可以修改该servlet的属性。
以下是 Servlet 常用注解及其说明:
注解 | 说明 | 示例 | 配置值 |
---|---|---|---|
@WebServlet | 标识一个类为 Servlet,并指定访问路径等配置 | @WebServlet(urlPatterns = "/example", name = "ExampleServlet") | urlPatterns , name , loadOnStartup , asyncSupported 等 |
@WebInitParam | 在 @WebServlet 中设置初始化参数 | @WebServlet(initParams = {@WebInitParam(name = "paramName", value = "paramValue")}) | name , value 等 |
@HttpMethodConstraint | 指定对特定 HTTP 方法的约束条件 | @HttpMethodConstraint(value = "GET", rolesAllowed = "admin") | value , emptyRoleSemantic , transportGuarantee 等 |
@ServletSecurity | 配置 Servlet 的安全约束 | @ServletSecurity(@HttpConstraint(transportGuarantee = ServletSecurity.TransportGuarantee.CONFIDENTIAL, rolesAllowed = "user")) | @HttpConstraint 中的各个属性 |
@MultipartConfig | 配置 Servlet 处理文件上传的相关参数 | @MultipartConfig(location = "/tmp", fileSizeThreshold = 1024 * 1024, maxFileSize = 1024 * 1024 * 5, maxRequestSize = 1024 * 1024 * 5 * 5) | location , fileSizeThreshold , maxFileSize , maxRequestSize 等 |
@WebFilter | 标识一个类为过滤器,并指定过滤路径 | @WebFilter(filterName = "MyFilter", urlPatterns = "/*") | filterName , urlPatterns , dispatcherTypes , initParams 等 |
@WebListener | 标识一个类为监听器 | @WebListener | 无 |
使用注解配置,我们可以将上面的xml配置简化为@WebServlet(name = "simple", urlPatterns = "/demo")
,通过在对应的 Servlet 类上使用该注解可以更方便地实现实现地址映射。
五、Http协议请求的处理与响应
ServletRequest
和 ServletResponse
接口是Servlet中定义的两个核心接口,用于处理与客户端的通信。
ServletRequest
提供了一种通用的方式来获取客户端请求的信息,包括请求参数、请求头、会话等,它是与协议无关的接口,适用于处理各种类型的请求,不仅限于 HTTP。ServletResponse
用于封装服务器对客户端的响应。它提供了设置响应状态码、响应头、写入响应体等方法。与ServletRequest
类似,ServletResponse
也是与协议无关的接口,可用于处理各种类型的响应。
HttpServletRequest
和 HttpServletResponse
分别是上面两个接口的子接口,专门用于处理 HTTP 请求和响应。它们扩展了 上面两个接口,提供了更丰富的处理 HTTP 请求和响应的方法。
HttpServletRequest
提供了获取 HTTP 方法、请求 URI、请求头等特定于 HTTP 的信息。HttpServletResponse
提供了设置 HTTP 状态码、响应头、Cookie 等特定于 HTTP 的功能。
1. HttpServletRequest常用方法
// 获取请求的方法(如 GET、POST)
public String getMethod();
// 获取请求的 URI
public String getRequestURI();
// 获取请求头的值
public String getHeader(String name);
// 获取所有请求头的名称
public Enumeration<String> getHeaderNames();
// 获取请求参数的值
public String getParameter(String name);
// 获取所有请求参数的名称
public Enumeration<String> getParameterNames();
// 获取请求参数的所有值
public String[] getParameterValues(String name);
// 获取 Cookie 数组
public Cookie[] getCookies();
// 获取会话(如果不存在则创建)
public HttpSession getSession();
// 获取会话(如果不存在则创建),指定是否创建新的会话
public HttpSession getSession(boolean create);
// 获取请求的字符编码
public String getCharacterEncoding();
// 获取请求的内容长度
public int getContentLength();
// 获取请求的内容类型
public String getContentType();
// 设置响应状态码
public void setStatus(int sc);
// 设置响应头
public void setHeader(String name, String value);
// 添加响应头
public void addHeader(String name, String value);
// 设置响应内容的字符编码
public void setCharacterEncoding(String charset);
// 设置响应内容的类型
public void setContentType(String type);
// 获取响应的字符输出流
public PrintWriter getWriter() throws IOException;
// 获取响应的字节输出流
public ServletOutputStream getOutputStream() throws IOException;
// 设置响应的缓存控制
public void setCacheControl(String control);
// 设置响应的过期时间
public void setDateHeader(String name, long date);
// 设置响应的内容长度
public void setContentLength(int len);
// 发送重定向响应
public void sendRedirect(String location) throws IOException;
// 向响应输出文本
public void PrintWriter writer.println(String text) throws IOException;
2. HttpServletResponse常用方法
// 设置响应状态码
public void setStatus(int sc);
// 设置响应头
public void setHeader(String name, String value);
// 添加响应头
public void addHeader(String name, String value);
// 设置响应内容的字符编码
public void setCharacterEncoding(String charset);
// 设置响应内容的类型
public void setContentType(String type);
// 获取响应的字符输出流
public PrintWriter getWriter() throws IOException;
// 获取响应的字节输出流
public ServletOutputStream getOutputStream() throws IOException;
// 设置响应的缓存控制
public void setCacheControl(String control);
// 设置响应的过期时间
public void setDateHeader(String name, long date);
// 设置响应的内容长度
public void setContentLength(int len);
// 发送重定向响应
public void sendRedirect(String location) throws IOException;
// 向响应输出文本
public void PrintWriter writer.println(String text) throws IOException;
六、Servlet的上下文
Servlet上下文又叫做:ServletContext。当WEB服务器启动时,会为每一个WEB应用程序(webapps下的每个目录就是一个应用程序)创建一块共享的存储区域。ServletContext也叫做“公共区域”,也就是同一个WEB应用程序中,所有的Servlet和JSP都可以共享同一个区域。ServletContext在WEB服务器启动时创建,服务器关闭时销毁。容器在启动的时候,会为每一个web应用创建唯一的一个符合ServletContext接口的对象,该对象一般称之为"servlet上下文"。
1. 主要作用
存储初始化参数:
- Servlet 上下文允许在部署描述符中配置的初始化参数,这些参数对整个应用程序都是可见的。
- 通过 ServletConfig 的
getInitParameter()
方法或直接在 Servlet 中使用getServletContext().getInitParameter()
方法访问。
获取资源:
- Servlet 上下文提供了获取 Web 应用程序中资源的方法,如 HTML 文件、图片、配置文件等。
- 通过
getServletContext().getResourceAsStream()
方法可以获取资源的输入流。
共享属性:
- Servlet 上下文允许在不同的 Servlet 之间共享属性。这些属性可以存储在上下文中,并在整个应用程序中访问。
- 使用
getServletContext().setAttribute()
设置属性,通过getServletContext().getAttribute()
获取属性。
获得 Web 应用程序信息:
- 可以获取 Web 应用程序的相关信息,如应用程序名称、服务器信息等。
- 通过
getServletContext().getServletContextName()
获取应用程序名称。
发送事件通知:
- Servlet 上下文可以向监听器发送事件通知,用于监听应用程序生命周期事件或属性变化等。
- 监听器通过实现相应的接口(如
ServletContextListener
、ServletContextAttributeListener
)来处理这些事件。
2. ServletContext常用方法
// 获取 Servlet 上下文的初始化参数值
public String getInitParameter(String name);
// 获取 Servlet 上下文的 MIME 类型映射
public String getMimeType(String file);
// 获取 Servlet 上下文中的真实路径
public String getRealPath(String path);
// 获取 Servlet 上下文的资源流
public InputStream getResourceAsStream(String path);
// 获取 Servlet 上下文的属性值
public Object getAttribute(String name);
// 设置 Servlet 上下文的属性值
public void setAttribute(String name, Object object);
// 移除 Servlet 上下文的属性
public void removeAttribute(String name);
// 获取 Servlet 上下文中的 RequestDispatcher
public RequestDispatcher getRequestDispatcher(String path);
// 获取 Servlet 上下文中的 Servlet
public Servlet getServlet(String name) throws ServletException;
// 添加映射到 Servlet 上下文的过滤器
public FilterRegistration.Dynamic addFilter(String filterName, String className);
// 添加映射到 Servlet 上下文的过滤器
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter);
// 添加映射到 Servlet 上下文的监听器
public void addListener(Class<? extends EventListener> listenerClass);
// 添加映射到 Servlet 上下文的监听器
public <T extends EventListener> void addListener(T t);
// 获取 Servlet 上下文中的会话超时时间
public int getSessionTimeout();
// 获取 Servlet 上下文中的会话 Cookie 配置
public SessionCookieConfig getSessionCookieConfig();
// 添加映射到 Servlet 上下文的 Servlet
public ServletRegistration.Dynamic addServlet(String servletName, String className);
// 添加映射到 Servlet 上下文的 Servlet
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet);
// 获取 Servlet 上下文中的所有 Servlet 注册器
public Map<String, ? extends ServletRegistration> getServletRegistrations();
七、Cookie与Session
1. Cookie
HTTP是一种不保存状态的协议,即无状态(stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存和持久化处理,为了实现对用户状态的持久化管理,HTTP引入了Cookie技术。Cookie是一种在用户浏览器中存储小型文本信息的机制,由服务器通过HTTP协议发送并存储至客户端,以便在后续请求中跟踪用户会话、存储用户偏好设置等。其工作原理如下:
- 浏览器端第一次发送请求到服务器端;
- 服务器端创建Cookie,该Cookie中包含用户的信息,然后将该Cookie发送到浏览器端;
- 浏览器端再次访问服务器端时会携带服务器端创建的Cookie;
- 服务器端通过Cookie中携带的数据区分不同的用户。
Cookie是通过HTTP请求和响应头在客户端和服务器端传递的:
- 在请求头中,采用名为“Cookie”的字段,客户端将存储的Cookie发送给服务器端,格式为“Cookie: a=A; b=B; c=C”。多个Cookie可以共用一个请求头,并用分号隔开,一个请求头中有一个Cookie字段;
- 在响应头中,采用名为“Set-Cookie”的字段,服务器端把需要存储的Cookie发送给客户端,格式为“Set-Cookie: a=A; b=B; c=C;”。多个Cookie可以共用一个响应头,并用分号隔开,一个响应头中也可以有多个Set-Cookie字段。
在Servlet中,类java.servlet.http.Cookie封装了相关的方法用于创建和操作Cookie。
Cookie常用方法
// 构造方法
Cookie(String name, String value);
// 将 Cookie 添加到响应头
void addCookie(Cookie cookie);
// 设置 Cookie 的存放路径
void setPath(String uri);
// 获取 Cookie 的路径
String getPath();
// 设置 Cookie 的域
void setDomain(String pattern);
// 获取 Cookie 的域
String getDomain();
// 设置 Cookie 的过期时间,以秒为单位
void setMaxAge(int expiry);
// 获取 Cookie 的过期时间
int getMaxAge();
// 获取 Cookie 的名称
String getName();
// 获取 Cookie 的值
String getValue();
Cookie的过期时间
负数:表示Cookie只保存在浏览器的内存中,关闭浏览器Cookie即被删除;
正数:表示Cookie保存在计算机硬盘中的的秒数,到期即从硬盘中删除Cookie;
零:表示删除该Cookie。
示例代码
创建和发送Cookie:
// 创建cookie对象
Cookie cookie = new Cookie("name", "admin");
// 发送cookie
response。addCookie(cookie);
获取Cookie:
// 获取cookies数组
Cookie[] cookies = request.getCookies();
// 判断数组是否为空
if (cookie != null && cookies.length > 0) {
// 遍历cookies数组
for (Cookie cookie : cookies) {
System.out.printIn(cookie.getName());
System.out.printIn(cookie.getValue());
}
}
2. Session
Session是在HTTP协议的基础上实现对用户状态的持久化管理的一种机制。Cookie和Session都可以用于跟踪用户的会话,以便识别同一用户的多次请求,但与Cookie不同的是,Session将用户状态信息存储在服务器端,而不是在用户浏览器中。与Cookie相比,Session提供了更高的安全性,但也增加了服务器的存储和管理负担,其工作原理如下:
- 用户第一次访问服务器时,服务器会为该用户创建一个唯一的Session标识,通常称为Session ID;
- 服务器将该Session ID通过Cookie发送给用户的浏览器,或者将其包含在URL中;
- 用户的浏览器在后续的请求中携带这个Session ID;
- 服务器根据携带的Session ID来识别用户,并检索与之关联的Session数据,实现对用户状态的保持。
在Servlet中,类javax.servlet.http.HttpSession封装了相关的方法用于创建和操作Session。
HttpSession常用方法
// 获取或创建 Session 对象
HttpSession getSession();
// 获取或创建 Session 对象,并指定是否创建新的 Session
HttpSession getSession(boolean create);
// 将属性设置到 Session 中
void setAttribute(String name, Object value);
// 从 Session 中获取属性值
Object getAttribute(String name);
// 从 Session 中移除属性
void removeAttribute(String name);
// 获取 Session 的唯一标识符
String getId();
// 获取 Session 的创建时间
long getCreationTime();
// 获取 Session 的最后访问时间
long getLastAccessedTime();
// 设置 Session 的最大不活动时间,以秒为单位
void setMaxInactiveInterval(int interval);
// 获取 Session 的最大不活动时间
int getMaxInactiveInterval();
// 使 Session 失效
void invalidate();
示例代码
创建和发送Session:
// 获取或创建 Session 对象
HttpSession session = request.getSession();
// 将属性设置到 Session 中
session.setAttribute("username", "admin");
获取Session:
// 获取 Session 对象
HttpSession session = request.getSession(false);
// 判断 Session 是否存在
if (session != null) {
// 从 Session 中获取属性值
String username = (String) session.getAttribute("username");
System.out.println("Username: " + username);
}
八、过滤器与监听器
1. 过滤器(Filter)
过滤器是Java EE中一种用于对请求和响应进行预处理和后处理的组件。过滤器在Servlet容器中注册,可以对所有请求和响应进行拦截,用于完成一些通用的任务,比如:
- 修改请求或响应的头信息;
- 身份验证和访问权限控制;
- 对请求或响应进行字符编码处理;
- 过滤敏感数据;
- 记录请求日志
在Servlet中,接口类javax.servlet.Filter
封装了相关的方法用于实现过滤器;接口类javax.servlet.FilterConfig
用于传递过滤器的配置信息,它包含了过滤器在部署描述符(xml文件)中配置的初始化参数;接口类javax.servlet.FilterChain
用于管理过滤器链的执行。在过滤器的doFilter
方法中,通过FilterChain
可以将请求和响应传递给下一个过滤器或目标资源。
补充:在Spring框架中提供了一种叫做拦截器(Interceptor)的机制,用于拦截并处理Controller的方法调用。与Servlet的过滤器类似,但更加灵活,可以根据业务需要选择性地拦截请求。关于两者的具体区别请自行搜索。
过滤器的生命周期
实例化阶段
:过滤器在web应用被加载时就完成实例化。初始化阶段
:完成实例化后,Servlet容器会调用void init(FilterConfig config)
方法初始化过滤器,这个阶段通常用于执行一些初始化操作,读取FilterConfig对象中的配置信息等。因为一个Servlet对象在整个生命周期中只调用init()方法一次,因此拦截器的初始化操作也只会执行一次。请求处理阶段
:在每次请求到达目标资源前,Servlet容器会调用过滤器的void doFilter(ServletRequest,ServlerResponse,FilterChain)
方法,允许过滤器修改请求或响应,或将请求和响应传递给下一个过滤器。如果过滤器对处理后的请求执行了放行操作,那么这个请求便会发送给目标资源,否则该请求会被过滤。销毁阶段
:Servlet容器在调用destory()
方法后,会销毁所有过滤器。因为一个Servlet对象在整个生命周期中只调用destory()方法一次,因此拦截器的销毁操作也只会执行一次。
过滤器常用方法
javax.servlet.Filter:
// 获取过滤器的配置信息
FilterConfig getFilterConfig();
// 初始化过滤器
void init(FilterConfig filterConfig) throws ServletException;
// 执行过滤操作
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
// 销毁过滤器
void destroy();
javax.servlet.FilterConfig:
// 获取过滤器的名称
String getFilterName();
// 根据初始化参数的名称获取初始化参数的值
String getInitParameter(String name);
// 获取所有初始化参数的名称的枚举
Enumeration<String> getInitParameterNames();
javax.servlet.FilterChain:
// 将请求和响应传递给过滤器链中的下一个过滤器或目标资源
void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
示例代码
com.example.MyFilter类中的代码如下:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class MyFilter implements Filter {
private FilterConfig filterConfig;
// 初始化过滤器的相关逻辑
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 读取过滤器配置
this.filterConfig = filterConfig;
// 获取初始化参数paramName的值
String paramValue = filterConfig.getInitParameter("paramName");
System.out.println("过滤器已初始化,paramName的值为:" + paramValue);
}
// 对请求进行处理
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
// 执行过滤器链中的下一个过滤器或目标资源
chain.doFilter(request, response);
long endTime = System.currentTimeMillis();
long executionTime = endTime - startTime;
// 记录请求的处理时间
System.out.println("请求的处理时间为:" + executionTime + " 毫秒");
}
// 销毁过滤器的相关逻辑
@Override
public void destroy() {
System.out.println("过滤器已被销毁");
}
}
xml文件中的相关内容如下:
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.example.TimingFilter</filter-class>
<init-param>
<param-name>paramName1</param-name>
<param-value>paramValue1</param-value>
</init-param>
<init-param>
<param-name>paramName2</param-name>
<param-value>paramValue2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/login</url-pattern>
<url-pattern>/index/*</url-pattern>
</filter-mapping>
以上代码实现了将MyFilter这个拦截器映射到此web应用的/login和以/index开头的url上,并设置了两个初始化参数。
此外,使用注解配置,我们可以将上面的xml配置简化为@WebFilter(filterName = "MyFilter", urlPatterns = {"/login", "/index/*"}, initParams = {@WebInitParam(name = "paramName1", value = "paramValue1"), @WebInitParam(name = "paramName2", value = "paramValue2")})
2. 监听器(Listener):
监听器用于监听Web应用中的事件,比如Servlet的生命周期事件、HTTP会话的创建和销毁事件等。监听器是基于观察者模式实现的,可以响应特定事件的发生,并执行相应的逻辑。常见的监听器包括:
ServletContextListener
:监听ServletContext的生命周期事件,可用于在Web应用启动和关闭时执行一些初始化和清理操作。HttpSessionListener
:监听HTTP会话的创建和销毁事件,可以进行用户登录和退出的处理。ServletRequestListener
:监听ServletRequest的创建和销毁事件,可用于记录请求日志等。