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

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

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

目录

Filter 过滤器

Filter 过滤器说明

过滤器介绍

4. 应用场景

Filter 过滤器基本原理

代码示例

login.jsp

LoginCLServlet.java

admin.jsp

ManageFilter.java

xml配置

Filter 过滤器 url-pattern

Filter 过滤器生命周期

● Filter 生命周期图

FilterConfig

● FilterConfig 说明

应用实例

 WyxFilterConfig 

 web.xml

FilterChain 过滤器链

基本原理示意图

应用实例 

 AFilter.java

BFilter.java

hi.jsp

xml

FilterChain 注意事项和细节

6. 小结:

综合代码示例

运行效果图

 topic.jsp

TopicServlet.java

配置过滤器

showTopic.jsp


Filter 过滤器

Filter 过滤器说明

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

 

 

过滤器介绍

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

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

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

 

4. 应用场景

● 权限检查

● 日记操作

● 事务管理

Filter 过滤器基本原理

代码示例

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

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>管理后台登录</title>
</head>
<body>
<h1>管理后台登录</h1>
<%System.out.println("request=" + request);
%>
<form action="<%=request.getContextPath() %>/loginCheckServlet" method="post">u:<input type="text" name="username"/> <br/><br/>p:<input type="password" name="password"/> <br/><br/><input type="submit" value="用户登录"/></form>
</body>
</html>

LoginCLServlet.java

public class LoginCheckServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取到用户名和密码->DB//假设密码是123456, 就可以通过String username = request.getParameter("username");String password = request.getParameter("password");System.out.println("request=" + request);if("123456".equals(password)) {//合法, 讲用户名,加入sessionrequest.getSession().setAttribute("username", username);//请求转发到admin.jsprequest.getRequestDispatcher("/manage/admin.jsp").forward(request,response);} else {//不合法, 返回登录页面request.getRequestDispatcher("/login.jsp").forward(request,response);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

admin.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>后台管理</title><base href="<%=request.getContextPath() %>/manage/"/>
</head>
<body>
<h1>后台管理</h1>
<%//验证request对象是和前面的filter是一个对象System.out.println("request=" + request);
%>
<a href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a>
<hr/>
<img src="shunping.jpg" height="300"/>
</body>
</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,那么会继续传递*/
public class ManageFilter implements Filter {private int count = 0;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {//当Tomcat 创建 Filter创建,就会调用该方法,进行初始化//提醒:回忆我们自己实现tomcat底层机制+servlet程序System.out.println("ManageFilter init被调用...");}@Overridepublic void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException, ServletException {System.out.println("ManageFilter doFilter() 被调用=" + (++count));//到每次调用该filter时,doFilter就会被调用//如果这里,没有调用继续请求的方法,则就停止//如果继续访问目标资源-> 等价于放行//说明:在调用过滤器前,servletRequest对象=request已经被创建并封装//所以:我们这里就可以通过servletRequest获取很多信息, 比如访问url , session//比如访问的参数 ... 就可以做事务管理,数据获取,日志管理等//获取到session//可以继续使用 httpServletRequest 方法.HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;System.out.println("输入密码=" + httpServletRequest.getParameter("password"));HttpSession session = httpServletRequest.getSession();//获取username session对象, 还可以继续使用Object username = session.getAttribute("username");if (username != null) {//filterChain.doFilter(servletRequest, servletResponse)//1. 继续访问目标资源url//2. servletRequest 和 servletResponse 对象会传递给目标资源/文件//3. 一定要理解filter传递的两个对象,再后面的servlet/jsp 是同一个对象(指的是在一次http请求)System.out.println("servletRequest=" + servletRequest);System.out.println("日志信息==");System.out.println("访问的用户名=" + username.toString());System.out.println("访问的url=" + httpServletRequest.getRequestURL());System.out.println("访问的IP=" + httpServletRequest.getRemoteAddr());filterChain.doFilter(servletRequest, servletResponse);} else {//说明没有登录过..回到登录页面servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);}}@Overridepublic void destroy() {//当filter被销毁时,会调用该方法System.out.println("ManageFilter destroy()被调用..");}
}

xml配置

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

public class WyxFilterConfig implements Filter {private String ip; //从配置获取的ip@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("WyxFilterConfig init() 被调用..");//通过filterConfig 获取相关的参数String filterName = filterConfig.getFilterName();ip = filterConfig.getInitParameter("ip");ServletContext servletContext = filterConfig.getServletContext();//可以获取到该filter所有的配置参数名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);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//通过forbidden ip 来进行控制//先获取到访问ipString remoteAddr = servletRequest.getRemoteAddr();if(remoteAddr.contains(ip)) {System.out.println("封杀该网段..");servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);return; //直接返回}//继续访问目标资源filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {}
}

 web.xml

    <filter><filter-name>WyxFilterConfig</filter-name><filter-class>com.filter.WyxFilterConfig</filter-class><!--这里就是给该filter配置的参数-根据业务逻辑来设置--><init-param><param-name>ip</param-name><param-value>127.0</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>123@qq.com</param-value></init-param></filter><filter-mapping><filter-name>WyxFilterConfig</filter-name><url-pattern>/abc/*</url-pattern></filter-mapping>

FilterChain 过滤器链

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

基本原理示意图

应用实例 

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

 AFilter.java

public class AFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("AFilter---> 线程id=" +Thread.currentThread().getId());System.out.println("AFilter doFilter 的前置代码...");System.out.println("执行 AFilter doFilter()");filterChain.doFilter(servletRequest, servletResponse);System.out.println("AFilter doFilter 的后置代码...");}@Overridepublic void destroy() {}
}

BFilter.java

public class BFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("BFilter---> 线程id=" +Thread.currentThread().getId());System.out.println("BFilter doFilter 的前置代码...");System.out.println("执行 BFilter doFilter()");filterChain.doFilter(servletRequest, servletResponse);System.out.println("BFilter doFilter 的后置代码...");}@Overridepublic void destroy() {}
}

hi.jsp

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

xml

 <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>

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

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

TopicServlet.java

public class TopicFilter implements Filter {//属性-> 存放禁用词private String[] forbiddenWords = null;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {//获取禁用词String forbiddenword = filterConfig.getInitParameter("forbiddenword");forbiddenWords = forbiddenword.split(",");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//解决从topic.jsp 提交的中文乱码问题servletRequest.setCharacterEncoding("utf-8");//判断评论是不是有禁用词String content = servletRequest.getParameter("content");//循环遍历一把,看看有没有禁用词for (String forbiddenWord : forbiddenWords) {//java基础if (content.contains(forbiddenWord)) {//返回topic.jspservletRequest.setAttribute("errorInfo", "你输入的有禁用词");servletRequest.getRequestDispatcher("/topic.jsp").forward(servletRequest, servletResponse);return;//返回}}//继续到目标filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}
}

配置过滤器

<filter><filter-name>TopicFilter</filter-name><filter-class>com.filter.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>/topic/*</url-pattern></filter-mapping>

showTopic.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>你发表的评论是</h1>
评论内容: <%=request.getParameter("content")%>
</body>
</html>