过滤器
当浏览器发送请求给服务器的时候,先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。
过滤一些敏感的字符串【规定不能出现敏感字符串】、避免中文乱码【规定Web资源都使用UTF-8编码】、权限验证【规定只有带Session或Cookie的浏览器,才能访问web资源】等等等
也就是说:当需要限制用户访问某些资源时、在处理请求时提前处理某些资源、服务器响应的内容对其进行处理再返回、我们就是用过滤器来完成的!
filter是如何实习拦截的? Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
调用目标资源之前,让一段代码执行。
是否调用目标资源(即是否让用户访问web资源)。
调用目标资源之后,让一段代码执行。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对 象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方 法,即web资源就会被访问,否则web资源不会被访问。
api 1 2 3 4 5 public interface Filter {void init (FilterConfig varl) ;void doFilter (ServletRequest val1,ServletResponse val2,FilterChain val3) ;void destroy () ;}
创建:
filter的创建和销毁是由web服务器负责的。web程序启动时,web服务器将创建Filter 的实例对象 ,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
销毁:
Web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。
filter开发和部署 Filter开发分为二个步骤:
编写java类实现Filter接口,并实现其doFilter方法。
在 web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class FilterDemo01 implements Filter { @Override public void init (FilterConfig filterConfig) throws ServletException { System.out.println("----过滤器初始化----" ); } @Override public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8" ); response.setCharacterEncoding("UTF-8" ); response.setContentType("text/html;charset=UTF-8" ); System.out.println("FilterDemo01执行前!!!" ); chain.doFilter(request, response); System.out.println("FilterDemo01执行后!!!" ); } @Override public void destroy () { System.out.println("----过滤器销毁----" ); } }
filter的部署 注册filter <filter>
用于注册过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <filter > <description > FilterDemo02过滤器</description > <filter-name > FilterDemo02</filter-name > <filter-class > me.gacl.web.filter.FilterDemo02</filter-class > <init-param > <description > 配置FilterDemo02过滤器的初始化参数</description > <param-name > name</param-name > <param-value > gacl</param-value > </init-param > <init-param > <description > 配置FilterDemo02过滤器的初始化参数</description > <param-name > like</param-name > <param-value > java</param-value > </init-param > </filter >
<filter-name>
用于为过滤器指定一个名字 ,该元素的内容不能为空。
<filter-class>
元素用于指定过滤器的完整的限定类名 。
<init-param>
元素用于为过滤器指定初始化参数,它的子元素、<param-name>指定参数的名字,<param-value>
指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数 。
<description>
用于添加描述信息,该元素的内容可为空,<description>可以不配置。
filter-mapping(映射过滤器) <filter-mapping>
元素用于设置一个Filter 所负责拦截的资源 。
一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
1 2 3 4 <filter-mapping > <filter-name > FilterDemo1</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
<filter-name>
子元素用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字
<url-pattern>
设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<servlet-name>
指定过滤器所拦截的Servlet名称 。
<dispatcher>
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST 。用户可以设置多个<dispatcher>
子元素用来指定 Filter 对资源的多种调用方式进行拦截。
dispatcher 子元素可以设置的值及其意义:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器 。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用 。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用 ,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用 。除此之外,过滤器不会被调用。
通过注解配置 1 2 @WebFilter(filterName = "FilterDemo1",urlPatterns = "/*")
Filter链 在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。 web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
简单应用 javaweb学习总结(四十三)——Filter高级开发 - 孤傲苍狼 - 博客园 (cnblogs.com) javaweb学习总结(四十六)——Filter(过滤器)常见应用 - 孤傲苍狼 - 博客园 (cnblogs.com)
filter的三种典型应用:
1、可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行
2、在让目标资源执行之前,可以对requestresponse作预处理,再让目标资源执行
3、在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能
禁止浏览器缓存所有动态页面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void doFilter (ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; response.setDateHeader("Expires" , -1 ); response.setHeader("Cache-Control" , "no-cache" ); response.setHeader("Pragma" , "no-cache" ); chain.doFilter(request, response); }
实现自动登陆 开发实体、集合模拟数据库、Dao
1 2 3 4 5 6 7 8 9 10 11 12 13 private String username ;private String password;public User () {} public User (String username, String password) { this .username = username; this .password = password; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class UserDB { private static List<User> users = new ArrayList <>(); static { users.add(new User ("aaa" , "123" )); users.add(new User ("bbb" , "123" )); users.add(new User ("ccc" , "123" )); } public static List<User> getUsers () { return users; } public static void setUsers (List<User> users) { UserDB.users = users; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public User find (String username, String password) { List<User> userList = UserDB.getUsers(); for (User user : userList) { if (user.getUsername().equals(username) && user.getPassword().equals(password)) { return user; } } return null ; } public User find (String username) { List<User> userList = UserDB.getUsers(); for (User user : userList) { if (user.getUsername().equals(username)) { return user; } } return null ; }
登陆界面 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <form action ="${pageContext.request.contextPath}/LoginServlet" > 用户名<input type ="text" name ="username" > <br > 密码<input type ="password" name ="password" > <br > <input type ="radio" name ="time" value ="10" > 10分钟 <input type ="radio" name ="time" value ="30" > 30分钟 <input type ="radio" name ="time" value ="60" > 1小时 <br > <input type ="submit" value ="登陆" > </form >
处理登陆的Servlet 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 String username = request.getParameter("username" );String password = request.getParameter("password" );UserDao userDao = new UserDao ();User user = userDao.find(username, password);if (user == null ) { request.setAttribute("message" , "用户名或密码是错的!" ); request.getRequestDispatcher("/message.jsp" ).forward(request, response); } request.getSession().setAttribute("user" , user); request.setAttribute("message" , "恭喜你,已经登陆了!" ); Cookie cookie = new Cookie ("autoLogin" , user.getUsername() + "." + user.getPassword());cookie.setMaxAge(Integer.parseInt(request.getParameter("time" )) * 60 ); response.addCookie(cookie); request.getRequestDispatcher("/message.jsp" ).forward(request, response);
过滤器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 HttpServletResponse response = (HttpServletResponse) resp; HttpServletRequest request = (HttpServletRequest) req; if (request.getSession().getAttribute("user" ) != null ) { chain.doFilter(request, response); return ; } Cookie[] cookies = request.getCookies(); String value = null ; for (int i = 0 ; cookies != null && i < cookies.length; i++) { if (cookies[i].getName().equals("autoLogin" )) { value = cookies[i].getValue(); } } if (value != null ) { String username = value.split("\\." )[0 ]; String password = value.split("\\." )[1 ]; UserDao userDao = new UserDao (); User user = userDao.find(username); String dbPassword = md5.md5(user.getPassword()); if (password.equals(dbPassword)) { request.getSession().setAttribute("user" , user); } } ;
过滤敏感词 要实现这样的功能也很简单,用户输入的敏感词肯定是在getParameter()获取的,我们在getParameter()得到这些数据的时候,判断有没有敏感词汇,如果有就替换掉就好了!简单来说:也是要增强request对象
增强request对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class MyDirtyRequest extends HttpServletRequestWrapper { HttpServletRequest request; private List<String> list = Arrays.asList("傻b" , "尼玛" , "操蛋" ); public MyDirtyRequest (HttpServletRequest request) { super (request); this .request = request; } @Override public String getParameter (String name) { String value = this .request.getParameter(name); if (value == null ) { return null ; } for (String s : list) { if (s.equals(value)) { value = "*****" ; } } return value ; } }
开发过滤器 1 2 3 4 5 6 7 8 9 10 11 public void doFilter (ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest httpServletRequest = (HttpServletRequest) req; HttpServletResponse httpServletResponse = (HttpServletResponse) resp; MyDirtyRequest dirtyRequest = new MyDirtyRequest (httpServletRequest); chain.doFilter(dirtyRequest, httpServletResponse); }