Java Web 从入门到退坑 —— 第十三章 Filter 过滤器
By: -gregPerlinLi-
1. 什么是 Filter 过滤器
1. Filter 过滤器是 JavaWeb 的三大组件之一,三大组件分别是 Servlet 程序、Listener 监听器、Filter 过滤器。
2. Filter 过滤器是 JavaEE 的规范,也就是接口。
3. Filter 过滤器的作用是:拦截请求,过滤响应。
拦截请求常见的应用场景有:
1. 权限检查
2. 日记操作
3. 事务管理
……
2. Filter 的初体验
要求:在 Web 工程下,有个 admin
目录,这个目录下的所有资源(HTML 页面,JPG 图片,jsp 页面)都必须是用户登录之后才允许访问。
思考: 根据之前学过的内容可知,在用户登录之后,都会把用户信息保存到 Session 域中,所以要检查用户是否登陆可以判断 Session 中是否包含有用户登录的信息即可
方法1(仅适用于 jsp 页面):
<%
Object user = session.getAttribute("user");
// If it is null, it means that you have not logged in
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
%>
I'm a.jsp file
方法2(使用 Filter 过滤器):
Filter 过滤器的原理:
在 web.xml
配置 Filter 过滤器
<!-- Configure Filter -->
<filter>
<!-- Give Filter an alias -->
<filter-name>AdminFilter</filter-name>
<!-- Configure the full class name of the Filter -->
<filter-class>com.gregperlinli.Filter.AdminFilter</filter-class>
</filter>
<!-- Filter of intercepting path configuration -->
<filter-mapping>
<!-- Indicates the current interception path to the Filter to use -->
<filter-name>AdminFilter</filter-name>
<!--
Configure interception path
The / slash indicates that the request address is http://ip:port/projctName/
Map to webapp directory in IDEA
/admin/* Indicates that the request address is: http://ip:port/projctName/admin/*
-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
示例代码:
/**
* doFilter() method is designed to intercept requests,and it can do permission checking
* @param request request
* @param response response
* @param chain chain
* @throws IOException e
* @throws ServletException e
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("username");
// If it is null, it means that you have not logged in
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
} else {
// Let the program continue to access the user's target resource
chain.doFilter(request, response);
}
}
Filter 过滤器的使用步骤:
1. 编写一个类去实现 Filter 接口
2. 实现过滤方法 doFilter()
3. 到 web.xml
中去配置 Filter 的拦截路径(也可以使用以下注解来进行配置)
@WebFilter(filterName = "AdminFilter", value = "/admin/*")
3. Filter 的生命周期
Filter 的生命周期包含几个方法
1. 构造器方法
2. init
初始化方法
3. doFilter
过滤方法
4. destroy
销毁方法
第1,2步,在 Web 工程启动的时候执行(Filter 已经创建)
第3步在每次拦截到请求的时候就会执行
第4步在停止 Web 工程的时候就会执行(停止 Web 工程,也会销毁 Filter 过滤器)
4. FilterConfig
类
FilterConfig
类见名知意,它是 Filter 过滤器的配置文件类
Tomcat 每次创建 Filter 的时候也会同时创建一个 FilterConfig
类,这里包含了 Filter 配置文件的配置信息。
FilterConfig
类的作用是获取 Filter 过滤器的配置内容
1. 获取 Filter 的名称 filter-name
的内容
2. 获取在 Filter 中配置的 init-param
初始化参数
3. 获取 ServletContext
对象
示例代码:
@WebFilter(filterName = "AdminFilter", value = "/admin/*",
initParams = {
@WebInitParam(name = "username", value = "root"),
@WebInitParam(name = "url", value = "jdbc:mysql://localhost:3306/test") })
public class AdminFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2. Filter initialize method");
// 1. Get the name of filter and the content of filter-name
System.out.println("filter-name: " + filterConfig.getFilterName());
// 2. Get the init-param initialization parameter configured in the filter
System.out.println("Initialize parameter username: " + filterConfig.getInitParameter("username"));
System.out.println("Initialize parameter url: " + filterConfig.getInitParameter("url"));
// 3. Get the ServletContext object
System.out.println(filterConfig.getServletContext());
}
}
5. FilterChain
过滤器链
Filter: 过滤器 Chain: 链,链条
FilterChain
就是过滤器链(多个过滤器如何一起工作)
FilterChain.doFilter()
方法的作用:
1. 执行下一个 Filter 过滤器(如果有 Filter)
2. 执行目标资源(如果没有 Filter)
示例代码:
Filter1.java
@WebFilter(filterName = "Filter1", value = "/admin/target.jsp")
public class Filter1 implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("Prefix code of Filter1");
chain.doFilter(request, response);
System.out.println("Post code of Filter1");
}
}
Filter2.java
@WebFilter(filterName = "Filter2", value = "/admin/target.jsp")
public class Filter2 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("Prefix code of Filter2");
chain.doFilter(request, response);
System.out.println("Post code of Filter2");
}
}
注意⚠️:在多个 Filter 过滤器执行的时候,对于使用 web.xml
来配置的 Filter 过滤器来说,它们执行的优先顺序是由它们在中从上到下配置的顺序决定的;而对于使用注解 @WebFilter()
配置的 FIlter 过滤器,则是按照 Filter 名字的顺序(不区分大小写)来决定的!
多个 Filter 过滤器执行的特点:
1. 所有 Filter 和目标资源默认都执行在同一个线程中
2. 以上多个 Filter 共同执行的时候,它们都是用同一个 Request
对象
6. Filter 的拦截路径
6.1. 精确匹配
<url-pattern>/target.jsp</url-pattern>
@WebFilter(filterName = "Filter", value = "/target.jsp")
以上配置的路径,表示请求地址必须为:http://ip:port/projectName/target.jsp
6.2. 目录匹配
<url-pattern>/target/*</url-pattern>
@WebFilter(filterName = "Filter", value = "/target/*")
以上配置的路径表示请求地址必须为:http://ip:port/projectName/target/*
(也就是该目录下的全部资源)
6.3. 后缀名匹配
<url-pattern>*.html</url-pattern>
@WebFilter(filterName = "Filter", value = "*.html")
以上配置的路径表示请求地址必须以 .html
结尾(即以 html
作为后缀名)才会拦截到
注意⚠️:Filter 过滤器只关心请求的地址是否匹配,不关心请求的路径是否存在!