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

Spring全家桶之全局异常处理

全局异常处理

        • 全局异常捕获链路图
        • 完美的异常处理方案

全局异常捕获链路图
┌───────────────────────────────┐
│           客户端请求            │
└───────────────────────────────┘│▼┌──────────────────────┐│ Spring Cloud Gateway │   ← 全局异常处理: ErrorWebExceptionHandler   (限流/鉴权/路由)     │└──────────────────────┘│▼┌───────────────────────────────┐│   微服务 A(Spring Boot)       │└───────────────────────────────┘│┌─────────────────────────┐│ DispatcherServlet       │ (Spring MVC 内核)       │└─────────────────────────┘│▼┌─────────────────────────┐│ Filter / Interceptor    │   ← 全局异常处理: 自定义 Filter 兜底└─────────────────────────┘│▼┌─────────────────────────┐│ Controller 层           ││  调用 Service / DAO     │└─────────────────────────┘│▼┌─────────────────────────┐│ Service 层              ││  抛 BizException 等异常  │└─────────────────────────┘│▼┌───────────────────────────────┐│ @RestControllerAdvice          │   ← 主战场: 捕获业务异常/参数异常│ + @ExceptionHandler            │└───────────────────────────────┘│▼┌───────────────────────────────┐│ HandlerExceptionResolver       │   ← Spring 兜底解析器└───────────────────────────────┘│▼┌───────────────────────────────┐│ /error (ErrorController)       │   ← 最终兜底: 保证返回统一 JSON└───────────────────────────────┘│▼
┌─────────────────────────────────────────┐
│         返回统一 JSON 响应给客户端         │
└─────────────────────────────────────────┘┌──────────────────────────────────────────┐│                 横向扩展                   ││   Feign 调用异常 → Feign ErrorDecoder      ││   Hystrix/Sentinel 异常 → 特殊 Handler     │└──────────────────────────────────────────┘
完美的异常处理方案
  • Spring(最底层机制)

1️⃣ 业务层异常(Service 层)
不要在 Service 层吞异常,抛出自定义业务异常:

public class BizException extends RuntimeException {private final int code;public BizException(int code, String message) {super(message);this.code = code;}public int getCode() { return code; }
}

2️⃣ Controller 层异常
用 @RestControllerAdvice + @ExceptionHandler 作为主战场:

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(BizException.class)public ApiResponse<?> handleBizException(BizException e) {return ApiResponse.error(e.getCode(), e.getMessage());}@ExceptionHandler(MethodArgumentNotValidException.class)public ApiResponse<?> handleValidationException(MethodArgumentNotValidException e) {String message = e.getBindingResult().getFieldError().getDefaultMessage();return ApiResponse.error(400, message);}@ExceptionHandler(Exception.class)public ApiResponse<?> handleException(Exception e) {return ApiResponse.error(500, "服务器异常:" + e.getMessage());}
}

3️⃣ Filter / Interceptor 层异常
防止 SpringMVC 之外的异常漏掉:

@Component
public class GlobalExceptionFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;try {chain.doFilter(req, res);} catch (Exception e) {response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.setContentType("application/json;charset=UTF-8");response.getWriter().write(JSON.toJSONString(ApiResponse.error(500, "过滤器捕获异常:" + e.getMessage())));}}
}

4️⃣ 最终兜底:ErrorController
如果前面都没捕获,Spring Boot 会走 /error,我们自定义:

@RestController
public class CustomErrorController implements ErrorController {@RequestMapping("/error")public ApiResponse<?> handleError(HttpServletRequest request) {return ApiResponse.error(500, "系统未知错误");}
}

5️⃣ 统一响应体

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {private int code;private String message;private T data;public static <T> ApiResponse<T> success(T data) {return new ApiResponse<>(0, "ok", data);}public static <T> ApiResponse<T> error(int code, String message) {return new ApiResponse<>(code, message, null);}
}
  • Spring Boot(单体应用主战场)
  1. 自定义业务异常
public class BizException extends RuntimeException {private final int code;public BizException(int code, String message) {super(message);this.code = code;}public int getCode() { return code; }
}
  1. 统一响应体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {private int code;private String message;private T data;public static <T> ApiResponse<T> success(T data) {return new ApiResponse<>(0, "ok", data);}public static <T> ApiResponse<T> error(int code, String message) {return new ApiResponse<>(code, message, null);}
}
  1. 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(BizException.class)public ApiResponse<?> handleBizException(BizException e) {return ApiResponse.error(e.getCode(), e.getMessage());}@ExceptionHandler(MethodArgumentNotValidException.class)public ApiResponse<?> handleValidationException(MethodArgumentNotValidException e) {String message = e.getBindingResult().getFieldError().getDefaultMessage();return ApiResponse.error(400, message);}@ExceptionHandler(Exception.class)public ApiResponse<?> handleException(Exception e) {return ApiResponse.error(500, "服务器异常:" + e.getMessage());}
}
  1. Filter 层兜底
@Component
public class GlobalExceptionFilter implements Filter {@Overridepublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {HttpServletResponse response = (HttpServletResponse) res;try {chain.doFilter(req, res);} catch (Exception e) {response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.setContentType("application/json;charset=UTF-8");response.getWriter().write(JSON.toJSONString(ApiResponse.error(500, "过滤器捕获异常:" + e.getMessage())));}}
}
  1. 最终兜底 ErrorController
@Component
public class FeignErrorDecoder implements ErrorDecoder {@Overridepublic Exception decode(String methodKey, Response response) {try {String body = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);ApiResponse<?> error = JSON.parseObject(body, ApiResponse.class);return new BizException(error.getCode(), error.getMessage());} catch (Exception e) {return new BizException(500, "远程服务调用失败");}}
}
  • Spring Cloud(微服务扩展)
  1. Feign 调用异常处理
@Component
public class FeignErrorDecoder implements ErrorDecoder {@Overridepublic Exception decode(String methodKey, Response response) {try {String body = IOUtils.toString(response.body().asInputStream(), StandardCharsets.UTF_8);ApiResponse<?> error = JSON.parseObject(body, ApiResponse.class);return new BizException(error.getCode(), error.getMessage());} catch (Exception e) {return new BizException(500, "远程服务调用失败");}}
}
  1. Gateway 全局异常处理(WebFlux)
@Component
public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler {@Overridepublic Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);response.getHeaders().setContentType(MediaType.APPLICATION_JSON);ApiResponse<?> error = ApiResponse.error(500, ex.getMessage());DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(error).getBytes(StandardCharsets.UTF_8));return response.writeWith(Mono.just(buffer));}
}
  1. 熔断 / 限流(Sentinel/Hystrix)异常处理
@ExceptionHandler(BlockException.class)
public ApiResponse<?> handleSentinelException(BlockException e) {return ApiResponse.error(429, "请求过多,请稍后再试");
}
http://www.dtcms.com/a/342867.html

相关文章:

  • Spring Boot生态中ORM对数据治理的支持有哪些?
  • Ubuntu22.04配置网络上网
  • linux-ubuntu里docker的容器portainer容器建立后如何打开?
  • Maven无法修改镜像,镜像在IDEA里不生效
  • 室外和室内 PoE 延长器有什么区别?
  • [CSP-J2020] 直播获奖
  • 集成学习:从原理到实战,一文掌握 Bagging、Boosting 与 Stacking
  • 集成学习:如何让多个 “弱模型” 变成 “强模型”?
  • demo 汽车之家(渲染-筛选-排序-模块抽离数据)
  • Linux之Ansible自动化运维(二)
  • Linux内核源码详解--缺页异常(Page Fault)处理的核心函数handle_pte_fault
  • Maven(三)
  • Class A 包含字段 x Class B 也包含字段 x,如果判断List<A> lista 和 List<B> listb 有相同的 x?
  • 基于websocket聊天室的基本点
  • SQL中的游标
  • html ajax前端页面
  • 51单片机-驱动直流电机模块教程
  • 单片机\物联网\51单片机\嵌入式开发\软硬件结合的基于STM32的电梯管理系统的设计/基于STM32的电梯运行系统的设计
  • 【华为OD-C卷-020 -关联端口组合并 100分(python、java、c++、js、c)】
  • 解决 uniapp 修改index.html文件不生效的问题
  • PCB文件怎么快速判断是通孔还是盲孔呢?
  • Git 2.15.0 64位安装步骤Windows详细教程从下载到验证(附安装包下载)
  • 14、外部中断
  • 【科普向-第三篇】汽车电子MCU操作系统详解:CP AUTOSAR与FreeRTOS
  • 1688电商商品大数据采集之路 技术篇
  • 嵌入式接口通识知识之PWM接口
  • 机器学习聚类与集成算法全解析:从 K-Means 到随机森林的实战指南
  • 从系统漏洞归零到候诊缩短20%:一个信创样本的效能革命
  • 播放器视频后处理实践(一)
  • 视频加水印 视频加水印软件 视频加动态水印