Filter 过滤器--基本原理--Filter 过滤器生命周期--过滤器链--注意事项和细节--全部应用实例--综合代码示例

简介: Filter 过滤器--基本原理--Filter 过滤器生命周期--过滤器链--注意事项和细节--全部应用实例--综合代码示例


Filter 过滤器

Filter 过滤器说明

为啥要过滤器-需求示意图

过滤器介绍

1. Filter 过滤器它是 JavaWeb 的三大组件之一(Servlet 程序、Listener 监听器、Filter 过滤器)

2. Filter 过滤器是 JavaEE 的规范,是接口

3. Filter 过滤器它的作用是:拦截请求,过滤响应。

4. 应用场景

● 权限检查

● 日记操作

● 事务管理

Filter 过滤器基本原理

代码示例

需求: 在 web 工程下,有后台管理目录 manage,要求该目录下所有资源(html、图片、jsp 、Servlet 等)用户登录后才能访问

login.jsp

1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
2. <html>
3. <head>
4.     <title>管理后台登录</title>
5. </head>
6. <body>
7. <h1>管理后台登录</h1>
8. <%
9.     System.out.println("request=" + request);
10. %>
11. <form action="<%=request.getContextPath() %>/loginCheckServlet" method="post">
12.     u:<input type="text" name="username"/> <br/><br/>
13.     p:<input type="password" name="password"/> <br/><br/>
14.     <input type="submit" value="用户登录"/></form>
15. </body>
16. </html>

LoginCLServlet.java

1. public class LoginCheckServlet extends HttpServlet {
2. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
3. //获取到用户名和密码->DB
4. //假设密码是123456, 就可以通过
5. String username = request.getParameter("username");
6. String password = request.getParameter("password");
7.         System.out.println("request=" + request);
8. if("123456".equals(password)) {
9. 
10. //合法, 讲用户名,加入session
11.             request.getSession().setAttribute("username", username);
12. //请求转发到admin.jsp
13.             request.getRequestDispatcher("/manage/admin.jsp")
14.                     .forward(request,response);
15.         } else {
16. //不合法, 返回登录页面
17.             request.getRequestDispatcher("/login.jsp")
18.                     .forward(request,response);
19. 
20.         }
21.     }
22. 
23. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
24.         doPost(request, response);
25.     }
26. }

admin.jsp

1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
2. <html>
3. <head>
4.     <title>后台管理</title>
5.     <base href="<%=request.getContextPath() %>/manage/"/>
6. </head>
7. <body>
8. <h1>后台管理</h1>
9. <%
10. //验证request对象是和前面的filter是一个对象
11.     System.out.println("request=" + request);
12. %>
13. <a href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a>
14. <hr/>
15. <img src="shunping.jpg" height="300"/>
16. </body>
17. </html>

ManageFilter.java

1. filter在web项目启动时, 由tomcat 来创建filter实例, 只会创建一个

2. 会调用filter默认的无参构造器, 同时会调用 init方法, 只会调用一次

3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入

4. 通过FilterConfig对象,程序员可以获取该filter的相关配置信息

5. 当一个http请求和该filter的的url-patter匹配时,就会调用doFilter方法

6. 在调用doFilter方法时,tomcat会同时创建ServletRequest 和ServletResponse 和 FilterChain对象, 并通过doFilter传入.

7. 如果后面的请求目标资源(jsp,servlet..) 会使用到request,和 response,那么会继续传递

1. /**
2.  * 1. filter在web项目启动时, 由tomcat 来创建filter实例, 只会创建一个
3.  * 2. 会调用filter默认的无参构造器, 同时会调用 init方法, 只会调用一次
4.  * 3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
5.  * 4. 通过FilterConfig对象,程序员可以获取该filter的相关配置信息
6.  * 5. 当一个http请求和该filter的的url-patter匹配时,就会调用doFilter方法
7.  * 6. 在调用doFilter方法时,tomcat会同时创建ServletRequest 和 ServletResponse 和 FilterChain对象
8.  * , 并通过doFilter传入.
9.  * 7. 如果后面的请求目标资源(jsp,servlet..) 会使用到request,和 response,那么会继续传递
10.  */
11. public class ManageFilter implements Filter {
12. 
13. private int count = 0;
14. 
15. @Override
16. public void init(FilterConfig filterConfig) throws ServletException {
17. //当Tomcat 创建 Filter创建,就会调用该方法,进行初始化
18. //提醒:回忆我们自己实现tomcat底层机制+servlet程序
19. 
20.         System.out.println("ManageFilter init被调用...");
21.     }
22. 
23. @Override
24. public void doFilter(ServletRequest servletRequest,
25.                          ServletResponse servletResponse,
26.                          FilterChain filterChain) throws IOException, ServletException {
27. 
28.         System.out.println("ManageFilter doFilter() 被调用=" + (++count));
29. 
30. //到每次调用该filter时,doFilter就会被调用
31. 
32. //如果这里,没有调用继续请求的方法,则就停止
33. //如果继续访问目标资源-> 等价于放行
34. 
35. //说明:在调用过滤器前,servletRequest对象=request已经被创建并封装
36. //所以:我们这里就可以通过servletRequest获取很多信息, 比如访问url , session
37. //比如访问的参数 ... 就可以做事务管理,数据获取,日志管理等
38. //获取到session
39. //可以继续使用 httpServletRequest 方法.
40. HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
41.         System.out.println("输入密码=" + httpServletRequest.getParameter("password"));
42. HttpSession session = httpServletRequest.getSession();
43. //获取username session对象, 还可以继续使用
44. Object username = session.getAttribute("username");
45. if (username != null) {
46. //filterChain.doFilter(servletRequest, servletResponse)
47. //1. 继续访问目标资源url
48. //2. servletRequest 和 servletResponse 对象会传递给目标资源/文件
49. //3. 一定要理解filter传递的两个对象,再后面的servlet/jsp 是同一个对象(指的是在一次http请求)
50.             System.out.println("servletRequest=" + servletRequest);
51.             System.out.println("日志信息==");
52.             System.out.println("访问的用户名=" + username.toString());
53.             System.out.println("访问的url=" + httpServletRequest.getRequestURL());
54.             System.out.println("访问的IP=" + httpServletRequest.getRemoteAddr());
55.             filterChain.doFilter(servletRequest, servletResponse);
56.         } else {//说明没有登录过..回到登录页面
57.             servletRequest.getRequestDispatcher("/login.jsp").
58.                     forward(servletRequest, servletResponse);
59.         }
60.     }
61. 
62. @Override
63. public void destroy() {
64. //当filter被销毁时,会调用该方法
65.         System.out.println("ManageFilter destroy()被调用..");
66.     }
67. }

xml配置

filter一般写在其它servlet的前面

  • 1. 观察我们发现filter 配置和 servlet 非常相似. filter也是被tomcat管理和维护
  • 2. url-pattern 就是当请求的url 和 匹配的时候,就会调用该filter
  • 3. /manage/* 第一个 / 解析成 http://ip:port/工程路径
  • 4. 完整的路径就是 http://ip:port/工程路径/manage/* 当请求的资源url满足该条件时都会调用filter , /manage/admin.jsp
1. <!--解读:filter一般写在其它servlet的前面
2.         1. 观察我们发现filter 配置和 servlet 非常相似. filter也是被tomcat管理和维护
3.         2. url-pattern 就是当请求的url 和 匹配的时候,就会调用该filter
4.         3. /manage/* 第一个 / 解析成 http://ip:port/工程路径
5.         4. 完整的路径就是 http://ip:port/工程路径/manage/* 当请求的资源url满足该条件时
6.         都会调用filter , /manage/admin.jsp
7.     -->
8. <filter>
9. <filter-name>ManageFilter</filter-name>
10. <filter-class>com.filter.ManageFilter</filter-class>
11. </filter>
12. <filter-mapping>
13. <filter-name>ManageFilter</filter-name>
14. <url-pattern>/manage/*</url-pattern>
15. </filter-mapping>

Filter 过滤器 url-pattern

1、url-pattern: Filter的拦截路径,即浏览器在请求什么位置的资源时,过滤器会进行拦截过滤

2.、精确匹配 <url-pattern>/a.jsp</url-pattern> 对应的 请求地址 http://ip[域名]:port/工程路径/a.jsp 会拦截

3、目录匹配 <url-pattern>/manage/*</url-pattern>对应的 请求地址 http://ip[域名]:port/工程路径/manage/xx , 即 web 工程 manage 目录下所有资源 会拦截

4、后缀名匹配 <url-pattern>*.jsp</url-pattern> 后缀名可变,比如 *.action *.do 等等对应的 请求地址 http://ip[域名]:port/工程路径/xx.jsp , 后缀名为 .jsp 请求会拦截

5、Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在

Filter 过滤器生命周期

● Filter 生命周期图

 

1. filter在web项目启动时, 由tomcat 来创建filter实例, 只会创建一个

2. 会调用filter默认的无参构造器, 同时会调用 init方法, 只会调用一次

3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入

4. 通过FilterConfig对象,程序员可以获取该filter的相关配置信息

5. 当一个http请求和该filter的的url-patter匹配时,就会调用doFilter方法

6. 在调用doFilter方法时,tomcat会同时创建ServletRequest 和 ServletResponse 和 FilterChain对象, 并通过doFilter传入.

7. 如果后面的请求目标资源(jsp,servlet..) 会使用到request,和 response,那么会继续传递

 

FilterConfig

● FilterConfig 接口

● FilterConfig 说明

1. FilterConfig 是 Filter 过滤器的配置类

2. Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。

3. FilterConfig 对象作用是获取 filter 过滤器的配置内容

应用实例

WyxFilterConfig

1. public class WyxFilterConfig implements Filter {
2. 
3. private String ip; //从配置获取的ip
4. 
5. @Override
6. public void init(FilterConfig filterConfig) throws ServletException {
7.         System.out.println("WyxFilterConfig init() 被调用..");
8. 
9. //通过filterConfig 获取相关的参数
10. String filterName = filterConfig.getFilterName();
11.         ip = filterConfig.getInitParameter("ip");
12. 
13. ServletContext servletContext = filterConfig.getServletContext();
14. 
15. //可以获取到该filter所有的配置参数名
16.         Enumeration<String> initParameterNames =
17.                 filterConfig.getInitParameterNames();
18. 
19. //遍历枚举
20. while (initParameterNames.hasMoreElements()) {
21.             System.out.println("名字=" + initParameterNames.nextElement());
22.         }
23. 
24.         System.out.println("filterName= " + filterName);
25.         System.out.println("ip= " + ip);
26.         System.out.println("servletContext= " + servletContext);
27. 
28. 
29.     }
30. 
31. @Override
32. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
33. 
34. //通过forbidden ip 来进行控制
35. //先获取到访问ip
36. 
37. String remoteAddr = servletRequest.getRemoteAddr();
38. if(remoteAddr.contains(ip)) {
39. 
40.             System.out.println("封杀该网段..");
41.             servletRequest.getRequestDispatcher("/login.jsp").
42.                     forward(servletRequest,servletResponse);
43. return; //直接返回
44. 
45.         }
46. 
47. //继续访问目标资源
48.         filterChain.doFilter(servletRequest,servletResponse);
49.     }
50. 
51. @Override
52. public void destroy() {
53. 
54.     }
55. }

web.xml

1. <filter>
2. <filter-name>WyxFilterConfig</filter-name>
3. <filter-class>com.filter.WyxFilterConfig</filter-class>
4. <!--这里就是给该filter配置的参数-根据业务逻辑来设置-->
5. <init-param>
6. <param-name>ip</param-name>
7. <param-value>127.0</param-value>
8. </init-param>
9. <init-param>
10. <param-name>port</param-name>
11. <param-value>8888</param-value>
12. </init-param>
13. <init-param>
14. <param-name>email</param-name>
15. <param-value>123@qq.com</param-value>
16. </init-param>
17. </filter>
18. <filter-mapping>
19. <filter-name>WyxFilterConfig</filter-name>
20. <url-pattern>/abc/*</url-pattern>
21. </filter-mapping>

FilterChain 过滤器链

一句话: FilterChain: 在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。

基本原理示意图

应用实例

需求: 演示过滤器链的使用

AFilter.java

1. public class AFilter implements Filter {
2. @Override
3. public void init(FilterConfig filterConfig) throws ServletException {
4. 
5.     }
6. 
7. @Override
8. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
9. 
10.         System.out.println("AFilter---> 线程id=" +
11.                 Thread.currentThread().getId());
12. 
13.         System.out.println("AFilter doFilter 的前置代码...");
14.         System.out.println("执行 AFilter doFilter()");
15.         filterChain.doFilter(servletRequest, servletResponse);
16.         System.out.println("AFilter doFilter 的后置代码...");
17.     }
18. 
19. @Override
20. public void destroy() {
21. 
22.     }
23. }

BFilter.java

1. public class BFilter implements Filter {
2. @Override
3. public void init(FilterConfig filterConfig) throws ServletException {
4. 
5.     }
6. 
7. @Override
8. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
9. 
10.         System.out.println("BFilter---> 线程id=" +
11.                 Thread.currentThread().getId());
12. 
13.         System.out.println("BFilter doFilter 的前置代码...");
14. 
15.         System.out.println("执行 BFilter doFilter()");
16.         filterChain.doFilter(servletRequest, servletResponse);
17.         System.out.println("BFilter doFilter 的后置代码...");
18.     }
19. 
20. @Override
21. public void destroy() {
22. 
23.     }
24. }

hi.jsp

1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
2. <html>
3. <head>
4.     <title>hi</title>
5. </head>
6. <body>
7. <h1>admin目录下的 hi.jsp</h1>
8. <h1>后台管理</h1>
9. <a href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a>
10. <hr/>
11. </body>
12. </html>

xml

1. <filter>
2. <filter-name>AFilter</filter-name>
3. <filter-class>com.filter.AFilter</filter-class>
4. </filter>
5. <filter-mapping>
6. <filter-name>AFilter</filter-name>
7. <url-pattern>/admin/*</url-pattern>
8. </filter-mapping>
9. 
10. <filter>
11. <filter-name>BFilter</filter-name>
12. <filter-class>com.filter.BFilter</filter-class>
13. </filter>
14. <filter-mapping>
15. <filter-name>BFilter</filter-name>
16. <url-pattern>/admin/*</url-pattern>
17. </filter-mapping>

FilterChain 注意事项和细节

1. 多个 filter 和目标资源在一次 http 请求,在同一个线程中

2. 当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行, 如果有多个匹配上,就会顺序执行,形成一个 filter 调用链 (底层可以使用一个数据结构搞定)如LinkedHashMap

3. 多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象

4. 多个 filter 执行顺序,和 web.xml 配置顺序保持一致.

5. chain.doFilter(req, resp)方法 将执行下一个过滤器的 doFilter 方法, 如果后面没有过滤器,则执行目标资源。

6. 小结:

 注意执行过滤器链时, 顺序是(用前面的案例分析) Http请求 -> A 过滤器 dofilter()-> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 dofilter() -> B 过滤器前置代码 -> B过滤器 chain.doFilter() -> 目标文件 -> B过滤器后置代码 -> A过滤器后置代码 ->返回给浏览器页面/数据

综合代码示例

● 需求分析: 使用过滤器, 完成如下要求

1) 点击发表评论页面 topic.jsp, 可以在 showTopic.jsp 显示评论内容

2) 如果发表的评论内容,有关键字比如 "苹果" "香蕉", 就返回 topic.jsp, 并提示有禁用词

3) 要求发表评论到 showTopic.jsp 时,经过过滤器的处理

4) 禁用词, 配置在过滤器, 在启动项目时动态的获取, 注意处理中文

运行效果图

topic.jsp

1. <%@ page contentType="text/html;charset=UTF-8" language="java"%>
2. <html>
3. <head>
4. <title>Title</title>
5. </head>
6. <body>
7. <h1>发表对阿凡达电影评论</h1>
8. 过滤词: 苹果, 香蕉 ${errorInfo}
9. <form method="post" action="<%=request.getContextPath()%>/topic/showTopic.jsp">
10.     用户: <input type="text" name="username"><br/>
11.     评论: <textarea rows="10" name="content" cols="20"></textarea><br/>
12. <input type="submit" value="发表评论">
13. </form>
14. </body>
15. </html>

TopicServlet.java

1. public class TopicFilter implements Filter {
2. 
3. //属性-> 存放禁用词
4. private String[] forbiddenWords = null;
5. 
6. @Override
7. public void init(FilterConfig filterConfig) throws ServletException {
8. //获取禁用词
9. String forbiddenword = filterConfig.getInitParameter("forbiddenword");
10.         forbiddenWords = forbiddenword.split(",");
11.     }
12. 
13. @Override
14. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
15. 
16. //解决从topic.jsp 提交的中文乱码问题
17.         servletRequest.setCharacterEncoding("utf-8");
18. 
19. //判断评论是不是有禁用词
20. String content = servletRequest.getParameter("content");
21. //循环遍历一把,看看有没有禁用词
22. for (String forbiddenWord : forbiddenWords) {//java基础
23. if (content.contains(forbiddenWord)) {
24. //返回topic.jsp
25.                 servletRequest.setAttribute("errorInfo", "你输入的有禁用词");
26.                 servletRequest.getRequestDispatcher("/topic.jsp")
27.                         .forward(servletRequest, servletResponse);
28. return;//返回
29.             }
30.         }
31. 
32. //继续到目标
33.         filterChain.doFilter(servletRequest, servletResponse);
34.     }
35. 
36. @Override
37. public void destroy() {
38. 
39.     }
40. }

配置过滤器

1. <filter>
2. <filter-name>TopicFilter</filter-name>
3. <filter-class>com.filter.TopicFilter</filter-class>
4. <!--配置禁用词-->
5. <init-param>
6. <param-name>forbiddenword</param-name>
7. <param-value>苹果,香蕉</param-value>
8. </init-param>
9. </filter>
10. <filter-mapping>
11. <filter-name>TopicFilter</filter-name>
12. <url-pattern>/topic/*</url-pattern>
13. </filter-mapping>

showTopic.jsp

1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
2. <html>
3. <head>
4. <title>Title</title>
5. </head>
6. <body>
7. <h1>你发表的评论是</h1>
8. 评论内容: <%=request.getParameter("content")%>
9. </body>
10. </html>
11.


目录
相关文章
|
2月前
|
JavaScript Java 容器
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
本文简要回顾了Servlet过滤器Filter的概念和使用,通过实例演示了如何创建过滤器以过滤请求字符编码,并解释了在web.xml中配置过滤器时使用`/`、`/*`和`/**`的区别。
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
|
12天前
过滤器链加载原理
过滤器链加载原理
20 0
过滤器链加载原理
|
4月前
|
开发框架 JSON 前端开发
利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理
利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理
|
5月前
分享JavaWeb中filter过滤器的案例妙用 - 脏话过滤/编码过滤/代码过滤
分享JavaWeb中filter过滤器的案例妙用 - 脏话过滤/编码过滤/代码过滤
34 0
|
6月前
|
Java 数据安全/隐私保护
Filter概述、执行流程、拦截路径配置及过滤器链
Filter概述、执行流程、拦截路径配置及过滤器链
84 0
过滤器简介--操作步骤--过滤器生命周期--过滤器匹配规则-- 过滤器链
过滤器简介--操作步骤--过滤器生命周期--过滤器匹配规则-- 过滤器链
65 0
Filter过滤器概念及生命周期
Filter过滤器概念及生命周期
155 0
|
存储 XML 消息中间件
filter功能演示-鉴权、声明缓存
filter功能演示-鉴权、声明缓存
159 0
|
Java
Filter概述、接口及配置
Filter概述、接口及配置
10768 0
|
Java 应用服务中间件 Spring
自定义Filter后,我的业务代码怎么被执行了多次?
若要求构建的过滤器针对全局路径有效,且无任何特殊需求(主要针对 Servlet 3.0 的一些异步特性),则完全可直接使用 Filter 接口(或继承 Spring 对 Filter 接口的包装类 OncePerRequestFilter),并使用**@Component** 将其包装为 Spring 中的普通 Bean,也可达到预期需求。
162 0