[TOC]
# 过滤器
## 为什么要使用过滤器
把请求中需要全局处理的逻辑放在过滤器中执行,控制层专心做与自己本身相关的事情(获取参数、处理业务逻辑、传递数据、页面跳转)。
在实际的开发中,我们一般将诸如页面编码设置、登陆用户 Session 判断等放在过滤器中执行。
![](https://box.kancloud.cn/e69696f764f5e3b0ea0427da0531f3d5_651x273.png)
## 如何使用过滤器
过滤器是一个实现了 javax.servlet.Filter 的类,在 Web 服务器启动的时候会被初始化。
- 定义过滤器类
~~~
package cn.filters;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {
private String encoding = "UTF-8";
/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
HttpServletRequest req = (HttpServletRequest) request;
req.setCharacterEncoding(encoding);
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
String en = fConfig.getInitParameter("Encoding");
if (null != en && !en.equals("")) {
encoding = en;
}
}
}
~~~
- 认识 web.xml
web.xml 放置在 WEB-INF 目录下,是 Servlet 容器中一个非常重要的配置文件。
在 web.xml 中主要定义的几个元素包括:Filter、Servlet(Servlet现在一般使用注解的方式,将请求的地址定义在类注解中),其中,Filter 建议定义在 web.xml 做更加精细的控制。
welcome-file-list 节点是默认欢迎页面的定义
**在 web.xml 中注册过滤器**
web.xml 实例代码
~~~
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>demo3</display-name>
<welcome-file-list>
<welcome-file>Login2Servlet</welcome-file>
<welcome-file>LoginServlet</welcome-file>
</welcome-file-list>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.filters.EncodingFilter</filter-class>
<init-param>
<param-name>Encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>cn.filters.SessionFilter</filter-class>
<init-param>
<param-name>UnCheckUrls</param-name>
<param-value>/LoginServlet#/LogoutServlet#/LoginCheckServlet</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
~~~
> 其中 `filter-mapping` 决定了过滤器执行的顺序
## 定义复杂的过滤器
1. 映射过滤应用程序中所有资源
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>/*</url-pattern> //访问当前主机,当前应用程序根下的所有文件包括多级子目录下的所有文件,注意这里*前有“/”
</filter-mapping>
~~~
2. 过滤指定的类型文件资源
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>*.html</url-pattern> //访问当前主机,当前应用程序根目录下的所有html文件,注意:*.html前没有“/”,否则错误
</filter-mapping>
~~~
> 其中*.html要过滤jsp那么就改*.html为*.jsp,但是注意没有“/”斜杠。如果要同时过滤多种类型资源:
**方法1 url-pattern 分开写**
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>*.jsp</url-pattern>//访问当前主机,当前应用程序根目录以所有及子目录下的所有jsp文件
</filter-mapping>
~~~
**方法2 将url-pattern合并**
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>*.html;*.jsp</url-pattern>
</filter-mapping>//*.html;*.jsp两类型之间用分号;间隔
~~~
3. 过滤指定的目录下的所有文件
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>/folder_name/*</url-pattern>//访问当前主机,当前应用程序根目录下的folder_name子目录(可是多级子目录)下所有文件
</filter-mapping>
~~~
4. 过滤指定的servlet
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<servlet-name>loggerservlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>loggerservlet</servlet-name>
<servlet-class>myfilter.LoggerServlet</servlet-class>
</servlet>
~~~
5. 过滤指定文件(即单一文件)
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>/simplefilter.html</url-pattern>
</filter-mapping>
~~~
6. 过滤指定目录下的指定类型的所有文件
> 这种情况下在web.xml中无法一次性配置完成,需要结合filter的实现类
> 首先在web.xml中配置过滤指定目录下的所有文件
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>/dir_name/*</url-pattern>
</filter-mapping>
~~~
然后在filter的实现类中的doFilter方法中获取请求的uri或者url,判断uri或者url中是否包含指定文件类型的字符串,决定是否过滤。
~~~
//获得用户请求的uri
String uri = request.getRequestURI();
if(uri.contains(".jsp")||uri.contains(".html"))
System.out.println("开始过滤"+url);
~~~
7. 过滤指定目录下指定类型的单一文件
~~~
<filter>
<filter-name>loggerfilter</filter-name>
<filter-class>myfilter.LoggerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loggerfilter</filter-name>
<url-pattern>/dir_name/index.jsp</url-pattern>
</filter-mapping>
~~~
> 以上都要注意是否有斜杠“/”