Spring Boot自定义拦截器配置

Spring Boot自定义拦截器与传统配置相差无异,依然是实现拦截器接口,使用注解将拦截器注册到Spring容器中。

拦截器

DispatcherServlet在调用Controller之前,会先调用拦截器的preHandle方法,并在Controller返回后调用postHandle方法和afterCompletion方法。

拦截器接口

org.springframework.web.servlet.HandlerInterceptor

Spring Boot中自定义拦截器需实现拦截器接口。

preHandle(..) - 前置处理。

postHandle(..) - 后置处理,位于视图渲染之前,可以向ModelAndView中添加数据。

afterCompletion(..) - 前置条件返回false,或拦截处理完成时调用。可获取响应数据及异常信息。

DispatcherServlet负责将拦截器应用到所有@Controller注解的类上。

Spring Boot拦截器配置

新建一个配置类(若没有),将实现了拦截器接口的实例,注册到Spring容器中,如下所示:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }
}

或者使用XML的声明方式:

<mvc:interceptors>
  <bean id="loggerInterceptor" class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptors>

ResponseBodyAdvice

Spring MVC中的拦截器会拦截所有@Controller注解的类,但对@ResponseBody和ResponseEntity后置处理无能为力。

若被拦截的方法使用了@ResponseBody注解,或返回值是ResponseEntity类型,拦截器中的后置处理可能会失效。

此时,需使用ResponseBodyAdvice接口,在beforeBodyWrite中进行后置处理。

org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<T>

实现如上接口,用注解将拦截器应用到指定的Controller上。

//针对@RestController注解
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}

//针对packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

//针对具体类
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}

默认@ControllerAdvice会作用到所有标有@Controller注解的类上。

可将以上类声明为Spring bean,或包含在自动扫描的类路径中。

异常处理

对于异常的处理,@ExceptionHandler将在具有匹配异常处理方法的advice中选择第一个。

 @RestControllerAdvice
 public class WebRestControllerAdvice {
   
  @ExceptionHandler(CustomNotFoundException.class)
  public ResponseMsg handleNotFoundException(CustomNotFoundException ex) {
   ResponseMsg responseMsg = new ResponseMsg(ex.getMessage());
   return responseMsg;
  }
 }