拦截器常见应用场景
日志记录:
记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
性能监控:
有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
通用行为:
读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
OpenSessionInView:
如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。
自定义拦截器
(1)Pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!-- springboot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependencies>
(2)自定义一个拦截器,有两种创建方式,我们用这两种方式分别建一个拦截器,如下
实现HandlerInterceptor 拦截器接口
package com.zx.demo.Interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
@Component
public class Interceptor1 implements HandlerInterceptor {
private Logger log = LoggerFactory.getLogger(this.getClass());
//前置处理:controller处理前调用,可以做一些参数预处理、登录校验等,true继续执行,false不再做下面的任何处理了
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("Interceptor1前置处理-----------------------");
return true;
}
//后置处理:controller执行后,视图渲染前
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("Interceptor1后置处理-----------------------");
}
//末置处理: controller执行完,视图也渲染完成,整个请求结束返回前,可以做:资源的清空、整个请求处理时长等
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("Interceptor1末置处理-----------------------");
}
}
继承HandlerInterceptorAdapter适配器类
package com.zx.demo.Interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class Interceptor2 extends HandlerInterceptorAdapter {
private Logger log = LoggerFactory.getLogger(this.getClass());
//前置处理:controller处理前调用,可以做一些参数预处理、登录校验等,true继续执行,false不再做下面的任何处理了
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("Interceptor2前置处理-----------------------");
return true;
}
//后置处理:controller执行后,视图渲染前
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("Interceptor2后置处理-----------------------");
}
//末置处理: controller执行完,视图也渲染完成,整个请求结束返回前,可以做:资源的清空、整个请求处理时长等
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("Interceptor2末置处理-----------------------");
}
}
(3)注册拦截器
package com.zx.demo.config;
import com.zx.demo.Interceptor.Interceptor1;
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.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfigurer implements WebMvcConfigurer{
@Autowired
private Interceptor1 interceptor1;
// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor1);
}
}
(4)编写测试Controller
package com.zx.demo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
Logger log = LoggerFactory.getLogger(HelloController.class);
@RequestMapping("/sayHello")
public String sayHello(){
log.info("sayHello接口调用---------------");
return "hello test!";
}
}
(5)启动类
package com.zx.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DemoApplication.class);
}
}
右键启动类启动项目后,浏览器访问localhost:9090/sayHello接口,控制台输出效果:
可以清晰的看到拦截器中配置的三个方法以及我们的接口处理顺序: 前置拦截器 ---> 业务处理 ---> 后置拦截器 --->末置拦截器
因为我在webConfigure中只注入了拦截器1,所以只打印了拦截器1的数据。我们把拦截器2也注入进去,修改(3)步骤
package com.zx.demo.config;
import com.zx.demo.Interceptor.Interceptor1;
import com.zx.demo.Interceptor.Interceptor2;
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.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfigurer implements WebMvcConfigurer{
@Autowired
private Interceptor1 interceptor1;
@Autowired
private Interceptor2 interceptor2;
// 这个方法是用来配置静态资源的,比如html,js,css,等等
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor1);
registry.addInterceptor(interceptor2);
}
}
运行结果:
拦截器拦截处理执行顺序是: 前置--- > 业务处理 ----> 后置 ---> 末置
多个拦截器执行顺序,根据addInterceptor注入的先后顺序,针对每一步的多个拦截操作执行顺序是先进后出原则