一.过滤器Filter
-
Filter介绍
Servlet有三大组件:Servlet,Filter,Listener.
Filter中文意思为过滤,在Web中,过滤器可以在请求到达目标资源之前先对请求进行拦截,也就是可以先对请求进行一些处理,之后再放行去访问目标资源;也可以在响应返回到客户端之前对响应进行拦截,也就是可以对响应做一些处理,再返回给客户端。
-
过滤器作用
通过Filter,能够对web服务器管理的所有web资源,比如jsp,servlet,静态图片,静态html等文件进行拦截过滤,从而实现一些特殊的功能。比如登录验证,统一编码处理,敏感词汇过滤等。
-
Filter接口
在Servlet中,提供了一个接口
javax.servlet.Filter
,只要实现该接口的类,就可以称为过滤器。Filter接口有三个方法需要重写:
-
init()
:初始化方法,在服务器启动后会创建Filter对象,然后调用init方法,只会执行一次,用于加载资源。 -
doFilter()
:核心方法,对于请求和响应的过滤,都是在该方法中完成,每一次请求被拦截的资源时会执行。 -
destroy()
:销毁方法,在服务器关闭后,Filter对象被销毁,会执行该方法,只执行一次,一般用于释放资源。
-
-
创建Filter过滤器
- 创建一个类实现
javax.servlet.Filter
接口 - 重写接口中的方法
- 配置Filter(web.xml或者注解)
import javax.servlet.*; import java.io.IOException; public class FilterDemo1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Filter 初始化"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("Filter 调用"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("Filter 销毁"); } }
注意:在Filter的doFilter方法内部如果没有调用doFilter(request,response)方法,那么服务器中的资源是不会被访问到的。doFilter(request,response)就是一个放行
- 创建一个类实现
-
Filter细节
-
web.xml配置
-
注册Filter
<filter> <filter-name>Demo1</filter-name> <filter-class>com.zzy.www.filter.FilterDemo1</filter-class> <init-param> <param-name>path</param-name> <param-value>/WEB_INF/a.txt</param-value> </init-param> </filter>
<filter-name>
:设置过滤器的名字,内容不能为空<filter-class>
:指定过滤器的完整的类名<init-param>
:用于为过滤器指定初始化参数,<param-name>
指定参数的名称,<param-value>
指定参数的值。(在过滤器中可以使用FilterConfig接口对象来访问初始化参数)(多个参数就有多个<init-param>
) -
映射Filter
<filter-mapping> <filter-name>Demo1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter-name>
:用于设置Filter的注册名称,这个值必须是在注册Filter时<filter>中声明过的过滤器名字。<url-pattern>
:设置Filter要拦截的请求路径。Filter的全路径匹配只支持/*,不支持/<filter-mapping>
还有两个标签<servlet-name>
和<dispatcher>
<servlet-name>
:指定过滤器要拦截的Servlet名称<dispatcher>
:指定过滤器拦截的资源被Servlet调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认是REQUEST。- REQUEST:默认值,只要不是由RequestDispatch的forward()或include()方法转发的,都会被该Filter拦截。
- FORWARD:当前Filter只会拦截由RequestDispatcher的forward()方法所转发的请求,其他的请求不会拦截。
- INCLUDE:只要是通过
<jsp:include page="xxx.jsp"/>
嵌入进来的页面,每一个嵌入的页面,都会走一次值为INCLUDE的过滤器。 - ERROR:当前Filter只会拦截转向错误页面的请求,其他请求不会拦截。
- ASYNC:会拦截AsyncContext对象发出的请求。
如果是注解的方式配置,则是设置dispatcherTypes属性。
-
-
过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 返回执行过滤器放行代码下边的代码
-
过滤器生命周期
- 当服务器启动时,会创建Filter对象,并调用init()方法,只会调用一次。
- 当访问资源时,路径与Filter的拦截路径匹配时,会执行Filter中的doFilter()方法,该方法是真正实现拦截操作的方法。
- 当服务器关闭时,会调用Filter的destroy()方法进行销毁,只会调用一次。
-
过滤器链(多个过滤器)
如果在web中设置了多个过滤器,那么这些过滤器执行过程是以一种链的形式执行的。
也就是每一个Filter串一起形成一条链,按照链的顺序依次执行,一个Filter执行完filterChain的doFilter()方法后,转而执行另一个Filter,直到最后一个Filter,最后一个Filter的filterChain.doFilter()会自动跳转到最终的请求资源。
在请求到达Filter之后,Filter可以拦截请求对象,并能对请求进行修改,修改过后再转向下一个Filter或资源。
当最终的资源执行完毕,形成了响应对象后,会按照Filter链的顺序逆序再次访问Filter,此时的Filter能够拦截到响应对象,并能对响应进行修改,最后客户端接收到的是被FIlter修改过的响应。
Filter3.png
-
-
Filter的特点
- Filter是单例多线程的
- FIlter是在web应用被加载时创建并初始化的,这点与Servlet不同(Servlet是在servlet第一次被访问时创建)
- 客户端每提交一次该Filter可以过滤的请求,服务器就会执行一次doFilter()方法,doFilter()方法是可以被多次执行的
- 由于Filter是单例多线程的,所以一般为了保证线程安全,是不会在FIlter类定义可以修改的成员变量的,因为会出现线程安全问题。
二.Filter例子
-
Filter解决乱码问题
之前编写servlet时候,在处理POST请求乱码时,需要在获取请求参数前设置request的编码
request.setCharacterEncoding("utf-8");
在响应时候,也需要处理乱码问题,之前是使用
response.setContentType("text/html;charset=utf-8");
这种处理方式很繁琐,需要在每一个servlet中都声明这些编码,可以通过使用过滤器,提取这些公有代码到过滤器中。
@WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); System.out.println("username: " + username); response.getWriter().println("用户名为:" + username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <form action="/BookTest/LoginServlet" method="post"> <label for="username">姓名:</label><input type="text" id="username" placeholder="请输入姓名" name="username"> <br> <input type="submit" value="登录"> </form> </body> </html>
@WebFilter(filterName = "FilterTest1", urlPatterns = "/*") public class FilterTest1 implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); chain.doFilter(req, resp); } public void init(FilterConfig config) throws ServletException { } }
-
登陆验证
针对用户访问网站,当用户未登录时只能访问首页,登陆页面,其他页面是没有权限访问的,必须登陆才能访问,此时过滤器可以做一个权限管控,如果用户已登录,就放行;否则则跳转到登录页面。
比如用户访问news.jsp页面.未登录前先访问news.jsp是会自动跳转到登录页面的,只有登录后访问才能直接访问news.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>news</title> </head> <body> <h1>Welcome!</h1> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录</title> </head> <body> <form action="/BookTest/LoginServlet" method="post"> <label for="username">姓名:</label><input type="text" id="username" placeholder="请输入姓名" name="username"> <br> <label for="password">密码:</label><input type="password" id="password" placeholder="请输入密码" name="password"><br> <input type="submit" value="登录"> </form> </body> </html>
@WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); System.out.println("username: " + username); if (username != null) { HttpSession s = request.getSession(); if (s.getAttribute("username") == null) { s.setAttribute("username", username); } } response.sendRedirect("/BookTest/news.jsp"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
@WebFilter(filterName = "FilterTest2",urlPatterns = "/*") public class FilterTest2 implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)resp; // 获取访问地址 String path = request.getServletPath(); System.out.println(path); if (path.startsWith("/news.jsp")) { HttpSession s = request.getSession(); System.out.println(s); // 说明还没登录 if (s == null) { // 跳转到登录界面 response.sendRedirect("/BookTest/login.html"); } else { String name = (String)s.getAttribute("username"); System.out.println("name = " + name); if (name == null) { response.sendRedirect("/BookTest/login.html"); } } } chain.doFilter(req, resp); } public void init(FilterConfig config) throws ServletException { } }
网友评论