介绍
过滤器是一种对象,它对资源的请求
(servlet或静态内容)或来自资源的响应执行过滤任务
,或者两者都执行
,在一个web应用中,可以开发编写多个Filter,这些Filter组合起来组合成一个Filter链
。若是一个过滤器链,先配置先执行,执行顺序是根据类名的的排序(请求时的执行顺序),响应时以相反的顺序执行
,
过滤器在doFilter
方法中执行过滤。 每个Filter都可以访问一个FilterConfig对象,它可以从中获取它的初始化参数,以及一个对ServletContext的引用,例如,它可以使用这个引用来加载过滤任务所需的资源。
过滤器在web应用程序的部署描述符中配置。
为该设计确定的例子有:
- 身份验证过滤器
- 日志记录和审计过滤器
- 图像转换过滤器
- 数据压缩过滤器
- 加密的过滤器
- 分过滤器
- 触发资源访问事件的过滤器
- XSL / T过滤器
- mime类型过滤器链
实现
需要用到的依赖
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>9.0.58</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
Filter类
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/s01")
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter01的init方法");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter01的doFilter方法");
// 放行资源
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("Filter01的响应之后方法");
}
@Override
public void destroy() {
System.out.println("Filter01的destroy方法");
}
}
Servlet类
package servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/s01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet01的service方法");
}
}
访问后http://localhost:8080/filter/s01
打印
Filter01的doFilter方法
Servlet01的service方法
Filter01的响应之后方法
结论:
- 先执行过滤器的方法再执行servlet的方法
- 响应后会执行过滤器的filterChain.doFilter(servletRequest, servletResponse);后面的代码
- 过滤器也可以设置拦截路径,只对特殊的路径进行拦截
利用过滤器解决的实际问题
请求乱码处理
乱码情况
- post请求,所有版本的Tomcat都需要处理,处理方式为
servletRequest.setCharacterEncoding("UTF-8");
- GET请求Tomcat8及以上版本不会乱码,Tomcat7及以下版本会乱码,需要处理
代码案例
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebFilter("/")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 基于Http的
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 处理get请求且服务器版本在Tomcat8以下
String method = request.getMethod();
if ("GET".equalsIgnoreCase(method)) {
// 获取服务器版本
String webVersion = request.getServletContext().getServerInfo();
String version = webVersion.substring(webVersion.indexOf("/") + 1, webVersion.indexOf("."));
if (Integer.parseInt(version) < 8) {
// 得到自定义的内部类,(MyWapper继承了)
HttpServletRequest myRequest = new Mywapper(request);
filterChain.doFilter(myRequest, servletResponse);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
class Mywapper extends HttpServletRequestWrapper {
// 定义成员变量,提升构造器中的request对象的范围
private HttpServletRequest request;
public Mywapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (value != value && !"".equals(value.trim())) {
value = new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
}
return value;
}
}
}
非法请求拦截
就是有些需要验证通过或者任何情况下都不允许用户访问,直接设置拦截器的拦截路径即可,进入此拦截器就返回