整合 Springboot 拦截器和过滤器的使用 Springboot
1:拦截器(Interceptor)
java中的拦截器是动态拦截action调用的对象。依赖于web框架,在springmvc中依赖于SpringMVC框架,在实现上基于Java的反射机制,属于AOP的一种应用,作用类似于过滤器,但是拦截器只能对Controller请求进行拦截,对其他的直接访问静态资源的请求无法拦截处理。
拦截器可以拦截前端请求,定义拦截器需要实现 HandlerInterceptor 接口,然后根据需求重写preHandle,postHandle,afterCompletion三个方法。
/**
* 拦截器
*
* @program: myspringboot
* @author: syt
* @create: 2020-03-05 21:11
*/
@Component
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("前置拦截器****");
//返回true表示通过请求,返回false表示请求被拦截
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("后置拦截器****");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("拦截器执行完成****");
}
}
复制代码
想要让自己的拦截器生效需要进行webmvc配置,自定义一个配置类实现WebMvcConfigurer接口,然后重写addInterceptors方法添加需要拦截的路径,JDK1.8以前都是继承于WebMvcConfigurerAdapter然后重新其中的方法,但是JDK1.8支持接口默认方法,官方就定义了可以不用继承WebMvcConfigurerAdapter直接实现WebMvcConfigurer即可。
**
* 配置拦截器和过滤器
*
* @program: myspringboot
* @author: syt
* @create: 2020-03-05 21:16
*/
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
/**
* 添加拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//addPa-thPatterns 用于添加拦截规则
//excludePathPatterns 用于排除拦截
/*要执行的拦截器*/
registry.addInterceptor(myInterceptor).
addPathPatterns("/**").
excludePathPatterns("/**/login", "/**/esProductinfo/**");
}
/**
* 解决跨域问题
* 源(origin)就是协议、域名和端口号。
* URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同,
* 则表示他们同源。否则,只要协议、域名、端口有任何一个不同,就是跨域
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
.maxAge(3600);
}
}
复制代码
自定义自己的配置类也可以继承WebMvcConfigurationSupport类。这个类有许多默认的配置,但是如果继承了WebMvcConfigurationSupport这个类,SpringBoot的mvc自动装配就好失效,默认配置都需要自己定义,如静态文件地址 /**,需要重新addResourceHandlers方法添加静态文件地址
/**
* 配置拦截器和过滤器
*
* @program: myspringboot
* @author: syt
* @create: 2020-03-05 21:16
*/
@Configuration
public class MyConfig extends WebMvcConfigurationSupport {
@Autowired
private MyInterceptor myInterceptor;
/**
* 静态资源
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/META-INF/resources/static/");
}
/**
* 添加拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//addPa-thPatterns 用于添加拦截规则
//excludePathPatterns 用于排除拦截
/*要执行的拦截器*/
registry.addInterceptor(myInterceptor).
addPathPatterns("/**").
excludePathPatterns("/**/login", "/**/esProductinfo/**");
}
/**
* 解决跨域问题
* 源(origin)就是协议、域名和端口号。
* URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口全部相同,
* 则表示他们同源。否则,只要协议、域名、端口有任何一个不同,就是跨域
*
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
.maxAge(3600);
}
}
复制代码
2:过滤器(filter)
方式一
对目标资源的请求和响应进行过滤截取。在请求到达servlet之前,进行逻辑判断,判断是否放行到servlet;也可以在一个响应response到达客户端之前进行过滤,判断是否允许返回客户端。
定义过滤器需要实现Filter接口
@Slf4j
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter的init方法");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter的doFilter方法");
//这里可以加一个判断,在过滤器请求不通过时可以返回自己的信息
if (false) {
filterChain.doFilter(servletRequest, servletResponse);
return;
} else {
servletResponse.setContentType("text/html;charset=UTF-8;");
PrintWriter out = servletResponse.getWriter();
out.write("过滤器不通过");
log.info("过滤器不通过");
out.flush();
out.close();
return;
}
}
@Override
public void destroy() {
log.info("MyFilter的destroy方法");
}
}
复制代码
想要让过滤器生效需要进行配置
@Configuration
public class MyConfig{
/**
* 添加filter
*
* @return
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
//该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
registration.addInitParameter("targetFilterLifecycle", "true");
registration.setEnabled(true);
//filter的执行顺序,数字小先执行
registration.setOrder(1);
//需要拦截的url路径
registration.addUrlPatterns("/demand/*", "/notice/*", "/query/*");
return registration;
}
}
复制代码
方式二
可以直接用@WebFilter注解加@Component注解直接就可以创建过滤器了
@Slf4j
@Component
@WebFilter(filterName = "myFilter",urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter的init方法");
}
/**
* 这里是过滤请求的方法
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter的doFilter方法");
if (false) {
filterChain.doFilter(servletRequest, servletResponse);
return;
} else {
servletResponse.setContentType("text/html;charset=UTF-8;");
PrintWriter out = servletResponse.getWriter();
out.write("过滤器不通过");
log.info("过滤器不通过");
out.flush();
out.close();
return;
}
}
@Override
public void destroy() {
log.info("MyFilter的destroy方法");
}
}
复制代码
感觉拦截器和过滤器很像,都是可以拦截请求做相应的处理。接下来说下他俩的具体区别。
①:拦截器是基于java的反射机制,而过滤器基于函数回调。 ②:过滤器依赖于servlet容器,拦截器不依赖于servlet容器。 ③:拦截器只能对action请求起作用,而过滤器几乎对所有的请求都起作用。 ④:拦截器可以访问action上下文,值栈里的对象,而过滤器不能。 ⑤:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。 ⑥:拦截器可以获取IOC容器中的各个bean,而过滤器就不行,(在拦截器里注入一个service,可以调用业务逻辑)。 ⑦:过滤器是在请求进入容器后,但进入servlert前进行预处理的。响应请求也是,在servlet处理结束后,返回给客户端前触发。而拦截器提供了三个方法支持(1)preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器(如我们上一章的Controller实现); 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
作者:着迷。
链接:https://juejin.im/post/5e639f33f265da570829f63c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。