开发者

Spring Boot @RestControllerAdvice全局异常处理最佳实践

开发者 https://www.devze.com 2025-07-03 10:24 出处:网络 作者: 小羊Go
目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2. @ExceptionHandler三、实战代码实现四、进阶使用技巧1. 异常分类处理2. 响应状态码控制3. 日志记录优化五、最佳实践建议六、常见
目录
  • 前言
    • 一、为什么要使用全局异常处理?
    • 二、核心注解解析
      • 1. @RestControllerAdvice
      • 2. @ExceptionHandler
    • 三、实战代码实现
      • 四、进阶使用技巧
        • 1. 异常分类处理
        • 2. 响应状态码控制
        • 3. 日志记录优化
      • 五、最佳实践建议
        • 六、常见问题解答
          • 七、总结

          前言

          在开发Spring Boot应用时,优雅地处理异常是保证系统健壮性和用户体验的关键。本文将详细介绍如何使用@RestControllerAdvice实现全局异常处理,并分享实际开发中的最佳实践。

          一、为什么要使用全局异常处理?

          1. 代码复用:避免在每个Controller中重复编写try-catch

          2. 统一响应格式:标准化错误返回结构

          3. 异常分类处理:针对不同类型异常定制处理逻辑

          4. 减少样板代码:让业务逻辑更专注于核心流程

          二、核心注解解析

          1. @RestControllerAdvice

          @RestControllerAdvice@Contro编程客栈llerAdvice@ResponseBody的组合注解,主要功能:

          @Target(ElementType.TYPE)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          @ControllerAdvice
          @ResponseBody
          public @interface RestControllerAdvice {
              // 可指定包路径或控制器类
              @AliasFor(annotation = ControllerAdvice.class)
              String[] value() default {};
          }

          2. @ExceptionHandler

          用于标注处理特定异常的方法:

          @Target(ElementType.METHOD)
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          public @interface ExceptionHandler {
              // 指定要处理的异常类数组
              Class<? extends Throwable>[] value() default {};
          }

          三、实战代码实现

          以下是完整全局异常处理器实现:

          他会对于ExceptionHandler指定的异常进行处理,底层是通过AOP的技术实现的。

          import com.shjseep.shrine.result.jsONResult;
          import org.springframework.web.bind.annotation.ExceptionHandler;
          import org.springframework.web.bind.annotation.RestControllerAdvice;
          /**
           * 全局异常处理器
           * @RestControllerAdvice = @ControllerAdvice + @ResponseBody
           */
          @RestControllerAdvice
          public class GlobalExceptionHandler {
              /**
               * 处理自定义业务异常
               */
              @ExceptionHandler(GlobleException.class)
              public JSONResult handleBusinessException(GlobleException e) {
                  e.printStackTrace();
                  return JSONResult.error(e.getMessage());
              }
              /**
               * 处理所有未捕获异常
               */
              @ExceptionHandler(Exception.class)
              public JSONResult handleSystemException(Exception e) {
                  e.printStackTrace();
                  return JSONResult.error("系统异常,正在殴打程序员...", "50000");
              }
          }

          四、进阶使用技巧

          1. 异常分类处理

          // 处理数据校验异常
          @ExceptionHandler(MethodArgumentNotValidException.class)
          public JSONResult handleValidException(MethodArgumentNotValidException e) {
              String message = e.getBindingResult().getAllErrors()
                      .stream()
                      .map(DefaultMessageSourceResolvable::getDefaultMessage)
                      .collect(Collectors.joining("; "));
            python  return JSONResult.error(message);
          }
          // 处理数据库异常
          @ExceptionHandler(DataAccessException.class)
          public JSONResult handleDataAccessException(DataAccessException e) {
              log.error("数据库操作异常", e);
              return JSONResult.error("数据库服务异常");
          }

          2. 响应状态码控制

          @ExceptionHandler(UnauthorizedException.class)
          @ResponseStatus(HttpStatus.FORBIDDEN)
          public JSONjavascriptResult handleUnauthorizedException(UnauthorizedException e) {
              return JSONResult.error("无权限访问", "403");
          }

          3. 日志记录优化

          @Slf4j
          @RestControllerAdvice
          public class GlobalExceptionHandler {
              @ExceptionHandler(Exception.class)
              public JSONResult handleException(Exception e) {
                  log.error("系统异常: {}", e.getMessage(), e);
                  return JSONResult.error("系统繁忙");
              }
          }

          五、最佳实践建议

          1. 异常分类细化:不要只用一个Exception.class处理所有异常

          2. 敏感信息过滤:生产环境不要返回堆栈信息

          3. 错误码规范:制定统一的错误码体系

          4. 日志完善:关键异常必须记录完整上下文

          5. 性能考虑:异常处理逻辑应尽量轻量

          六、常见问题解答

          Q1:全局异常处理器不生效怎么办?

          • 检查是否在Spring扫描路径下

          • 确认没有其他异常处理器覆盖

          • 检查是否有Filter提前处理了异常

          Q2:如何测试全局异常处理器?

          @SpringBootTest
          class GlobalExceptionHandlerTest {
              @Autowired
              private WebApplicationContext context;
              private MockMvc mockMvc;
              @BeforeEach
              void setup() {
                  mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
              }
              @Test
              void testBusinessException() throws Exception {
                  mockMvc.perform(get("/api/test-exception"))
                         .andExpect(status().isOk())
                         .andExpect(jjavascriptsonPath("$.code").value("50000"));
              }
          }

          Q3:如何与FeignClient集成?

          @Configuration
          public class FeignConfig {
              @Bean
              public ErrorDecoder errorDecoder() {
                  return (methodKey, response) -> {
                      // 将Feign异常转换为自定义异常
                      return new BusinessException("远程服务调用失败");
                  };
              }
          }

          七、总结

          通过@RestControllerAdvice实现全局异常处理可以:

          1. 提高代码可维护性

          2. 增强系统健壮性

          3. 改善用户体验

          4. 便于监控报警

          到此这篇关于Spring Boot @RestControllerAdvice全局异常处理最佳实践的文章就介绍到这了,更多相关Spring Boot @RestControllerAdvice全局异常内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

          0

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          关注公众号