Day18: Spring异常急诊科:解剖MVC中的异常分诊体系 —— 从局部绷带到全局手术台的异常处理全路线图

目录

    • 一、急诊分级诊疗体系:HandlerExceptionResolver优先权争夺战
      • 1.1 四大科室优先级列表
      • 1.2 分诊规则核心代码解析
    • 二、候诊大厅:@ControllerAdvice全局分诊台实现内幕
      • 2.1 全局异常分诊站配置
      • 2.2 分诊台特殊装备库
    • 三、疑难病例会诊:复合异常处理案例
      • 3.1 参数验证异常特护病房
      • 3.2 自定义业务异常绿色通道
    • 四、急诊科室扩展训练:自定义分诊规则
      • 4.1 打造专属急诊科室
    • 五、急诊分诊黄金法则:最佳实践清单
      • 5.1 优先级设计金字塔
      • 5.2 避坑指南(常见急诊误诊案例)
    • 六、急救技术升级路线
      • 6.1 异常监控系统整合
      • 6.2 国际会诊:多语言错误消息
    • 七、急诊科室的未来

急诊室的故事:当Controller层突然抛出一个异常,Spring MVC就像配备智能分诊系统的三甲医院,@ControllerAdvice是候诊大厅的分诊台,HandlerExceptionResolver们是各科专家,而你的异常就是需要救治的病患。今天我们一起拆解Spring异常处理的分级诊疗系统!


一、急诊分级诊疗体系:HandlerExceptionResolver优先权争夺战

1.1 四大科室优先级列表

// 核心处理器优先级链(源码节选)
public class DispatcherServlet {
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    // 初始化顺序决定了处理优先级
    initHandlerExceptionResolvers() {
        // 1. ExceptionHandlerExceptionResolver (@ExceptionHandler)
        // 2. ResponseStatusExceptionResolver (@ResponseStatus)
        // 3. DefaultHandlerExceptionResolver (Spring标准异常转换)
        // 4. SimpleMappingExceptionResolver (xml配置异常映射)
    }
}

会诊流程图解
患者异常 → 专科医生1(最高优先级)→ 治不好 → 转诊专科医生2 → … → 急诊大厅(SimpleMappingExceptionResolver)

1.2 分诊规则核心代码解析

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver {
    @Override
    protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
        // 判断是否有@ExceptionHandler方法可处理该异常
        return findExceptionHandlerMethod(handler, exception) != null;
    }
}

public class ResponseStatusExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(...) {
        // 检查是否有@ResponseStatus注解
        ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(
            exception.getClass(), ResponseStatus.class);
        if (status != null) {
            return handleResponseStatus(status, request, response, handler, exception);
        }
        return null; // 无法处理,转交下一科室
    }
}

二、候诊大厅:@ControllerAdvice全局分诊台实现内幕

2.1 全局异常分诊站配置

@ControllerAdvice(basePackages = "com.example.controller")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionTriage {

    // 处理所有SQL异常
    @ExceptionHandler(SQLException.class)
    public ResponseEntity<ErrorResult> handleSQLException(SQLException ex) {
        return ResponseEntity.status(503)
            .body(new ErrorResult("DATABASE_ERROR", ex.getMessage()));
    }

    // 拦截所有未捕获的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResult> fallbackHandler(Exception ex) {
        return ResponseEntity.status(500)
            .body(new ErrorResult("SYSTEM_ERROR", "系统开小差啦~"));
    }
}

2.2 分诊台特殊装备库

匹配模式增强

@ControllerAdvice(
    annotations = RestController.class, // 拦截带有特定注解的Controller
    assignableTypes = {BaseController.class}, // 拦截指定类及其子类
    basePackageClasses = UserOperation.class // 按功能模块划分
)
public class CustomizedExceptionAdvice {
    // 精确到毫厘的异常拦截
}

三、疑难病例会诊:复合异常处理案例

3.1 参数验证异常特护病房

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResult> handleValidationException(
    MethodArgumentNotValidException ex) {
    
    List<FieldError> errors = ex.getBindingResult().getFieldErrors();
    Map<String, String> errorMap = errors.stream()
        .collect(Collectors.toMap(
            FieldError::getField,
            FieldError::getDefaultMessage
        ));
    
    return ResponseEntity.badRequest()
        .body(new ErrorResult("VALIDATION_FAILED", errorMap));
}

3.2 自定义业务异常绿色通道

public class BusinessException extends RuntimeException {
    private final ErrorCode code;
    
    public BusinessException(ErrorCode code, String message) {
        super(message);
        this.code = code;
    }
    // getters...
}

@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResult> handleBusinessException(
    BusinessException ex) {
    
    return ResponseEntity.status(ex.getCode().getHttpStatus())
        .body(new ErrorResult(ex.getCode().name(), ex.getMessage()));
}

四、急诊科室扩展训练:自定义分诊规则

4.1 打造专属急诊科室

public class CustomExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Object handler, Exception ex) {
        
        if (ex instanceof OAuth2AuthenticationException) {
            response.setStatus(401);
            writeJsonResponse(response, new ErrorResult("AUTH_FAIL", "请重新登录"));
            return new ModelAndView(); // 已处理
        }
        return null; // 转交其他处理器
    }
}

// 注册自定义解析器
@Configuration
public class ExceptionConfig implements WebMvcConfigurer {
    
    @Override
    public void configureHandlerExceptionResolvers(
        List<HandlerExceptionResolver> resolvers) {
        
        resolvers.add(0, new CustomExceptionResolver()); // 最高优先级
    }
}

五、急诊分诊黄金法则:最佳实践清单

5.1 优先级设计金字塔

  1. 特定Controller的@ExceptionHandler
  2. @ControllerAdvice全局处理器
  3. ResponseStatusExceptionResolver
  4. 自定义HandlerExceptionResolver
  5. DefaultHandlerExceptionResolver

5.2 避坑指南(常见急诊误诊案例)

症状表现 根本原因 诊疗方案
异常被多个处理器重复处理 未明确指定异常类型范围 精确匹配异常类型树
全局处理器不生效 包扫描路径未正确配置 检查@ControllerAdvice的basePackages
响应状态码始终200 未正确设置response状态 使用ResponseEntity或直接设置response
异步请求异常无法捕获 未配置异步异常处理器 添加AsyncUncaughtExceptionHandler

六、急救技术升级路线

6.1 异常监控系统整合

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResult> captureException(Exception ex) {
    // 发送异常到监控平台
    monitorClient.send(new ErrorEvent(ex));
    return ResponseEntity.internalServerError()
        .body(new ErrorResult("ERROR", "系统繁忙"));
}

6.2 国际会诊:多语言错误消息

@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResult> handleI18nException(
    BusinessException ex, Locale locale) {
    
    String message = messageSource.getMessage(
        ex.getCode().name(), null, locale);
    
    return ResponseEntity.status(ex.getCode().getHttpStatus())
        .body(new ErrorResult(ex.getCode().name(), message));
}

七、急诊科室的未来

  • 反应式异常处理:WebFlux中的异常处理新范式
  • 全链路追踪:集成Sleuth实现异常链路追踪
  • AI预诊断:基于机器学习的异常分类系统

掌握Spring MVC异常处理体系后,你的应用将拥有三甲医院级别的容错能力。记住:好的异常处理不是消灭异常,而是让系统在遭遇异常时依然能优雅地提供服务。现在打开你的IDE,打造一个永不宕机的"医疗系统"吧!

你可能感兴趣的:(Spring,spring,mvc,java)