一、Filter简介
Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,Web开发人员通过Filter技术,对Web服务器管理的所有Web资源:例如Jsp,Servlet,静态图片文件或静态HTML文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、自动登录、压缩响应信息等一些高级功能。
Servlet API中提供了一个Filter接口,开发Web应用时,如果编写的Java类实现了这个接口,则把这个Java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:
二、Filter开发步骤
1、编写Java类实现Filter接口,并实现doFilter方法。
2、在Web.xml文件中使用<filter>和<filter-mapping>元素对编写的Filter类进行注册,并设置它所能拦截的资源。
三、Filter链
1、在一个Web应用中,可以开发编写多个Filter,这些Filter组合起来称之为Filter链。
2、Web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有Filter,如果有,则调用第2个Filter,如果没有,则调用目标资源。
四、过滤器生命周期
空参构造() 1次
init() 1次
doFilter(请求,响应,过滤器链) N次,与请求次数有关
destory() 1次
Filter是一个单例
五、使用Filter读取配置文件信息
1、web.xml
<filter> <filter-name>FilterDemo4</filter-name> <filter-class>com.gnnuit.web.filter.FilterDemo4</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>FilterDemo4</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2、FilterDemo4.java
package com.gnnuit.web.filter; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; //使用FilterConfig读取配置文件的信息 public class FilterDemo4 implements Filter { private FilterConfig filterConfig; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 方式一:读取一个 String encoding = filterConfig.getInitParameter("encoding"); response.setContentType("text/html;charset=" + encoding); // 方式二:读取多个 Enumeration<String> enums = filterConfig.getInitParameterNames(); while (enums.hasMoreElements()) { String key = enums.nextElement(); String value = filterConfig.getInitParameter(key); System.out.println(key + ":" + value); } chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } }
五、Filter应用
1、统一Post请求中文字符编码的过滤器。(通过配置参数encoding指明使用何种字符编码,以处理表单form请求参数的中文问题)
(1)web.xml
<filter> <filter-name>FilterDemo5</filter-name> <filter-class>com.gnnuit.web.filter.FilterDemo5</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>FilterDemo5</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(2)FilterDemo5.java
package com.gnnuit.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; //post请求中文字符编码的过滤器 public class FilterDemo5 implements Filter { private FilterConfig filterConfig; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 设置post请求编码 request.setCharacterEncoding("utf-8"); // 设置输出编码 String encoding = filterConfig.getInitParameter("encoding"); response.setContentType("text/html;charset=" + encoding); chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } }
2、禁止浏览器缓存所有动态页面的过滤器和控制浏览器缓存页面中的静态资源的过滤器
(1)web.xml
<filter> <filter-name>FilterDemo6</filter-name> <filter-class>com.gnnuit.web.filter.FilterDemo6</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>html</param-name> <param-value>86400</param-value> </init-param> </filter> <filter-mapping> <filter-name>FilterDemo6</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(2)FilterDemo6.java
package com.gnnuit.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //禁止浏览器缓存所有动态资源[例如JSP资源] //浏览器缓存所有静态资源,并指定缓存时间[例如html资源] public class FilterDemo6 implements Filter { private FilterConfig filterConfig; @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String uri = httpRequest.getRequestURI(); if (uri != null && uri.endsWith("jsp")) { httpResponse.setHeader("expires", "-1"); httpResponse.setHeader("cache-control", "no-cache"); httpResponse.setHeader("pragma", "no-cache"); } else if (uri != null && uri.endsWith(".html")) { String strHtml = filterConfig.getInitParameter("html"); long time = System.currentTimeMillis() + Integer.parseInt(strHtml) * 1000; // time为毫秒值 httpResponse.setDateHeader("expires", time); httpResponse.setHeader("cache-control", time / 1000 + ""); httpResponse.setHeader("pragma", time / 1000 + ""); } chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } }
3、使用Filter实现URL级别的权限认证(情景:在实际开发中我们经常把一些执行敏感操作的Servlet映射到一些特殊目录中,并用Filter把这些特殊目录保护起来,限制只能拥有相应访问权限的用户才能访问这些目录下的资源。从而在我们的系统中实现一种URL级别的权限功能。)
(1)login.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body> <form action="/day19/message.jsp" method="post"> <table border="1" align="center"> <caption>用户登录</caption> <tr> <th>用户名</th> <td><input type="text" name="username"/></td> </tr> <tr> <th>密码</th> <td><input type="password" name="password"/></td> </tr> <tr> <th>角色</th> <td> <select name="role"> <option selected="selected" value="管理员">管理员</option> <option value="普通用户">普通用户</option> </select> </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="提交"/> </td> </tr> </table> </form> </body> </html>
(2)FilterDemo7.java
package com.gnnuit.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; //对目录实现URL级别的角色认证 public class FilterDemo7 implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); String role = request.getParameter("role"); System.out.println("role="+role); if (username != null && password != null) { if (username.trim().length() > 0 && password.trim().length() > 0) { if ("管理员".equals(role)) { request.setAttribute("message", "欢迎管理员" + username + "登录"); request.setAttribute("flag", "admin"); } else if ("普通用户".equals(role)) { request.setAttribute("message", "欢迎普通用户" + username + "登录"); request.setAttribute("flag", "user"); } } else { request.setAttribute("message", "用户名或密码为空"); } } else { request.setAttribute("message", "用户名或密码为空"); } chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } }
(3)message.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> ${message }<br/> <c:choose> <c:when test="${flag=='admin' }"> <a href="#">下载</a> </c:when> <c:when test="${flag=='user' }"> <a href="#">下载</a> </c:when> </c:choose> </body> </html>
(4)web.xml
<filter> <filter-name>FilterDemo7</filter-name> <filter-class>com.gnnuit.web.filter.FilterDemo7</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo7</filter-name> <url-pattern>/message.jsp</url-pattern> </filter-mapping>
4、实现用户自动登录的过滤器。(1、在用户登录成功后,发送一个名称为user的Cookie给客户端,Cookie的值为用户名和密码。2、编写一个AutoLoginFilter,这个Filter检查用户是否带有名称为user的Cookie来,如果有,则调用dao查询Cookie的用户名和密码是否和数据库匹配,匹配则向Session中存入user对象(即用户登录标记),以实现程序完成自动登录)。
(1)login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> <form action="${pageContext.request.contextPath }/LoginServlet" method="post"> <table border="1" align="center"> <caption>用户登录</caption> <tr> <th>用户名</th> <td><input type="text" name="username"/></td> </tr> <tr> <th>密码</th> <td><input type="password" name="password"/></td> </tr> <tr> <td colspan="2" align="center"> <input type="radio" name="time" value="60"/>一分钟 <input type="radio" name="time" value="180"/>三分钟 <input type="radio" name="time" value="300"/>五分钟 </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="提交"/> </td> </tr> </table> </form> </body> </html>
(2)LoginServlet.java
package com.gnnuit.web.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); if (username != null && password != null && username.trim().length() > 0 && password.trim().length() > 0) { if (username.equals("jack") && password.equals("123")) { // 登录成功,将信息绑定到HttpSession域对象中 request.getSession().setAttribute("username", username); request.getSession().setAttribute("password", password); // 向浏览器写入Cookie Cookie cookie = new Cookie("usernameAndPassword", username + "_" + password); int time = Integer.parseInt(request.getParameter("time")); cookie.setMaxAge(time); response.addCookie(cookie); // 重定向到welcome.jsp页面 response.sendRedirect(request.getContextPath() + "/welcome.jsp"); } } } }
(3)AutoPostFilter.java
package com.gnnuit.web.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; //自定义登录Filter过渡器 public class AutoPostFilter implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; Cookie[] cookies = httpRequest.getCookies(); Cookie userCookie = null; if (cookies != null) { for (Cookie c : cookies) { if ("usernameAndPassword".equals(c.getName())) { userCookie = c; break; } } if (userCookie != null) { String usernameAndPassword = userCookie.getValue(); String[] values = usernameAndPassword.split("_"); if("jack".equals(values[0].trim())&& "123".equals(values[1].trim())){ httpRequest.getSession().setAttribute("username",values[0]); chain.doFilter(request, response); } }else{ httpRequest.getRequestDispatcher("/login.jsp").forward(request, response); } }else{ //httpRequest.getSession().setAttribute("username","游客"); httpRequest.getRequestDispatcher("/login.jsp").forward(request, response); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
(4)welcome.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <body> 欢迎 ${username }光临 </body> </html>
(5)web.xml
<filter> <filter-name>AutoPostFilter</filter-name>
<filter-class>com.gnnuit.web.filter.AutoPostFilter</filter-class> </filter>
<filter-mapping>
<filter-name>AutoPostFilter</filter-name>
<url-pattern>/welcome.jsp</url-pattern> </filter-mapping>