优雅处理HTTP请求:过滤器、拦截器、ControllerAdvice和自定义AOP

news/2024/12/29 15:08:24/

我们在开发Spring Boot应用程序时,经常会遇到需要对HTTP请求进行一些处理的情况,例如鉴权、数据校验、请求日志记录等等。在处理HTTP请求时,我们可以使用四种不同的技术来实现这些功能:过滤器、拦截器、ControllerAdvice和自定义AOP。

在本文中,我们将分别介绍这四种技术的概念、用法和区别,并举例说明如何在Spring Boot应用程序中使用它们来实现对HTTP请求的统一处理。

基本概念及拦截执行顺序

  1. 过滤器(Filter):过滤器是Java Web中的一种技术,它在请求到达Servlet之前或之后进行处理。因此,过滤器是最先执行的拦截器。在过滤器中可以进行一些通用的业务处理,例如鉴权、数据校验、请求日志记录等等。Spring Boot应用程序中注册的过滤器按照注册的顺序依次执行。
  2. 拦截器(Interceptor):拦截器是Spring MVC框架提供的一种技术,它在请求到达Controller之前或之后进行处理。因此,拦截器在过滤器之后执行,但在请求到达Controller之前。在拦截器中可以进行请求的修改或者一些通用的业务逻辑处理。Spring Boot应用程序中注册的拦截器按照注册的顺序依次执行。
  3. ControllerAdvice:ControllerAdvice是Spring MVC提供的一个注解,用于定义一个全局的异常处理器、数据绑定器和模型处理器。它可以被用于处理所有的Controller中抛出的异常和响应,对于多个Controller中重复的异常处理可以进行统一管理。ControllerAdvice在请求到达Controller之后执行,可以对Controller返回的数据进行统一处理,例如添加通用的响应头、设置统一的返回值格式等等。
  4. 自定义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项目中实现一个过滤器来获取和解析请求头中的内容:

  1. 创建一个过滤器类,实现Filter接口。在该过滤器类中,可以重写doFilter方法,在该方法中获取并解析请求头信息。
 

Java

复制代码

public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 获取请求头信息 String headerInfo = httpRequest.getHeader("Header-Info"); // 解析请求头信息 // ... chain.doFilter(request, response); // 继续执行请求处理 } // 可以重写init和destroy方法进行初始化和销毁操作 }

  1. 在Spring Boot应用程序中注册该过滤器类。可以通过创建一个配置类并继承WebMvcConfigurerAdapter类,然后重写addFilters方法来注册过滤器。
 

Java

复制代码

public class MyFilterConfig extends WebMvcConfigurerAdapter { @Bean public FilterRegistrationBean<MyFilter> myFilter() { FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new MyFilter()); registrationBean.addUrlPatterns("/*"); // 指定过滤的URL return registrationBean; } }

这样,当请求到达时,就会先进入过滤器的doFilter方法进行处理,并获取和解析请求头信息。过滤器可以处理任何类型的请求,而不仅仅是Web请求,因此需要在过滤器中进行类型判断。

拦截器

在Spring Boot项目中,可以使用拦截器(Interceptor)来对HTTP请求进行统一转换和处理请求头信息。拦截器可以在请求处理前和处理后进行一些处理操作。

以下例子展示如何在Spring Boot项目中实现一个拦截器来获取和解析请求头中的信息:

创建一个拦截器类,实现HandlerInterceptor接口。在该拦截器类中,可以重写preHandle方法,在该方法中获取并解析请求头信息。

 

Java

复制代码

public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取请求头信息 String headerInfo = request.getHeader("Header-Info"); // 解析请求头信息 // ... return true; // 返回true继续执行请求处理,返回false则不执行请求处理 } // 可以重写 afterCompletion 和 postHandle 方法进行请求处理后的操作 }

在Spring Boot应用程序中注册该拦截器类。可以通过创建一个配置类并继承WebMvcConfigurerAdapter类,然后重写addInterceptors方法来注册拦截器。

 

Java

复制代码

@Configuration public class MyInterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()); } }

这样,当请求到达时,就会先进入拦截器的preHandle方法进行处理,并获取和解析请求头信息。注意,拦截器只能处理@Controller注解或@RequestMapping注解的处理器方法,并且只对Web请求有效,对于非Web请求(如静态资源)不会进行拦截。

除preHandle(目标方法执行前执行), HandlerInterceptor还有两外两个方法:

  • postHandle 目标方法执行后执行
  • afterCompletion 请求完成时执行

ControllerAdvice

  • @ControllerAdvice是Spring MVC提供的一个注解,用于定义一个全局的异常处理器、数据绑定器和模型处理器。它可以被用于处理所有的Controller中抛出的异常和响应,对于多个Controller中重复的异常处理可以进行统一管理。
  • @ControllerAdvice注解对于应用程序中所有的@Controller注解的类中的方法进行全局处理,可以捕获Controller中的异常并返回相应的响应信息,也可以在Controller中返回数据之前对数据进行统一处理。
  • @ControllerAdvice注解所标注的类中,可以定义多个方法,每个方法可以处理不同的异常或返回不同类型的数据。在方法上可以使用@ExceptionHandler、@InitBinder或@ModelAttribute注解来指定要处理的异常类型、数据绑定规则和模型处理规则。

下面是一个@ControllerAdvice注解的示例:

 

Java

复制代码

@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public ResponseEntity<String> handleException(Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } }

上面的代码定义了一个全局异常处理器,用于处理所有Controller中抛出的Exception异常,如果出现异常则返回一个HTTP 500错误响应,并将异常信息作为响应体返回。

另外,@ControllerAdvice注解中还可以添加basePackages属性或value属性来指定需要处理的Controller所在的包路径或类。例如:

 

Java

复制代码

@ControllerAdvice(basePackages = "com.example.controller") public class GlobalExceptionHandler { // ... }

这样就只会处理com.example.controller包下的Controller中抛出的异常。

总之,@ControllerAdvice是一个很有用的注解,可以让我们在应用程序中统一处理异常和响应,避免重复的代码,提高代码的可维护性和可读性。

自定义AOP

在Spring Boot项目中,可以使用自定义AOP的方式来统一处理HTTP请求,并获取和解析请求头中的内容。通过自定义AOP切面,可以在请求处理前和处理后添加相应的切面逻辑。

以下例子展示如何在Spring Boot项目中实现自定义AOP切面来获取和解析请求头中的内容:

创建一个注解,用于标注需要进行切面处理的方法。在该注解中添加一个String类型的属性,用于指定需要获取的请求头信息。

 

Java

复制代码

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value(); }

创建一个切面类,实现Aspect接口,并在该类中定义一个切点方法和一个通知方法。在切点方法中,使用@Pointcut注解来指定需要进行切面处理的方法;在通知方法中,通过JoinPoint参数获取请求对象,并从请求对象中获取并解析请求头信息。

 

Java

复制代码

@Aspect @Component public class MyAspect { @Pointcut("@annotation(com.example.demo.MyAnnotation)") public void myPointcut() {} @Around("myPointcut()") public Object myAdvice(ProceedingJoinPoint joinPoint) throws Throwable { // 获取请求对象 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取注解中指定的请求头信息 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); MyAnnotation annotation = methodSignature.getMethod().getAnnotation(MyAnnotation.class); String headerInfo = request.getHeader(annotation.value()); // 解析请求头信息 // ... // 继续执行请求处理 Object result = joinPoint.proceed(); // 处理请求处理结果 // ... return result; } }

在需要进行切面处理的方法上添加自定义注解,并指定需要获取的请求头信息。

 

Java

复制代码

@RestController public class MyController { @MyAnnotation("Header-Info") @GetMapping("/hello") public String hello() { return "Hello World!"; } }

这样,在请求到达需要进行切面处理的方法时,就会先进入自定义AOP切面的通知方法进行处理,并获取和解析请求头信息。注意,自定义AOP切面可以处理任何类型的方法,而不仅仅是@Controller注解或@RequestMapping注解的处理器方法,它也可以处理非Web请求(如异步方法或定时任务等)。


http://www.ppmy.cn/news/91357.html

相关文章

使用Makefile笔记总结

文章目录 一、简单了解Makefile1.1 Makefile示例1.2 基本规则1.3 make是如何工作的1.4 使用变量1.5 make自动推导 二、变量2.1 变量的定义和引用2.2 变量的两种高级用法2.3 override 和 define 关键字2.4 环境变量与目标变量2.5 自动变量 三、Makefile规则3.1 通配符3.2 目标依…

电脑不小心点了网络重置之后连不上任何网包括热点的解决方法

直接参考这个博客&#xff1a; 先用别人的电脑下一个ccleaner到U盘上&#xff0c;然后插到自己电脑上安装&#xff0c;然后安装下面这个博客一波操作&#xff0c;最后重启即可。 笔记本不小心网络重置后&#xff0c;不能上网&#xff0c;网络适配器存在感叹号_吉星J_x的博客-…

数据结构与算法—排序算法篇

目录 1、选择排序 1.1、算法思想 1.2、步骤 1.3、算法实现 1.4、算法分析 2、 冒泡排序 2.1、算法思想 2.2、算法实现 2.3、算法分析 2.4、改进冒泡排序 3、插入排序 3.1、算法思想 3.2、算法实现 3.3、算法分析 4、希尔排序 4.1、算法思想 4.2、增长量选定规…

centos8 安装mysql8

1、下载mysql8软件库 wget https://repo.mysql.com//mysql80-community-release-el8-3.noarch.rpm 2、安装软件库 rpm -ivh mysql80-community-release-el8-3.noarch.rpm 3、安装mysql yum install mysql-server 4、启动mysql systemctl start mysqld systemctl enable…

基于TCP、UDP网络编程

文章目录 网络协议分层套接字UDP和TCP差异UDP的APIDatagramSocketDatagramPacket 基于UDP Socket 实现一个回显程序TCP的APISocket的API基于TCP实现回显程序 网络协议分层 应用层&#xff1a; 应用程序拿到数据怎么用传输层&#xff1a; 负责关注传输过程中起点和终点网络层 &…

如何处理SAP错误:不可能为条目1000 UMB 1000 MR1 2004确立帐户 (附:ChatGPT 如何处理这个问题的?)

SAP财务用户在MR22 进行修改物料价格时&#xff0c;出现了一个报错。报错如下&#xff1a;“不可能为条目1000 UMB 1000 MR1 2004确立帐户”。 Account determination for entry 1000 UMB 1000 MR2 2004 not possible Message No. M8147 Diagnosis The system did not find …

Lucene中的Field域、索引维护、搜索、相关度排序和中文分词器讲解

Field域 Field属性 Field是文档中的域&#xff0c;包括Field名和Field值两部分&#xff0c;一个文档可以包括多个Field&#xff0c;Document只是Field的一个承载体&#xff0c;Field值即为要索引的内容&#xff0c;也是要搜索的内容。 是否分词(tokenized) 是&#xff1a;作…

java+iClientOpenlayers实现污水排放扩散模拟(湖库污染排放扩散模拟)

软件实现效果 一、应用背景 湖库污染是一个日益严峻的环境问题。随着城市化和工业化的加速发展&#xff0c;越来越多的有害物质被排放入湖库中&#xff0c;导致湖库污染加剧并扩散到周围地区。本文将探讨湖库污染扩散的原因、影响和解决方法。 首先&#xff0c;湖库污染扩散的…