过滤器
过滤器可以看作是一个对service资源的中控,客户端在请求已配置过滤器的资源时首先要通过filter的审视/处理,然后才能够请求到对应的service资源,service在响应时,同样的要经过filter才能响应给客户端
概述
Filter,是作用目标资源的请求进行过滤的一套技术规范
- Filter接口定义了过滤器的开发规范,所有的过滤器都要实现该接口
- Filter的工作位置是项目中所有目标资源之前,容器再创建HttpServletRequest和HttpServletResponse对象后,会先调用Filter的doFilter方法
- Filter的doFilter方法可以控制请求是否继续,如果放行,则请求继续,如果拒绝,则请求到此为止,由过滤器本身做出响应
- Filter不仅可以对请求做出过滤,也可以再目标资源做出响应之前,对响应再次进行处理
- Filter是GOF中责任链模式的经典案例
- Filter的常用应用包括但不限于:登录权限检查,解决网站乱码,过滤敏感字符,日志记录,性能分析
- Filter
以打印日志为例实现过滤器
/**
* 1.实现Filter接口
* 2.重写过滤方法
* 3.配置过滤器
* web.xml
* 注解
*/
@WebServlet("/servleta")
public class LogginFilter implements Filter{
//指定日期格式
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/*
过滤请求的和响应的方法
1.请求到达目标资源之前,先经过该方法
2.该方法有能力控制请求是否继续向后到达目标资源,可以再该方法内直接向客户端做响应处理
3.请求到达目标资源后,响应之前,还会经过该方法
*/
@Override
public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws Exception{
/*
1.请求到达目标资源之前的功能代码
判断是否登录
校验权限是否满足
2.放行代码
3.响应之前HttpServletResponse转换为响应报文之前的功能代码
*/
//参数父转子
HttpServletRequest request = (HttpServletRequest)servletRequest
HttpServletResponse response = (HttpServletResponse)servletResponse
//请求到达目标资源之前 打印日志
String requestURI = request.getRequestURI();//获取URI
String dateTime = dateFormat.format(new Date());//获取当前系统时间
String beforeLogging = requestURI +"在"+dateTime+"被访问了"
System.out.println(beforeLoggin);
//获取请求达到目标之前系统时间
long t1 = System.currentTimeMillis();
//放行代码
filterChain.doFilter(req,res);
//获取请求达到目标之后,响应之前时间
long t2 = System.currentTimeMillis();
//响应之前的功能代码
String afterLoggin = requestURI + "资源在"+dateTime+"的请求耗时"+(t2-t1)+"毫秒";
System.out.println(afterLoggin);
}
}
<filter>
<filter-name>logginFilter</filter-name>
<filter-class>com.aili.LogginFilter</filter-class>
</filter>
<!--配置过滤器的过滤资源规则,路径-->
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<!--
url-pattern 根据请求的资源路径,对指定的请求进行过滤
/* 过滤全部资源
/a/* 过滤以a开头的资源
*.html 过滤以html为后缀的资源
/servlet1 对servlet1请求进行过滤
servlet-name 根据请求的servlet的别名,对指定的servlet资源进行过滤
一个filter-mapping中可以同时存在多个url-pattern和servlet-name
-->
<url-pattern>/*</url-pattern>
<!--也可以使用servlet别名来配置-->
<servlet-name>servleta</servlet-name>
</filter-mapping>
过滤器的生命周期
- 初始化阶段(Initialization):
当容器启动或者第一次请求到达过滤器时,会调用过滤器的 init() 方法进行初始化。
init() 方法只会在过滤器被创建时调用一次,用于进行一些初始化工作,比如读取配置文件等。 - 请求处理阶段(Request Processing):
每当有请求到达过滤器时,容器会调用过滤器的 doFilter() 方法来处理请求。
doFilter() 方法会在请求到达 Servlet 之前被调用,可以在这里对请求进行处理,比如修改请求参数、验证用户身份等。 - 销毁阶段(Destruction):
当容器关闭或者过滤器需要被移除时,会调用过滤器的 destroy() 方法进行清理工作。
destroy() 方法只会在过滤器被销毁时调用一次,用于释放资源,比如关闭数据库连接等。
过滤器的生命周期由容器管理,过滤器的生命周期与 Servlet 的生命周期有些类似,过滤器类是通过容器来实例化和管理的
过滤器链
一个web项目中,可以同时定义多个过滤器,多个过滤器对同一个资源进行过滤工作时,工作位置有先有后,整体形成一个工作链,称之为过滤器链
- 过滤器链中的过滤器的顺序由filter-mapping顺序决定
- 每个过滤器过滤的范围不同,针对同一个资源来说,过滤器链中的过滤器个数可能是不同的
- 如果某个Filter是使用ServletName进行匹配规则的设置,那么这个Filter执行的优先级要更低
Java Web过滤器链的一般工作流程:
客户端发送请求到服务器。
请求首先被第一个过滤器拦截。
第一个过滤器可以对请求进行处理,然后决定是否将请求传递给下一个过滤器。
如果第一个过滤器决定将请求传递下一个过滤器,则请求会继续经过下一个过滤器。
这个过程会一直持续,直到请求到达目标资源(Servlet或JSP)。
目标资源处理完请求后,响应会按相反的顺序经过过滤器链返回给客户端。
过滤器链的顺序由在web.xml文件中配置的<filter-mapping>
元素的顺序决定。
实例
public class Filter1 implements Filter {
public void init(FilterConfig config) throws ServletException {
// Initialization code
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Pre-processing code
// Pass the request along the filter chain
chain.doFilter(request, response);
// Post-processing code
}
public void destroy() {
// Cleanup code
}
}
public class Filter2 implements Filter {
// Similar structure as Filter1
}
// In web.xml
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.example.Filter1</filter-class>
</filter>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.example.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器注解
//定义了一个拦截所有路径,并且定义了一个名为paramName,值为paramValue的初始化参数
//在过滤器初始化时,可以通过FilterConfig对象获取这个初始化参数的值
//如果需要指定过滤器链的执行顺序,可以使用@WebFilter注解的filterName属性来控制过滤器的执行顺序。过滤器链的执行顺序是根据过滤器的名称(filterName)的字母顺序来确定的,按照字母顺序先后执行。
//也可以利用过滤器类名来确定过滤器执行顺序
@WebFilter(
filterName="loggingFilter",
urlPatterns = { "/*" },
initParams = {@WebInitParam(name = "paramName", value = "paramValue") }
servletNames = {"servletBName"}
)
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化操作
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 过滤逻辑
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 销毁操作
}
}