Filter过滤器02
5.Filter过滤器生命周期
- 验证-Tomcat来创建Filter实例,只会创建一个实例
- package com.filter;
- import javax.servlet.*;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- /**
- * 1.filter在web项目启动时,由Tomcat来创建Filter实例,只会创建一个实例
- * 2.会调用filter的默认无参构造器,同时会调用init()方法,只会调用一次
- * 3.在创建filter实例时,同时会创建FilterConfig对象,并通过init()方法传入
- * 4.通过FilterConfig对象,程序员可以获取该filter的相关配置信息
- * 5.当一个http请求和该filter的url-pattern匹配时,就会调用doFilter()方法
- * 6.在调用doFilter()方法时,Tomcat会同时创建ServletRequest,ServletResponse和FilterChain三个对象
- * 并通过doFilter方法传入
- * 7.如果后面的请求目标资源(jsp,servlet..)会使用到request,response,那么会继续传递,
- * 即request和后面的request是同一个,response和后面的也是同一个
- */
- public class ManageFilter implements Filter {
- private int count = 0;
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- //当Tomcat创建filter后,会调用该方法,进行初始化
- System.out.println("ManageFilter init方法被调用...");
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException {
- System.out.println("doFilter被调用的次数=" + (++count));
- }
- @Override
- public void destroy() {
- //当filter对像被销毁时,就会调用该方法
- System.out.println("ManageFilter destroy被调用...");
- }
- }
复制代码 redeployTomcat,在浏览器访问资源,触发过滤器,后台输出如下:
6.FilterConfig
6.1FilterConfig基本使用
- FilterConfig接口图
- FilterConfig说明
- FilterConfig是Filter过滤器的配置类
- Tomcat每次创建Filter的时候,也会创建一个FilterConfig对象,这里包含了Filter配置文件的配置信息。
- FilterConfig对象的作用是获取filter过滤器的配置内容
FilterConfig的简单使用:
DemoFilterConfig:- package com.filter;
- import javax.servlet.*;
- import java.io.IOException;
- import java.util.Enumeration;
- /**
- * 演示FilterConfig使用
- */
- public class DemoFilterConfig implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- System.out.println("DemoFilterConfig init方法被调用...");
- //演示通过FilterConfig获取相关的参数
- //获取filter在xml中配置的名字<filter-name>
- String filterName = filterConfig.getFilterName();
- //获取指定参数
- String ip = filterConfig.getInitParameter("ip");
- //filterConfig可以获取到ServletContext,
- // 这意味着filter过滤器可以和任何Servlet进行通信
- ServletContext servletContext = filterConfig.getServletContext();
- //这里可以获取该filter所有的配置的参数名
- // (也可以进一步使用getInitParameter获取指定参数)
- Enumeration<String> initParameterNames =
- filterConfig.getInitParameterNames();
- //遍历枚举
- while (initParameterNames.hasMoreElements()) {
- System.out.println("名字= " + initParameterNames.nextElement());
- }
- System.out.println("filterName= " + filterName);
- System.out.println("ip= " + ip);
- System.out.println("servletContext= " + servletContext);
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
- FilterChain filterChain) throws IOException, ServletException {
- }
- @Override
- public void destroy() {
- }
- }
复制代码 在web.xml文件中配置filter:- <filter>
- <filter-name>DemoFilterConfig</filter-name>
- <filter-class>com.filter.DemoFilterConfig</filter-class>
-
- <init-param>
- <param-name>ip</param-name>
- <param-value>166.66.66.66</param-value>
- </init-param>
- <init-param>
- <param-name>port</param-name>
- <param-value>8888</param-value>
- </init-param>
- <init-param>
- <param-name>email</param-name>
- <param-value>jack@qq.com</param-value>
- </init-param>
-
- </filter>
- <filter-mapping>
- <filter-name>DemoFilterConfig</filter-name>
- <url-pattern>/abc/*</url-pattern>
- </filter-mapping>
复制代码 redeployTomcat,后台输出如下:
可以看到FilterConfig对象可以获取filter过滤器的配置内容。
6.2简单应用-封杀ip
需求:只要某个网段(如以127.0开头的ip)访问我们的web应用,就将其返回登录页面,不允许访问网站。
思路:在web.xml文件中,将要封杀的网段作为初始配置信息。filter实例创建的时候,在init方法中读取配置的要封杀的网段信息,在filter使用的过程中,如果发现用户的请求ip包含了配置的ip网段,就认为是被封杀的ip,进行处理。
细节补充:filter配置的初始化信息只能在init方法中通过FilterConfig对象来获取。为了让doFilter方法中也能使用到,我们在filter类中创建一个属性,在init方法中将获取的配置ip赋给属性,让其在doFilter方法中也能使用。
例子
DemoFilterConfig:- package com.filter;
- import javax.servlet.*;
- import java.io.IOException;
- import java.util.Enumeration;
- /**
- * 演示FilterConfig使用
- */
- public class DemoFilterConfig implements Filter {
- private String ip;//从配置中获取的ip
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- System.out.println("DemoFilterConfig init方法被调用...");
- //获取指定参数
- ip = filterConfig.getInitParameter("ip");
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
- FilterChain filterChain) throws IOException, ServletException {
- //通过forbidden ip来控制
- //先获取访问ip
- String remoteAddr = servletRequest.getRemoteAddr();
- if (remoteAddr.contains(ip)) {//如果访问ip包含了配置ip
- //封杀该网段
- System.out.println("当前访问的ip为" + remoteAddr + "-封杀该网段...");
- servletRequest.getRequestDispatcher("/login.jsp")
- .forward(servletRequest, servletResponse);
- return;//直接返回
- }
- //否则就继续访问目标资源
- filterChain.doFilter(servletRequest, servletResponse);
- }
- @Override
- public void destroy() {
- }
- }
复制代码 在web.xml中配置filter:- <filter>
- <filter-name>DemoFilterConfig</filter-name>
- <filter-class>com.filter.DemoFilterConfig</filter-class>
-
- <init-param>
- <param-name>ip</param-name>
- <param-value>127.0</param-value>
- </init-param>
-
- </filter>
- <filter-mapping>
- <filter-name>DemoFilterConfig</filter-name>
- <url-pattern>/abc/*</url-pattern>
- </filter-mapping>
复制代码 redeployTomcat,在浏览器直接访问web应用abc目录下的资源,以触发filter。
可以看到浏览器直接返回登录页面。因为当前访问的ip为127.0.0.1,filter检测到当前地址为封杀网段,将页面直接转发回登录页面。
后台输出:
7.FilterChain过滤器链
一句话FilterChain:在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。
7.1基本原理示意图
如上,服务器接收请求,将请求中的url和过滤器的配置的url-pattern匹配,如果匹配成功,就会触发过滤器。如果匹配多个过滤器的url-pattern,则执行多个过滤器。
- 第一个过滤器调用doFilter方法,走前置代码(业务代码),运行到chain.doFilter()时,若请求的url符合其他过滤器配置的url-pattern,就会在doFilter方法中执行下一个filter过滤器的doFilter方法。
多个filter过滤器的执行顺序与web.xml文件中配置的顺序一致。
- 下一个filter过滤器执行完前置代码后,也在chain.doFilter()继续判断...依次类推,最后调用目标资源。
- 当目标资源调用完毕后,返回执行倒数第一个filter的后置代码(业务代码),然后返回执行倒数第二个filter后置代码,依次类推....直到第一个filter的后置代码执行完毕,然后服务器向浏览器返回响应。
这个返回调用的机制在事务提交上很有用
7.2过滤器链实例演示
需求:演示过滤器链的使用
AFilter:- package com.filter;
- import javax.servlet.*;
- import java.io.IOException;
- public class AFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- System.out.println("AFilter doFilter 的前置代码... ");
- System.out.println("执行AFilter filterChain.doFilter()...");
- filterChain.doFilter(servletRequest, servletResponse);
- System.out.println("AFilter doFilter 的后置代码... ");
- }
- @Override
- public void destroy() {
- }
- }
复制代码 BFilter:- package com.filter;
- import javax.servlet.*;
- import java.io.IOException;
- public class BFilter implements Filter {
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- System.out.println("BFilter doFilter 的前置代码... ");
- System.out.println("执行BFilter filterChain.doFilter()...");
- filterChain.doFilter(servletRequest, servletResponse);
- System.out.println("BFilter doFilter 的后置代码... ");
- }
- @Override
- public void destroy() {
- }
- }
复制代码 在admin目录下的hi.jsp:- <%--
- Created by IntelliJ IDEA.
- User: li
- Date: 2022/11/29
- Time: 17:55
- Version: 1.0
- --%>
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <html>
- <head>
- <title>admin 目录下的 hi.jsp</title>
- </head>
- <body>
- <h1>admin 目录下的 hi.jsp</h1>
- <h1>后台管理</h1>
- <a target="_blank" href="https://www.cnblogs.com/#">用户列表</a>||<a target="_blank" href="https://www.cnblogs.com/#">添加用户</a>||<a target="_blank" href="https://www.cnblogs.com/#">删除用户</a>
- <hr/>
- </body>
- </html>
复制代码 在web.xml中配置filter:- <filter>
- <filter-name>AFilter</filter-name>
- <filter-class>com.filter.AFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>AFilter</filter-name>
- <url-pattern>/admin/*</url-pattern>
- </filter-mapping>
- <filter>
- <filter-name>BFilter</filter-name>
- <filter-class>com.filter.BFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>BFilter</filter-name>
- <url-pattern>/admin/*</url-pattern>
- </filter-mapping>
复制代码 redeployTomcat,在浏览器访问http://localhost:8080/filter/admin/hi.jsp。
后台输出如下:
7.3FilterChain注意事项和细节
- 多个filter和目标资源在一次http请求中,在同一线程中
- 当一个请求url和filter的url-pattern匹配时,才会被执行,如果有多个匹配上,就会顺序执行,形成一个filter调用链
- 多个filter共同执行时,因为是一次http请求,使用的是同一个request对象
- 多个filter执行的顺序和web.xml配置顺序一致
- chain.doFilter(req,resp)方法,将执行下一个过滤器的doFilter方法,如果后面没有过滤器,则执行目标资源
- 小结:注意执行过滤器链时,顺序是(以7.2的例子演示):
HTTP请求->A过滤器doFilter()->A过滤器前置代码->A过滤器chain.doFilter()->B过滤器doFilter()->B过滤器前置代码—>B过滤器chain.doFilter()->目标文件->B过滤器后置代码->A过滤器后置代码->返回给浏览器页面/数据
8.Filter练习
需求:使用过滤器,完成如下要求
- 点击发表评论页面topic.jsp,可以在showTopic.jsp显示评论内容
- 如果发表的评论内容中,有关键字比如“苹果”,“香蕉”,就返回topic.jsp,并提示有禁用词
- 要求发表评论到showTopic.jsp时,要经过过滤器的处理
- 禁用词配置在过滤器,在启动项目时动态获取,注意中文的处理
练习
topic.jsp:- <%--
- Created by IntelliJ IDEA.
- User: li
- Date: 2022/11/29
- Time: 22:17
- Version: 1.0
- --%>
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <html>
- <head>
- <title>topic</title>
- </head>
- <body>
- <form action="<%=request.getContextPath()%>/hw/showTopic.jsp" method="post">
- <h1>发表对阿凡达电影的评论</h1>
- 过滤词:苹果,香蕉
- ${notice}
- 用户:<input type="text" name="username"/><br/>
- 评论:<textarea cols="15" rows="5" name="topic"></textarea><br/>
- <input type="submit" value="发表评论">
- </form>
- </body>
- </html>
复制代码 showTopic.jsp:- <%--
- Created by IntelliJ IDEA.
- User: li
- Date: 2022/11/29
- Time: 22:18
- Version: 1.0
- --%>
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <html>
- <head>
- <title>Title</title>
- </head>
- <body>
- <h3>用户:
- <%=request.getParameter("username")%></h3>
- <h3>发表的评论是:<%=request.getParameter("topic")%>
- </h3>
- </body>
- </html>
复制代码 TopicFilter:- package com.filter.hw;
- import javax.servlet.*;
- import java.io.IOException;
- public class TopicFilter implements Filter {
- private String[] forbiddenWords;
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- //获取配置信息(禁用词)
- String forbiddenWord = filterConfig.getInitParameter("forbiddenWord");
- forbiddenWords = forbiddenWord.split(",");
- }
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
- FilterChain filterChain) throws IOException, ServletException {
- //注意中文乱码问题!!!
- servletRequest.setCharacterEncoding("utf-8");
- //获取用户评论
- String username = servletRequest.getParameter("username");
- String topic = servletRequest.getParameter("topic");
- //评论不能为空
- if (topic == null || "".equals(topic)) {
- servletRequest.setAttribute("notice", "评论不能为空!");
- servletRequest.getRequestDispatcher("/hw/topic.jsp")
- .forward(servletRequest, servletResponse);
- return;
- }
- //判断评论是否有禁用词
- for (String forbiddenWord : forbiddenWords) {
- if (topic.contains(forbiddenWord)) {
- servletRequest.setAttribute("notice", "含有敏感词...");
- servletRequest.getRequestDispatcher("/hw/topic.jsp")
- .forward(servletRequest, servletResponse);
- return;
- }
- }
- //如果没有禁用词,且评论不为空
- servletRequest.getRequestDispatcher("/hw/showTopic.jsp")
- .forward(servletRequest, servletResponse);
- }
- @Override
- public void destroy() {
- }
- }
复制代码 在web.xml中配置filter:- <filter>
- <filter-name>TopicFilter</filter-name>
- <filter-class>com.filter.hw.TopicFilter</filter-class>
-
- <init-param>
- <param-name>forbiddenWord</param-name>
- <param-value>香蕉,苹果</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>TopicFilter</filter-name>
-
- <url-pattern>/hw/showTopic.jsp</url-pattern>
- </filter-mapping>
复制代码 redeployTomcat,在浏览器访问http://localhost:8080/filter/hw/topic.jsp
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |