Servlet_Filter过滤器

什么是Filter过滤器?

Filter过滤器是实现了javax.servlet.Filter接口的类,它的基本功能是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理的前后实现一些功能,例如设置网站的编码,或者实现自动登录等。


Filter接口中的方法

  • init(FilterConfig conf)方法: 用来初始化Filter过滤器。
  • doFilter(ServletRequest request,ServletResponse response,FilterChain chain)方法:把请求交付给Filter链的下一个Filter或目标程序去处理。
  • destroy()方法:Filter过滤器在销毁时自动调用,用来释放资源。

实现第一个Filter程序

先编写一个简单的Servlet程序

public class PServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("GBK");
        resp.getWriter().write("<h1>学习资料~</h>");
    }
}

编写Servlet映射

    <servlet>
        <servlet-name>PServlet</servlet-name>
        <servlet-class>Filter.PServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PServlet</servlet-name>
        <url-pattern>/pilipili</url-pattern>
    </servlet-mapping>

张三访问/pilipili获取学习资料~

到目前为止只是一个简单的Servlet程序,现在我们加入Filter过滤器拦截/pilipili请求,让张三看广告~
先编写Filter过滤器的实现类

public class AdvertFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { } // 初始化Filter过滤器
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        response.setCharacterEncoding("GBK");
        response.getWriter().write("<h1>广告~</h>");
    }
    @Override
    public void destroy() { } // Filter过滤器在销毁时自动调用,释放资源
}

编写Filter过滤器的映射

    <filter>
        <filter-name>Advert</filter-name>
        <filter-class>Filter.AdvertFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Advert</filter-name>
        <url-pattern>/pilipili</url-pattern>
    </filter-mapping>

当张三访问/pilipili时,会被我们设置的过滤器拦截,执行AdvertFilter程序

到此,一个简单的Filter过滤器程序的演示就完成了


Filter映射

Filter的映射方式有两种,一种是使用通配符"*"来实现,这个前面讲过了不再赘述,另一种方式是使用<filter-mapping>元素中的子元素<dispatcher>来指定过滤器所拦截的资源被Servlet容器调用的方式,它有以下4个值:

  • REQUEST(默认):当用户直接访问页面时会被拦截,如果是通过include方法或forward方法访问,则过滤器不会调用。
  • INCLUDE:通过RequestDispatcher的include方法访问,则该过滤器被调用。
  • FORWARD:通过RequestDispatcher的forward方法访问,则该过滤器被调用。
  • ERROR:如果是通过声明式异常处理机制调用,那么过滤器将被调用。
    看例子:
    准备一个pilipili.html文件用于输出学习资料~
<html>
<head>
    <title>Pilipili</title>
</head>
<body>
    <h1>学习资料~</h>
</body>
</html>

改造上面例子中的Servlet程序,映射文件不变(过滤器的映射记得先注释掉),将/pilipili请求以forward方法转发给pilipili.html页面

public class PServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/pilipili.html").forward(req,resp);
    }
}

此时,如果访问/pilipili,先通过映射文件找到PServlet类,然后再转发到pilipili.html页面

接下来在PServlet类转发到pilipili.html页面的过程中进行拦截
使用上面例子中的Filter过滤器类即可,修改配置文件,将虚拟路径改为pilipili.html

    <filter>
        <filter-name>Advert</filter-name>
        <filter-class>Filter.AdvertServlet</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Advert</filter-name>
        <url-pattern>/pilipili.html</url-pattern>
    </filter-mapping>

此时如果直接访问/pilipili依然会得到学习资料,因为虽然为/pilipili.html设置了过滤器,但是`<filter-mapping>`中没有指定<dispatcher>元素的值,默认为REQUEST,我们通过forward方法访问不会调用过滤器。我们将<dispatcher>的值指定为FORWARD,过滤器生效,跳转到广告


Filter链

Web应用可以注册多个Filter过滤器,当多个Filter过滤器都对同一个URL进行拦截时,会组成一个Filtet链。Filter链用FilterChain对象表示,使用FilterChain对象中的doFilter方法可以让当前Filter放行,使请求进入下一个Filter。

还是使用上面的例子,为/pilipili注册两个Filter并配置映射。(其他无关的映射记得注释掉,PServlet中的跳转也注释掉)

编写两个Filter过滤器的实现类,类名和输出不一样即可

public class Filter1 implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException { } // 初始化Filter过滤器
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        response.getWriter().write("<p>Filter1</p>");
        chain.doFilter(request,response);
        response.getWriter().write("<p>Filter1</p>");
    }
    public void destroy() { } // Filter过滤器在销毁时自动调用,释放资源
}

并配置两个Filter过滤器的映射

    <filter>
        <filter-name>Filter1</filter-name>
        <filter-class>Filter.Filter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter1</filter-name>
        <url-pattern>/pilipili</url-pattern>
    </filter-mapping>

访问/pilipili得到的结果为

1221有点类似于递归的情况,先遇到哪个Filter由映射的顺序决定,如果web.xml里Filter2的映射在前,Filter1的映射在后,那么结果就为2112。

posted @ 2022-07-27 21:16  独游空想家  阅读(199)  评论(0编辑  收藏  举报