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:

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

一灰灰blog


小灰灰Blog
251 声望46 粉丝