当前位置: 首页 > ai >正文

[Java实战]springboot注解@ControllerAdvice解析(十二)

[Java实战]springboot注解@ControllerAdvice解析(十二)

一、引言

在现代的 Spring Boot 应用程序开发中,我们追求代码的简洁性、可维护性和可扩展性。而 @ControllerAdvice 注解就像是为控制器层量身定制的“魔法棒”,它能够帮助我们优雅地处理全局异常、统一响应格式,还能对控制器进行一些通用的增强操作。本文将深入探讨 @ControllerAdvice 的使用场景,带你领略其在 Spring Boot 项目中的强大魅力。

二、全局异常处理

2.1 背景

在传统的 Spring MVC 项目中,我们常常会为每个控制器方法编写单独的异常处理逻辑。例如,当一个方法抛出 NullPointerException 时,我们可能需要在该方法内部捕获异常并返回一个友好的错误提示。但这种方式会导致代码冗余,且难以维护。一旦需要修改异常处理逻辑,我们可能需要逐个修改每个控制器方法中的异常处理代码。

2.2 @ControllerAdvice 的解决方案

@ControllerAdvice 注解可以配合 @ExceptionHandler 注解来实现全局异常处理。我们只需要定义一个带有 @ControllerAdvice 注解的类,在这个类中通过 @ExceptionHandler 注解标注的方法来捕获特定类型的异常,并返回统一的响应格式。

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(NullPointerException.class)public ResponseEntity<String> handleNullPointerException(NullPointerException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("发生空指针异常:" + e.getMessage());}@ExceptionHandler(IllegalArgumentException.class)public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) {return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("非法参数异常:" + e.getMessage());}
}

在上面的代码中,GlobalExceptionHandler 类通过 @ControllerAdvice 注解标记为一个全局异常处理器。当项目中任何控制器方法抛出 NullPointerExceptionIllegalArgumentException 时,都会被相应的异常处理方法捕获,并返回相应的 HTTP 状态码和错误信息。这种方式大大减少了代码冗余,提高了代码的可维护性。

三、统一响应格式

3.1 问题

在开发 RESTful API 时,我们希望所有的响应都遵循统一的格式,例如包含状态码、消息和数据等字段。如果没有 @ControllerAdvice,我们可能需要在每个控制器方法中手动构造这样的响应格式,这同样会导致代码重复。

3.2 使用 @ControllerAdvice 实现

@ControllerAdvice 可以通过 @ModelAttribute 注解来实现对控制器方法返回值的统一包装。我们可以定义一个通用的响应类,然后在 @ControllerAdvice 标注的类中使用 @ModelAttribute 注解来将控制器方法的返回值包装成我们定义的通用响应格式。

public class ApiResponse<T> {private int code;private String message;private T data;// 省略构造方法、getter 和 setter 方法
}@ControllerAdvice
public class GlobalResponseAdvice {@ModelAttributepublic ApiResponse<?> addApiResponseHandler(@ModelAttribute Object data) {if (data instanceof ApiResponse<?>) {return (ApiResponse<?>) data;} else {return new ApiResponse<>(200, "操作成功", data);}}
}

在这个例子中,GlobalResponseAdvice 类通过 @ModelAttribute 注解的方法 addApiResponseHandler 来处理控制器方法的返回值。如果返回值已经是一个 ApiResponse 类型的对象,就直接返回;否则,将返回值包装成一个状态码为 200、消息为“操作成功”的 ApiResponse 对象。这样,我们就可以确保所有的控制器方法返回的响应都遵循统一的格式,方便前端进行处理。

四、控制器方法增强

4.1 需求

有时候,我们希望在控制器方法执行前后进行一些通用的操作,比如记录日志、验证用户权限等。如果没有合适的工具,我们可能需要在每个控制器方法中手动添加这些逻辑,这不仅增加了代码量,还降低了代码的可读性。

4.2 @ControllerAdvice 的实现方式

@ControllerAdvice 注解可以与 @Before@After@AfterReturning@AfterThrowing@Around 等 AOP 注解配合使用,来实现对控制器方法的增强。

@ControllerAdvice
public class ControllerMethodAdvice {private final Logger logger = LoggerFactory.getLogger(ControllerMethodAdvice.class);@Before("execution(* com.example.controller.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {logger.info("方法执行前:{}", joinPoint.getSignature().getName());}@After("execution(* com.example.controller.*.*(..))")public void afterMethod(JoinPoint joinPoint) {logger.info("方法执行后:{}", joinPoint.getSignature().getName());}@AfterReturning(pointcut = "execution(* com.example.controller.*.*(..))", returning = "result")public void afterReturningMethod(JoinPoint joinPoint, Object result) {logger.info("方法返回值:{}", result);}@AfterThrowing(pointcut = "execution(* com.example.controller.*.*(..))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {logger.error("方法抛出异常:{}", ex.getMessage());}
}

在上面的代码中,我们通过 @ControllerAdvice 注解定义了一个增强类 ControllerMethodAdvice,并使用 AOP 注解来实现对控制器方法的增强。@Before 注解的方法会在控制器方法执行前记录方法名称,@After 注解的方法会在控制器方法执行后记录方法名称,@AfterReturning 注解的方法会在控制器方法正常返回后记录返回值,@AfterThrowing 注解的方法会在控制器方法抛出异常后记录异常信息。这样,我们就可以在不修改控制器方法代码的情况下,实现对控制器方法的通用增强。

五、跨多个控制器共享数据

5.1 场景

在一些复杂的业务场景中,我们可能需要在多个控制器之间共享一些数据,比如用户信息、配置参数等。如果没有合适的机制,我们可能需要在每个控制器中重复获取这些数据,这不仅增加了代码量,还可能导致数据不一致的问题。

5.2 @ControllerAdvice 的应用

@ControllerAdvice 注解可以通过 @ModelAttribute 注解来向模型中添加共享数据,这些数据可以在多个控制器中使用。

@ControllerAdvice
public class SharedDataAdvice {@ModelAttribute("sharedData")public String addSharedData() {return "这是共享数据";}
}

在上面的代码中,SharedDataAdvice 类通过 @ModelAttribute 注解的方法 addSharedData 向模型中添加了一个名为 sharedData 的共享数据。在任何控制器的方法中,我们都可以通过 Model 对象来获取这个共享数据,而不需要重复获取。

@Controller
public class TestController {@GetMapping("/test")public String test(Model model) {String sharedData = model.getAttribute("sharedData").toString();return "共享数据:" + sharedData;}
}

TestControllertest 方法中,我们通过 Model 对象获取了名为 sharedData 的共享数据,并将其返回给前端。

六、总结

@ControllerAdvice 注解在 Spring Boot 项目中有着广泛的应用场景。它不仅可以实现全局异常处理,减少代码冗余,提高代码的可维护性;还可以统一响应格式,方便前端进行处理;还能对控制器方法进行增强,实现通用的日志记录、权限验证等功能;并且可以实现跨多个控制器共享数据,避免重复获取数据。总之,@ControllerAdvice 是一个非常实用的注解,它能够帮助我们编写出更加优雅、简洁、可维护的代码。在实际开发中,我们应该充分了解并合理利用 @ControllerAdvice 的这些功能,提升我们的开发效率和代码质量。

http://www.xdnf.cn/news/5464.html

相关文章:

  • DeepSeek模型微调指南:解锁高级技术,引领AI新变革
  • 信息系统项目管理师-软考高级(软考高项)​​​​​​​​​​​2025最新(十五)
  • DeepSeek:开启能源领域智能化变革新时代
  • MySQL索引概述
  • C/C++复习--C语言隐式类型转换
  • stm32 WDG看门狗
  • MySQL数据库常见面试题之三大范式
  • Python打卡训练营Day22
  • 并发笔记-锁(一)
  • AI 小智代码架构分析
  • 【DNDC模型】双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的应用
  • Java 中 AQS 的实现原理
  • Problem B: 面向对象综合题2
  • [思维模式-27]:《本质思考力》-7- 逆向思考的原理与应用
  • MySQL的锁
  • 软考第五章知识点总结
  • LeetCode 热题 100 98. 验证二叉搜索树
  • NOR Flash与NAND Flash详解
  • 添加文字标签
  • 第六天:Java数组
  • 最长字符串 / STL+BFS
  • JDS-算法开发工程师-第9批
  • 如何通过管理Windows服务加速电脑启动?
  • TikTok 推广干货:AI 加持推广效能
  • java.util.Timer
  • pycharm更改终端为wsl.exe
  • stm32测频率占空比最好的方案
  • 多智体具身人工智能:进展与未来方向(下)
  • 【计算机视觉】基于Python的相机标定项目Camera-Calibration深度解析
  • 【TI MSPM0】CCS工程管理