定义
过滤器filter,也可以理解成拦截器,就是在访问web资源之前或之后,对其进行拦截,然后做一些处理后,再传给过滤器链中的下一个过滤器,或进入请求的servlet进行处理。filter可以用于对request过滤,也可以对response过滤。但常见的一般都用于拦截request,相当于在请求资源前先做一个预处理。
作用
不用的时候,直接去掉web.xml、@注解中注册的过滤器,不会影响servlet,不需要修改servlet部分代码等,所以易维护。
- 自动登录 CheckLoginFilter
- 统一设置编码格式 EncodeFilter
- 访问权限控制 AuthorityFilter
- 敏感字符过滤
- 输入验证
- 访问量统计
- 数据压缩
等等…
一个简单的filter示例
生命周期:init() —> doFilter() —> destroy()
public class MyFilter implements Filter {
//销毁方法,销毁时调用
public void destroy() {
}
//filter过滤器处理部分
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
chain.doFilter(req, resp);
}
//初始化方法,接收FilterConfig类型的参数,参数中包括一些Filter的配置
public void init(FilterConfig config) throws ServletException {
}
}
-
init()阶段:
public void init(FilterConfig config)
filter的创建和销毁,都由WEB服务器负责。web 应用程序启动时,web 服务器将创建filter 的实例,并调用init方法进行初始化。
注意:filter只创建一次,且在启动时创建,init()方法也执行一次 -
destroy()阶段:
public void destroy()
销毁过滤器时,只调用一次 -
doFilter()阶段:
public void doFilter(HttpServletRequest request,HttpServletResponse response, FilterChain chain)
三个参数,其中FilterChain可以理解成一个过滤器链,这个链上有很多filter。
FilterChain
对象负责调用链中的下一个过滤器或资源。FilterChain接口只有一个方法
public void doFilter(HttpServletRequest request,HttpServletResponse response),该方法作用就是传递req、resp给下一个过滤器。
配置
web.xml配置
- filter执行顺序由配置里的
<filter-mapping></filter-mapping>
的顺序决定,越靠前越先执行 - 和servlet不同的是filter的url-pattern设置要拦截的资源路径
<!-- 跨域 -->
<filter>
<filter-name>crossOriginFilter</filter-name>
<filter-class>com.bluemsun.filter.CrossOriginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossOriginFilter</filter-name>
<!-- /* 匹配服务器下所有路径资源-->
<url-pattern>/*</url-pattern>
</filter-mapping>
作用的资源路径
<!--通配符* 所有资源:作用于服务器所有路径下的资源-->
<url-pattern>/*</url-pattern>
<!--后缀名匹配:作用于服务器所有的jsp资源-->
<url-pattern>*.jsp</url-pattern>
<!--目录匹配:xxx路径下的所有资源-->
<url-pattern>/xxx/*</url-pattern>
<!--作用于xxx路径下所有的do资源-->
<url-pattern>/user/*.do</url-pattern>
<!--匹配某一具体资源-->
<url-pattern>/user/login</url-pattern>
跨域Filter
public class CrossOriginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//强制类型转换成Http
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//允许跨域的域名。单个域名、*(匹配所有域名)
//request.getHeader("Origin") 即直接获取请求头的origin的值,即请求方的域名
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
//若要使用cookie,需要设置值为true,表示允许发送cookie(可选)
response.setHeader("Access-Control-Allow-Credentials", "true");
//服务器支持的所有请求头字段
response.setHeader("Access-Control-Allow-Headers",
"Origin," +
"Access-Control-Request-Headers," +
"Access-Control-Allow-Headers," +
"Content-Type," +
"Keep-Alive," +
"User-Agent," +
"Cache-Control," +
"Cookie," +
"DNT," +
"X-Requested-With," +
"X-Mx-ReqToken," +
"X-Requested-With," +
"If-Modified-Since," +
"Accept," +
"Connection," +
"X-XSRF-TOKEN," +
"X-CSRF-TOKEN," +
"Authorization");
//(预检请求)的响应结果,规定了服务器允许客户端使用的请求方法, 如:POST, GET 和 OPTIONS
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
//设置(预检请求)的返回结果的过期时间,这里设置响应最大有效时间为 86400 秒,即24 小时
//即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息可以被缓存多久
response.setHeader("Access-Control-Max-Age", "86400");
//设置除了简单响应首部以外,需要暴露给外部的其他首部
response.setHeader("Access-Control-Expose-Headers", "Authorization");
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
登录验证Filter
public class CheckLoginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//强制类型转换成Http
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String uri = request.getRequestURI();
//静态资源,放行
if (uri.endsWith(".jsp")) {
chain.doFilter(request, response);
return;
}
//login请求直接放行,过滤除login以外的请求(这里负责login的url是 /userServlet)
if(!uri.contains("userServlet")){
//获取用户登录信息(获取session)
HttpSession session = request.getSession();
User currentUser = (User) session.getAttribute("currentUser");
//如果检查到用户没有登录,可以直接重定向到登录页面
if (currentUser == null) {
response.sendRedirect("/login.jsp");
return;
}
}
}
public void init(FilterConfig config) throws ServletException {
}
}
filter调用顺序
1. 配置位置不同,执行顺序不同:
3种情况:
- web.xml配置:filter执行顺序由配置里的
<filter-mapping></filter-mapping>
的顺序决定,mapping越靠前越先执行 - 注解配置:filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
- 两处都配置:web.xml中的filter优先执行
2. chain.doFilter(request, response)之前OR之后
-
对request进行过滤:放在chain.doFilter()之前
-
对response进行过滤:放在chain.doFilter()之后
手写一个编码EncodeFilter(展示流程)
参考博客:
Java Web之过滤器(Filter):
https://blog.csdn.net/yuzhiqiang_1993/article/details/81288912?spm=1001.2014.3001.5506