简介
Filter也称之为过滤器,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
过滤器可以拦截请求和响应,,操作请求和响应中的数据,,控制是否允许访问目标资源,,url级别的拦截 (粗粒度)。
原理
一个过滤器
首先在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest 。根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据。
然后在HttpServletResponse到达客户端之前,拦截HttpServletResponse 。根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
基本应用
1,创建一个Filter
public class Filter1 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 为了调用子类的方法 HttpServletRequest httpServletRequest = (HttpServletRequest) request; System.out.println("***** 执行过滤器1 ... ...拦截路径: " + httpServletRequest.getRequestURI()); // 允许访问目标资源,简称 放行 chain.doFilter(httpServletRequest, response); } @Override public void destroy() { } }
2,web.xml配置
<!-- 注册过滤器 --> <filter> <filter-name>filter1</filter-name> <filter-class>com.test.web.filter.Filter1</filter-class> <!-- 配置当前过滤器的配置信息 --> <init-param> <param-name>safeNum</param-name> <param-value>10</param-value> </init-param> </filter> <!-- 映射过滤器需要拦截的路径 --> <filter-mapping> <filter-name>filter1</filter-name> <url-pattern>/hello.jsp</url-pattern> <url-pattern>/HelloServlet</url-pattern> </filter-mapping>
过滤器链(多个过滤器共同拦截)
注意:我们下面的两个过滤器都拦截了同样的路径,先后顺序是由映射决定的,而不是注册顺序,也就是说下面这两个过滤器先执行的是filter2而不是filter1
<!-- 注册过滤器 --> <filter> <filter-name>filter1</filter-name> <filter-class>com.test.web.filter.Filter1</filter-class> </filter> <filter> <filter-name>filter2</filter-name> <filter-class>com.test.web.filter.Filter2</filter-class> </filter> <!-- 映射过滤器需要拦截的路径 --> <filter-mapping> <filter-name>filter2</filter-name> <url-pattern>/hello.jsp</url-pattern> <url-pattern>/HelloServlet</url-pattern> </filter-mapping> <filter-mapping> <filter-name>filter1</filter-name> <url-pattern>/hello.jsp</url-pattern> <url-pattern>/HelloServlet</url-pattern> </filter-mapping>
生命周期
如下所示,1:实例化 2,初始化 3,拦截工作 4,销毁
public class Filter2 implements Filter { public Filter2() { System.out.println("----------- 1 执行Filter2的构造方法"); } public void init(FilterConfig fConfig) throws ServletException { System.out.println("----------- 2 执行Filter2的初始化方法"); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 为了调用子类的方法 HttpServletRequest httpServletRequest = (HttpServletRequest) request; System.out.println("----------- 3 执行Filter2的执行拦截的方法 , 拦截路径:" + httpServletRequest.getRequestURI());// 放行 chain.doFilter(request, response); } public void destroy() { System.out.println("----------- 4 执行Filter2的销毁的方法 "); } }
过滤器拦截方式
1 直接请求(默认)
2 请求转发(forward)
3 错误页面跳转(error)
4 引入其他页面(include)
如果你修改拦截方式,需要在web.xml中 通过 dispatcher标签指定。
<filter> <display-name>Filter2</display-name> <filter-name>Filter2</filter-name> <filter-class>com.test.web.filter.Filter2</filter-class> <!-- 配置当前过滤器的配置信息 --> <init-param> <param-name>safeNum</param-name> <param-value>10</param-value> </init-param> </filter> <filter-mapping> <filter-name>Filter2</filter-name> <url-pattern>/hello.jsp</url-pattern> <!-- 配置拦截jsp的方式: 请求转发 --> <dispatcher>FORWARD</dispatcher> <!-- 增加拦截方式: 直接请求 --> <dispatcher>REQUEST</dispatcher> </filter-mapping> <filter-mapping> <filter-name>Filter2</filter-name> <url-pattern>/HelloServlet</url-pattern> </filter-mapping>
案例演示一:解决post方式获取参数乱码和浏览器乱码
Filter:
public class EncodingFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 1 解决获取参数中文乱码(post) request.setCharacterEncoding("utf-8"); // 2 解决浏览器出现的中文乱码 response.setContentType("text/html;charset=utf-8"); chain.doFilter(request, response); } public void destroy() { } public void init(FilterConfig fConfig) throws ServletException { } }
web.xml:
<filter> <display-name>EncodingFilter</display-name> <filter-name>EncodingFilter</filter-name> <filter-class>com.test.web.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
案例演示二:统一解决get和post获取参数乱码
Filter:
public class GenericEncodingFilter implements Filter { public void destroy() { } public void init(FilterConfig fConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 为了能够使用 子类的方法, 向下转型 HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 对子类获取参数的方法进行增强: 包装 HttpServletRequest myRequest = new MyRequest(httpServletRequest); // 放行 chain.doFilter(myRequest, response); } class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; // 标识: 表示map是否处理过 private boolean isUpdate = false; // 表示没有处理 public MyRequest(HttpServletRequest request) { super(request); // 注意: 这行代码不能丢失 this.request = request; } @Override public Map<String, String[]> getParameterMap() { // 1 获取请求方式 String method = request.getMethod(); // 2 判断 if ("post".equalsIgnoreCase(method)) { // 2.1 如果是post方式, 设置请求编码集, 返回map即可 try { request.setCharacterEncoding("utf-8"); return request.getParameterMap(); // 结束当前方法 } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if ("get".equalsIgnoreCase(method)) { // 2.2 如果是get方式 // 2.2.1 获取map(没有处理) Map<String, String[]> parameterMap = request.getParameterMap(); // 2.2.2 遍历map中的值, 使用先编码,再解码 解决乱码问题 if (parameterMap != null && isUpdate==false) { // 如果map没有处理过且不为null,才会被处理 for (Entry<String, String[]> en : parameterMap.entrySet()) { String[] valArr = en.getValue(); // 数组是一个引用(地址) for (int i = 0; i < valArr.length; i++) { // 注意: // 这里不能使用增强for循环 try { valArr[i] = new String(valArr[i].getBytes("iso-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } // 处理完map需要将状态修改为true isUpdate = true; } // 2.2.3 返回map(处理过) return parameterMap; } return super.getParameterMap(); } // 改造获取非多选的值 @Override public String getParameter(String name) { // 1 获取已经处理好的map Map<String, String[]> parameterMap = this.getParameterMap(); // 2 从map中获取正确的值 String[] valArr = parameterMap.get(name); // 3 判断 if (valArr != null) { return valArr[0]; } else { return null; } } @Override public String[] getParameterValues(String name) { // 1 获取已经处理好的map Map<String, String[]> parameterMap = this.getParameterMap(); // 2 从map中获取正确的值 String[] valArr = parameterMap.get(name); return valArr; } } }
web.xml:
<filter> <display-name>GenericEncodingFilter</display-name> <filter-name>GenericEncodingFilter</filter-name> <filter-class>com.test.web.filter.GenericEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>GenericEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>