过滤器sg(day27-过滤器Filter02)
Filter过滤器02
5.Filter过滤器生命周期
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:
<!--配置DemoFilterConfig--> <filter> <filter-name>DemoFilterConfig</filter-name> <filter-class>com.filter.DemoFilterConfig</filter-class> <!--这里就是给filter配置的参数-由程序员根据业务逻辑来设置--> <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:
<!--配置DemoFilterConfig--> <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 href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a> <hr/> </body> </html>在web.xml中配置filter:
<!--配置AFilter和BFilter--> <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> 过滤词:苹果,香蕉 <div>${notice}</div> 用户:<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>用户:<span> <%=request.getParameter("username")%></span></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:
<!--配置TopicFilter--> <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
输入不含敏感词的评论:
输入含敏感词的评论:
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!