标签:
Filter 的基本功能是对发送到 Servlet 的请求进行拦截, 并对响应也进行拦截.
Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行
Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文件和静态 html 文件
①. 创建一个 Filter 类: 实现 Filter 接口: public class HelloFilter implements Filter
②. 在 web.xml 文件中配置并映射该 Filter. 其中 url-pattern 指定该 Filter 可以拦截哪些资源, 即可以通过哪些 url 访问到该 Filter
<!-- 注册 Filter --> <filter> <filter-name>helloFilter</filter-name> <filter-class>com.atguigu.javaweb.HelloFilter</filter-class> </filter> <!-- 映射 Filter --> <filter-mapping> <filter-name>helloFilter</filter-name> <url-pattern>/test.jsp</url-pattern> </filter-mapping>
①. Filter 接口:
> public void init(FilterConfig filterConfig): 类似于 Servlet 的 init 方法. 在创建 Filter 对象(Filter 对象在 Servlet 容器加载当前 WEB 应用时即被创建)后, 立即被调用, 且只被调用一次. 该方法用于对当前的 Filter 进行初始化操作. Filter 实例是单例的.
* FilterConfig 类似于 ServletConfig
* 可以在 web.xml 文件中配置当前 Filter 的初始化参数. 配置方式也和 Servlet 类似。
<filter> <filter-name>helloFilter</filter-name> <filter-class>com.atguigu.javaweb.HelloFilter</filter-class> <init-param> <param-name>name</param-name> <param-value>root</param-value> </init-param> </filter>
> public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 真正 Filter 的逻辑代码需要编写在该方法中. 每次拦截都会调用该方法.
* FilterChain: Filter 链. 多个 Filter 可以构成一个 Filter 链.
- doFilter(ServletRequest request, ServletResponse response):
把请求传给 Filter 链的下一个 Filter,若当前 Filter 是 Filter 链的最后一个 Filter, 将把请求给到目标 Serlvet(或 JSP)
- 多个 Filter 拦截的顺序和 <filter-mapping> 配置的顺序有关, 靠前的先被调用.
理解 Filter 链:
> public void destroy(): 类似于 Servlet 的destroy() 方法; 释放当前 Filter 所占用的资源的方法. 在 Filter 被销毁之前被调用, 且只被调用一次.
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST.
可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
①. REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
通过 GET 或 POST 请求直接访问。
②. FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
或 <jsp:forward page="/..." /> 或 通过 page 指令的 errorPage 转发页面. <%@ page errorPage="test.jsp" %>
②. INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。或 <jsp:include file="/..." />
④. ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
在 web.xml 文件中通过 error-page 节点进行声明:
<error-page> <exception-type>java.lang.ArithmeticException</exception-type> <location>/test.jsp</location> </error-page> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/test.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>
1. 禁用缓存的过滤器
有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
response.setDateHeader("Expires",-1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma","no-cache");
并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头
2. 解决字符编码的过滤器
通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题
3. 检验用户是否登录的过滤器
1). Servlet API 中提供了一个 HttpServletRequestWrapper 类来包装原始的 request 对象,HttpServletRequestWrapper 类实现了 HttpServletRequest 接口中的所有方法,
这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法
//包装类实现 ServletRequest 接口. public class ServletRequestWrapper implements ServletRequest { //被包装的那个 ServletRequest 对象 private ServletRequest request; //构造器传入 ServletRequest 实现类对象 public ServletRequestWrapper(ServletRequest request) { if (request == null) { throw new IllegalArgumentException("Request cannot be null"); } this.request = request; } //具体实现 ServletRequest 的方法: 调用被包装的那个成员变量的方法实现。 public Object getAttribute(String name) { return this.request.getAttribute(name); } public Enumeration getAttributeNames() { return this.request.getAttributeNames(); } //... }
相类似 Servlet API 也提供了一个 HttpServletResponseWrapper 类来包装原始的 response 对象
2). 作用: 用于对 HttpServletRequest 或 HttpServletResponse 的某一个方法进行修改或增强.
public class MyHttpServletRequest extends HttpServletRequestWrapper{ public MyHttpServletRequest(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String val = super.getParameter(name); if(val != null && val.contains(" fuck ")){ val = val.replace("fuck", "****"); } return val; } }
3). 使用: 在 Filter 中, 利用 MyHttpServletRequest 替换传入的 HttpServletRequest
HttpServletRequest req = new MyHttpServletRequest(request); filterChain.doFilter(req, response);
此时到达目标 Servlet 或 JSP 的 HttpServletRequest 实际上是 MyHttpServletRequest
/** * 自定义的 HttpFilter, 实现自 Filter 接口 * */ public abstract class HttpFilter implements Filter { /** * 用于保存 FilterConfig 对象. */ private FilterConfig filterConfig; /** * 不建议子类直接覆盖. 若直接覆盖, 将可能会导致 filterConfig 成员变量初始化失败 */ @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; init(); } /** * 供子类继承的初始化方法. 可以通过 getFilterConfig() 获取 FilterConfig 对象. */ protected void init() {} /** * 直接返回 init(ServletConfig) 的 FilterConfig 对象 */ public FilterConfig getFilterConfig() { return filterConfig; } /** * 原生的 doFilter 方法, 在方法内部把 ServletRequest 和 ServletResponse * 转为了 HttpServletRequest 和 HttpServletResponse, 并调用了 * doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) * * 若编写 Filter 的过滤方法不建议直接继承该方法. 而建议继承 * doFilter(HttpServletRequest request, HttpServletResponse response, * FilterChain filterChain) 方法 */ @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; doFilter(request, response, chain); } /** * 抽象方法, 为 Http 请求定制. 必须实现的方法. * @param request * @param response * @param filterChain * @throws IOException * @throws ServletException */ public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException; /** * 空的 destroy 方法。 */ @Override public void destroy() {} }
标签:
原文地址:http://www.cnblogs.com/linyueshan/p/5648332.html