优雅处理 HTTP 请求:过滤器拦截器、ControllerAdvice 和自定义 AOP
我们在开发 Spring Boot 应用程序时,经常会遇到需要对 HTTP 请求进行一些处理的情况,例如鉴权、数据校验、请求日志记录等等。在处理 HTTP 请求时,我们可以使用四种不同的技术来实现这些功能:过滤器、拦截器、ControllerAdvice 和自定义 AOP。
在本文中,我们将分别介绍这四种技术的概念、用法和区别,并举例说明如何在 Spring Boot 应用程序中使用它们来实现对 HTTP 请求的统一处理。
基本概念及拦截执行顺序
过滤器(Filter):过滤器是 Java Web 中的一种技术,它在请求到达 Servlet 之前或之后进行处理。因此,过滤器是最先执行的拦截器。在过滤器中可以进行一些通用的业务处理,例如鉴权、数据校验、请求日志记录等等。Spring Boot 应用程序中注册的过滤器按照注册的顺序依次执行。
拦截器(Interceptor):拦截器是 Spring MVC 框架提供的一种技术,它在请求到达 Controller 之前或之后进行处理。因此,拦截器在过滤器之后执行,但在请求到达 Controller 之前。在拦截器中可以进行请求的修改或者一些通用的业务逻辑处理。Spring Boot 应用程序中注册的拦截器按照注册的顺序依次执行。
ControllerAdvice:ControllerAdvice 是 Spring MVC 提供的一个注解,用于定义一个全局的异常处理器、数据绑定器和模型处理器。它可以被用于处理所有的 Controller 中抛出的异常和响应,对于多个 Controller 中重复的异常处理可以进行统一管理。ControllerAdvice 在请求到达 Controller 之后执行,可以对 Controller 返回的数据进行统一处理,例如添加通用的响应头、设置统一的返回值格式等等。
自定义 AOP(Aspect-Oriented Programming):自定义 AOP 是一种编程范式,它可以用于在方法调用前、后或抛出异常时添加一些横切逻辑。在 Spring Boot 应用程序中,自定义 AOP 切面可以用于对 HTTP 请求进行统一处理,例如获取和解析请求头信息、请求日志记录、鉴权等等。自定义 AOP 切面的执行顺序在拦截器之后,在请求到达 Controller 之前执行。
总的来说,四种拦截方式的执行顺序是过滤器->拦截器->ControllerAdvice->自定义 AOP。
但是需要注意的是,这并不是绝对的顺序,具体的执行顺序还会受到过滤器链、拦截器链、AOP 切入位置等因素的影响,例如
如果在过滤器或拦截器中调用了 chain.doFilter(request, response)或 handlerInterceptor.preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)方法,则会依次调用过滤器链和拦截器链的下一个过滤器或拦截器。
自定义 AOP 的执行顺序在 ControllerAdvice 之后,是因为一般情况下我们会将切入点选在 Controller 的方法上
四种拦截方法的使用 case
过滤器
在 Spring Boot 项目中,可以使用过滤器(Filter)来统一处理 HTTP 请求,并获取和解析请求头中的内容。过滤器可以在请求到达 Servlet 之前或之后进行一些处理操作。
以下例子展示如何在 Spring Boot 项目中实现一个过滤器来获取和解析请求头中的内容:
创建一个过滤器类,实现 Filter 接口。在该过滤器类中,可以重写 doFilter 方法,在该方法中获取并解析请求头信息。
在 Spring Boot 应用程序中注册该过滤器类。可以通过创建一个配置类并继承 WebMvcConfigurerAdapter 类,然后重写 addFilters 方法来注册过滤器。
这样,当请求到达时,就会先进入过滤器的 doFilter 方法进行处理,并获取和解析请求头信息。过滤器可以处理任何类型的请求,而不仅仅是 Web 请求,因此需要在过滤器中进行类型判断。
拦截器
在 Spring Boot 项目中,可以使用拦截器(Interceptor)来对 HTTP 请求进行统一转换和处理请求头信息。拦截器可以在请求处理前和处理后进行一些处理操作。
以下例子展示如何在 Spring Boot 项目中实现一个拦截器来获取和解析请求头中的信息:
创建一个拦截器类,实现 HandlerInterceptor 接口。在该拦截器类中,可以重写 preHandle 方法,在该方法中获取并解析请求头信息。
在 Spring Boot 应用程序中注册该拦截器类。可以通过创建一个配置类并继承 WebMvcConfigurerAdapter 类,然后重写 addInterceptors 方法来注册拦截器。
这样,当请求到达时,就会先进入拦截器的 preHandle 方法进行处理,并获取和解析请求头信息。注意,拦截器只能处理 @Controller 注解或 @RequestMapping 注解的处理器方法,并且只对 Web 请求有效,对于非 Web 请求(如静态资源)不会进行拦截。
除 preHandle(目标方法执行前执行), HandlerInterceptor 还有两外两个方法:
postHandle 目标方法执行后执行
afterCompletion 请求完成时执行
ControllerAdvice
@ControllerAdvice 是 Spring MVC 提供的一个注解,用于定义一个全局的异常处理器、数据绑定器和模型处理器。它可以被用于处理所有的 Controller 中抛出的异常和响应,对于多个 Controller 中重复的异常处理可以进行统一管理。
@ControllerAdvice 注解对于应用程序中所有的 @Controller 注解的类中的方法进行全局处理,可以捕获 Controller 中的异常并返回相应的响应信息,也可以在 Controller 中返回数据之前对数据进行统一处理。
@ControllerAdvice 注解所标注的类中,可以定义多个方法,每个方法可以处理不同的异常或返回不同类型的数据。在方法上可以使用 @ExceptionHandler、@InitBinder 或 @ModelAttribute 注解来指定要处理的异常类型、数据绑定规则和模型处理规则。
下面是一个 @ControllerAdvice 注解的示例:
上面的代码定义了一个全局异常处理器,用于处理所有 Controller 中抛出的 Exception 异常,如果出现异常则返回一个 HTTP 500 错误响应,并将异常信息作为响应体返回。
另外,@ControllerAdvice 注解中还可以添加 basePackages 属性或 value 属性来指定需要处理的 Controller 所在的包路径或类。例如:
这样就只会处理 com.example.controller 包下的 Controller 中抛出的异常。
总之,@ControllerAdvice 是一个很有用的注解,可以让我们在应用程序中统一处理异常和响应,避免重复的代码,提高代码的可维护性和可读性。
自定义 AOP
在 Spring Boot 项目中,可以使用自定义 AOP 的方式来统一处理 HTTP 请求,并获取和解析请求头中的内容。通过自定义 AOP 切面,可以在请求处理前和处理后添加相应的切面逻辑。
以下例子展示如何在 Spring Boot 项目中实现自定义 AOP 切面来获取和解析请求头中的内容:
创建一个注解,用于标注需要进行切面处理的方法。在该注解中添加一个 String 类型的属性,用于指定需要获取的请求头信息。
创建一个切面类,实现 Aspect 接口,并在该类中定义一个切点方法和一个通知方法。在切点方法中,使用 @Pointcut 注解来指定需要进行切面处理的方法;在通知方法中,通过 JoinPoint 参数获取请求对象,并从请求对象中获取并解析请求头信息。
在需要进行切面处理的方法上添加自定义注解,并指定需要获取的请求头信息。
这样,在请求到达需要进行切面处理的方法时,就会先进入自定义 AOP 切面的通知方法进行处理,并获取和解析请求头信息。注意,自定义 AOP 切面可以处理任何类型的方法,而不仅仅是 @Controller 注解或 @RequestMapping 注解的处理器方法,它也可以处理非 Web 请求(如异步方法或定时任务等)。
评论