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。
本文来自博客园,作者:独游空想家,转载请注明原文链接:https://www.cnblogs.com/linzhikai/p/16525321.html