Filter也称为过滤器,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,Servlet,
静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制,页面的同一编码,过滤敏感词汇、压缩响应信息等一些高级功能!
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
看一下filter中有哪些方法!
<span style="font-size:18px;">public class Demo1Filter implements Filter { //Filter 链的执行 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { } //Init 方法在 Filter 生命周期中仅执行一次,web 容器在调用 init 方法时 public void init(FilterConfig filterConfig) throws ServletException { } //在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。 public void destroy() { } } </span>
我们先来看一下在访问资源的时候,他的执行过程!
在我们的web容器启动时在 web
应用程序启动时,web 服务器将根据 web.xml
文件中的配置信息来创建每个注册的 Filter
实例对象,并将其保存在服务器的内存中。然后当用户用浏览器请求一个页面的时候, 会先向web的容器发送一个请求,然后web容器在根据请求去找相应的资源!在找资源的时候,会先经过Filter,然后在继续向后执行,一个应用程序中可以有多个filter!filter 的执行的顺序跟在web.xml文件中配置的顺序是一样的!
下边我们通过一个实例来看一下filter是如何应用的!
web.xml配置
<!-- 编码过滤器 --> <filter> <filter-name>setCharacterEncoding</filter-name> <filter-class>com.company.strutstudy.web.servletstudy.filter.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>setCharacterEncoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 请求url日志记录过滤器 --> <filter> <filter-name>logfilter</filter-name> <filter-class>com.company.strutstudy.web.servletstudy.filter.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>logfilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
编码拦截器:
public class EncodingFilter implements Filter { private String encoding; private Map<String, String> params = new HashMap<String, String>(); // 项目结束时就已经进行销毁 public void destroy() { System.out.println("end do the encoding filter!"); params=null; encoding=null; } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { //UtilTimerStack.push("EncodingFilter_doFilter:"); System.out.println("before encoding " + encoding + " filter!"); req.setCharacterEncoding(encoding); // resp.setCharacterEncoding(encoding); // resp.setContentType("text/html;charset="+encoding); chain.doFilter(req, resp); System.out.println("after encoding " + encoding + " filter!"); System.err.println("----------------------------------------"); //UtilTimerStack.pop("EncodingFilter_doFilter:"); } // 项目启动时就已经进行读取 public void init(FilterConfig config) throws ServletException { System.out.println("begin do the encoding filter!"); encoding = config.getInitParameter("encoding"); for (Enumeration e = config.getInitParameterNames(); e .hasMoreElements();) { String name = (String) e.nextElement(); String value = config.getInitParameter(name); params.put(name, value); } } }
日志拦截器:
public class LogFilter implements Filter { FilterConfig config; public void destroy() { this.config = null; } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { // 获取ServletContext 对象,用于记录日志 ServletContext context = this.config.getServletContext(); //long before = System.currentTimeMillis(); System.out.println("before the log filter!"); //context.log("开始过滤"); // 将请求转换成HttpServletRequest 请求 HttpServletRequest hreq = (HttpServletRequest) req; // 记录日志 System.out.println("Log Filter已经截获到用户的请求的地址:"+hreq.getServletPath() ); //context.log("Filter已经截获到用户的请求的地址: " + hreq.getServletPath()); try { // Filter 只是链式处理,请求依然转发到目的地址。 chain.doFilter(req, res); } catch (Exception e) { e.printStackTrace(); } System.out.println("after the log filter!"); //long after = System.currentTimeMillis(); // 记录日志 //context.log("过滤结束"); // 再次记录日志 //context.log(" 请求被定位到" + ((HttpServletRequest) req).getRequestURI() // + "所花的时间为: " + (after - before)); } public void init(FilterConfig config) throws ServletException { System.out.println("begin do the log filter!"); this.config = config; } }
HelloServlet类:
public class HelloWorldServlet extends HttpServlet{ /** * 查看httpservlet实现的service一看便知,起到了一个controll控制器的作用(转向的) * 之后便是跳转至我们熟悉的doget,dopost等方法中 */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doservice..."+this.getInitParameter("encoding")); super.service(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doget..."); doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("dopost..."); }
结果:
before encoding utf-8 filter! before the log filter! Log Filter已经截获到用户的请求的地址:/hello doservice...UTF-8 doget... dopost... after the log filter! after encoding utf-8 filter! ----------------------------------------
Filter生命周期
和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是
1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。
2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。
3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。
4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。
注意:init方法与destroy方法只会直接一次。