java过滤器拦截器
本文最后更新于 2024-04-01,欢迎来到我的Blog! https://www.zpeng.site/
java过滤器拦截器
1.介绍
过滤器
过滤器是Tomcat中的组件
过滤器是过滤Servlet请求的
过滤的执行时机
1)Servlet执行之前
2)Servlet执行之后
拦截器
拦截器是SpringMVC中的组件
拦截器是拦截Controller请求的
拦截器的执行时机
1)在DispatcherServlet执行之后,Controller执行之前执行
2)在Controller执行之后,DispatcherServlet执行之前执行
3)在DispatcherServlet执行之后,视图渲染完成之后执行
2.过滤器
2.1简介
过滤器是Servlet规范中的一部分,它在Spring框架之外,由Servlet容器(如Tomcat)管理。
过滤器在请求到达Servlet之前执行,并且可以在响应返回给客户端之前执行。
过滤器通常用于执行一些跨多个请求和响应的任务,如日志记录、身份验证、编码转换等。
过滤器通过实现javax.servlet.Filter接口来定义。
2.2Filter原理
Filter(过滤器)在 Web 应用程序中具有生命周期,包括初始化和销毁两个阶段。其生命周期由 Web 容器负责管理。
初始化阶段:
当 Web 容器启动时,会检测并创建配置文件(如 web.xml)中定义的 Filter。
创建 Filter 实例,并调用 init() 方法进行初始化。
在 init() 方法中,可以进行一些一次性的初始化操作,如加载配置文件、创建资源等。
请求处理阶段:
在 Web 应用程序启动后,Filter 可以拦截、处理和修改来自客户端的请求和服务器的响应。
当有请求到达时,Web 容器会调用 Filter 的 doFilter() 方法,并传递请求和响应对象。
在 doFilter() 方法中,可以编写过滤逻辑,检查请求、修改请求或响应的内容,以及将请求传递给下一个 Filter 或目标资源。
如果存在多个 Filter,它们会按照 Filter 链的顺序依次执行。
销毁阶段:
当 Web 容器关闭或重启时,会销毁已创建的 Filter 实例。
调用 Filter 的 destroy() 方法进行销毁。
在 destroy() 方法中,可以执行一些清理操作,如释放资源、关闭连接等。
需要注意的是,在 Filter 的生命周期中,init()和destroy()方法仅在 Filter 实例创建和销毁时调用一次,而doFilter()方法每次请求被拦截时都会被调用。
可以在 Filter 的init()方法中进行一些初始化配置的操作,如读取配置文件、初始化资源等。在destroy()方法中可以释放资源,做一些清理工作。
利用 Filter 的生命周期,开发人员可以在请求处理过程中实现自定义的逻辑,并对请求和响应进行处理、修改或增强。
Filter 有如下几个方法:
void init(FilterConfig filterConfig) 用于完成过滤器的初始化。
doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) 实现过滤功能,将该方法对每个请求增加额外的处理。
void destroy() 用于过滤器销毁前,完成某些资源的回收。
2.3使用
测试用controller
package com.example.useragent.demos.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BasicController {
// http://127.0.0.1:8080/hello?name=lisi
@RequestMapping("/hello")
@ResponseBody
public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
System.out.println("BasicController.hello");
System.out.println("BasicController.hello");
System.out.println("BasicController.hello");
System.out.println("BasicController.hello");
return "Hello " + name;
}
}
FirstFilter
package com.example.useragent.demos.web.filter;
import javax.servlet.*;
import java.io.IOException;
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
System.out.println("FirstFilter 初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("------对 First request 进行过滤 --------");
//下面这行代码就是放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("------对 First response 进行过滤 --------");
}
@Override
public void destroy() {
Filter.super.destroy();
System.out.println("firstFilter 已销毁");
}
}
SecondFilter
package com.example.useragent.demos.web.filter;
import javax.servlet.*;
import java.io.IOException;
//@WebFilter(urlPatterns="/*")
public class SecondFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Second Filter 初始化完成");
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("------对 Second request 进行过滤 --------");
//下面这行代码就是放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("------对 Second response 进行过滤 --------");
}
@Override
public void destroy() {
System.out.println("Second Filter 已销毁");
Filter.super.destroy();
}
}
WebConfig 配置文件方式
也可用@WebFilter注解方式
package com.example.useragent.demos.web.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean firstFilterRegistrationBean() {
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
// 对哪些路径进行过滤
filterFilterRegistrationBean.addUrlPatterns("/*");
filterFilterRegistrationBean.setOrder(1); // 设置优先级 ,数字越小,优先级越高
FirstFilter filter = new FirstFilter(); // 绑定过滤器
filterFilterRegistrationBean.setFilter(filter);
return filterFilterRegistrationBean;
}
@Bean
public FilterRegistrationBean secondFilterRegistrationBean() {
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.addUrlPatterns("/hello");
filterFilterRegistrationBean.setOrder(2); // 设置优先级
// 绑定过滤器
SecondFilter filter = new SecondFilter();
filterFilterRegistrationBean.setFilter(filter);
return filterFilterRegistrationBean;
}
}
在每个过滤器的doFilter()方法中,可以调用 FilterChain 的doFilter()方法来传递请求和响应给下一个过滤器,或者传递给目标资源。如果没有调用doFilter()方法,过滤器链将会被中断,请求将不会继续传递。
2.4测试
http://127.0.0.1:8080/hello?name=zpeng
2.5执行顺序
我们可以看见 FirstFilter 先进行过滤,然后交给 SecondFilter ,然后访问资源,然后 SecondFilter 对响应进行过滤,然后 FirstFilter 对响应进行过滤。图示如下:
3.拦截器
3.1简介
拦截器是Spring框架的一部分,它依赖于Spring的AOP模块。
拦截器在Spring的DispatcherServlet中工作,用于拦截请求并在控制器之前或之后执行。
拦截器通常用于记录日志、执行安全检查、数据绑定等操作。
拦截器通过实现
org.springframework.web.servlet.HandlerInterceptor
接口或扩展org.springframework.web.servlet.handler.HandlerInterceptorAdapter
类来定义。
它依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上,基于Java的反射机制,属于面向切面编程(AOP)的一种运用,就是在service或者一个方法前,调用一个方法,或者在方法后,调用一个方法,比如动态代理就是拦截器的简单实现,在调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在调用方法后打印出字符串,甚至在抛出异常的时候做业务逻辑的操作。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。
3.2Interceptor 原理
preHandle()
这个方法在Controller方法执行之前执行,在该方法中可以做一些权限校验的操作。如果希望该拦截器对请求进行拦截后,还要调用其他的拦截器或者控制器去处理业务,则返回true;如果希望该拦截器拦截请求后,不需要再调用其他拦截器或控制器去处理业务,则返回false。
postHandle()
这个方法在 Controller 方法执行之后,渲染视图之前执行,可以对Controller方法的返回值进行处理。
afterCompletion()
这个方法在 Controller方法执行之后,视图渲染完毕之后执行,也即DispatcherServlet完全处理完请求之后执行,可以做一些资源清理的操作。
服务器接收到浏览器发出的请求
执行拦截器的preHandle()方法
执行Controller处理请求
执行拦截器的postHandle()方法
DispatcherServlet渲染视图
执行拦截器的afterCompletion()方法
3.3使用
FirstInterceptor
package com.example.useragent.demos.web.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Service
public class FirstInterceptor implements HandlerInterceptor {
/**
* 该方法在DispatcherServlet执行之后,Controller执行之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("First Interceptor --> preHandler()!");
// 如果返回false,则停止流程,api不会被调用
return true;
}
/**
* 该方法在Controller执行之后,DispatcherServlet执行之前执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("First Interceptor --> postHandle()!");
}
/**
* 该方法在DispatcherServlet渲染视图之后,执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("First Interceptor --> afterCompletion()!");
}
}
SecondInterceptor
package com.example.useragent.demos.web.interceptor;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Service
public class SecondInterceptor implements HandlerInterceptor {
/**
* 该方法在DispatcherServlet执行之后,Controller执行之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Second Interceptor --> preHandler()!");
// 如果返回false,则停止流程,api不会被调用
return true;
}
/**
* 该方法在Controller执行之后,DispatcherServlet执行之前执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("Second Interceptor --> postHandle()!");
}
/**
* 该方法在DispatcherServlet渲染视图之后,执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("Second Interceptor --> afterCompletion()!");
}
}
InterceptorConfig
package com.example.useragent.demos.web.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private FirstInterceptor firstInterceptor;
@Autowired
private SecondInterceptor secondInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器
registry.addInterceptor(firstInterceptor)
.addPathPatterns("/**"); // 拦截所有请求路径
registry.addInterceptor(secondInterceptor)
.addPathPatterns("/**"); // 拦截所有请求路径
//.excludePathPatterns("/login", "/error"); // 排除某些路径
}
}
3.4测试
http://127.0.0.1:8080/hello?name=zpeng
3.5执行顺序
First Interceptor --> preHandler()!
Second Interceptor --> preHandler()!
BasicController.hello
BasicController.hello
BasicController.hello
BasicController.hello
Second Interceptor --> postHandle()!
First Interceptor --> postHandle()!
Second Interceptor --> afterCompletion()!
First Interceptor --> afterCompletion()!
服务器接收到浏览器发出的请求
执行第一个拦截器的preHandle()方法
执行第二个拦截器的preHandle()方法
调用Controller处理请求
执行第二个拦截器的postHandle()方法
执行第一个拦截器的postHandle()方法
DispatcherServlet渲染视图
执行第二个拦截器的afterCompletion()方法
执行第一个拦截器的afterCompletion()方法
当第一个拦截器的preHandle()方法返回false时,不会继续执行,请求结束。
当第一个拦截器的preHandle()方法返回true,第二个拦截器的preHandle()方法返回false时,会执行第一个拦截器和第二个拦截器的preHandle(),以及第一个拦截器的afterCompletion()方法,之后请求结束。
当前拦截器的preHandle()方法返回false,会执行之前拦截器的preHandle()、当前拦截器的preHandle(),以及之前拦截器的afterCompletion()。
4.过滤器拦截器一起
4.1介绍
拦截器:对请求在handler【Controller】前后进行处理,属于应用上下文。
过滤器:对请求在进入后Servlet之前或之后进行处理,允许交换请求和响应对象。
拦截器和过滤器执行顺序:
1、Filter.init();
2、Filter.doFilter(); before doFilter
3、HandlerInterceptor.preHandle();
4、Controller方法执行
5、HandlerInterceptor.postHandle();
6、DispatcherServlet视图渲染
7、HandlerInterceptor.afterCompletion();
8、Filter.doFilter(); after doFilter
9、Filter.destroy();
4.2测试
都打开看结果
- 感谢你赐予我前进的力量