I have introduced a basic use posture of the interceptor before: [WEB series] Introduction to the use posture of the Interceptor of SpringBoot
In SpringBoot by implementing WebMvcConfigurer
of addInterceptors
time to register the interceptor method, then when we want to use interceptors in Bean, how can the whole?
<!-- more -->
I. Project construction
This project is developed with the help of SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
Open a web service for testing
<dependencies>
<!-- 邮件发送的核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
II. Interceptor
The implementation of the interceptor is relatively simple, and it is enough to implement the HandlerInterceptor
interface. For example, we implement a basic permission check interceptor, by obtaining parameters from the request header, when the conditions are met, it means passing
0. Security check interceptor
@Slf4j
public class SecurityInterceptor implements HandlerInterceptor {
/**
* 在执行具体的Controller方法之前调用
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 一个简单的安全校验,要求请求头中必须包含 req-name : yihuihui
String header = request.getHeader("req-name");
if ("yihuihui".equals(header)) {
return true;
}
log.info("请求头错误: {}", header);
return false;
}
/**
* controller执行完毕之后被调用,在 DispatcherServlet 进行视图返回渲染之前被调用,
* 所以我们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。
* <p>
* preHandler 返回false,这个也不会执行
*
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("执行完毕!");
response.setHeader("res", "postHandler");
}
/**
* 方法需要在当前对应的 Interceptor 类的 preHandle 方法返回值为 true 时才会执行。
* 顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。此方法主要用来进行资源清理。
*
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("回收");
}
}
Next is the registration of this interceptor
@RestController
@SpringBootApplication
public class Application implements WebMvcConfigurer {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/**");
}
@GetMapping(path = "show")
public String show() {
return UUID.randomUUID().toString();
}
}
The next question is, we hope that the value used for verification is placed in the configuration file, not hard-coded in the code, how can it be adjusted?
1. Specify the configuration
In the project resource file, add a request header configured to indicate verification
application.yml
security:
check: yihuihui
To read the configuration, you can use Envrioment.getProperty()
or @Value
But pay attention to the above interceptor registration, a method of direct construction, added to InterceptorRegistry
, in the interceptor, even if you add @Value
, @Autowired
annotations will not take effect (in the final analysis, this interceptor is not managed by the Spring context)
2. Interceptor injection bean
So if you want to use the bean object in the Spring container in the interceptor, how can you fix it?
2.1 New static ApplicationContext container class
A feasible method is to maintain a tool class in the project, which holds ApplicationContext
, and access the bean object through this tool class
@Component
public class SpringUtil implements ApplicationContextAware, EnvironmentAware {
private static ApplicationContext applicationContext;
private static Environment environment;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
@Override
public void setEnvironment(Environment environment) {
SpringUtil.environment = environment;
}
public static <T> T getBean(Class<T> clz) {
return applicationContext.getBean(clz);
}
public static String getProperty(String key) {
return environment.getProperty(key);
}
}
Based on this, in the interceptor, if you want to get the configuration, you can directly change it to the following
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 一个简单的安全校验,要求请求头中必须包含 req-name : yihuihui
String header = request.getHeader("req-name");
if (Objects.equals(SpringUtil.getProperty("security.check"), header)) {
return true;
}
log.info("请求头错误: {}", header);
return false;
}
To access the bean in this way, the advantage is that is more versatile and has a wide range of applications.
2.2 Register the interceptor as a bean
Although the above method is feasible, but it seems not so elegant, is there a way to directly declare the interceptor as a bean object, and then directly use the @Autowired
annotation to inject the dependent bean
Of course it is feasible. Pay attention to the several postures of bean registration. Here we use the following method to register the interceptor
@Bean
public SecurityInterceptor securityInterceptor() {
return new SecurityInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securityInterceptor()).addPathPatterns("/**");
}
The bean is declared by configuring the class above, and then where the interceptor is registered, the construction method is not used directly to create an instance; the above usage means that the bean container of spring is used to register, and the bean of the interceptor is realized in this way. statement
Therefore, other dependencies can be injected in the interceptor
The test is relatively simple, as follows
yihui@M-162D9NNES031U:SpringBlog git:(master) $ curl 'http://127.0.0.1:8080/show' -H 'req-name:yihuihui' -i
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 36
Date: Mon, 15 Nov 2021 10:56:30 GMT
6610e593-7c60-4dab-97b7-cc671c27762d%
3. Summary
Although this article introduces how to inject beans into the interceptor, the actual knowledge points are still several postures for creating bean objects; two common ways are provided above, a SpringUtil holds SpringContext, and then access with this tool class Bean object, clever use of it can save a lot of things;
The other is to declare the interceptor as a bean. The main point to note in this method is that when registering the interceptor, you cannot directly use the new
interceptor; of course, in addition to the above method, there are other cases for bean creation. Interested friends can try it
III. Source code and related knowledge points not to be missed
0. Project
Related blog posts:
Project source code:
- Engineering: https://github.com/liuyueyi/spring-boot-demo
- Source code: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/213-web-interceptor
1. WeChat public account: Yi Hui Hui Blog
It is not as good as the letter. The above content is purely a family statement. Due to limited personal ability, it is inevitable that there will be omissions and errors. If you find a bug or have a better suggestion, you are welcome to criticize and correct me. I am grateful.
The following is a gray personal blog, which records all the blog posts in study and work. Welcome everyone to visit
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。