news 2026/8/7 0:19:47

告别 try-catch 地狱:Spring Boot 全局异常处理 (GlobalExceptionHandler) 最佳实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
告别 try-catch 地狱:Spring Boot 全局异常处理 (GlobalExceptionHandler) 最佳实践

一、 为什么要用 GlobalExceptionHandler?(作用)

在传统的 Web 开发中,我们经常会在 Controller 层看到大量的重复代码:

// ❌ 糟糕的代码示范@GetMapping("/user")publicResultgetUser(){try{userService.doSomething();returnResult.success();}catch(BusinessExceptione){returnResult.error(e.getCode(),e.getMessage());}catch(Exceptione){log.error("未知错误",e);returnResult.error(500,"系统内部错误");}}

这种写法有三个痛点

  1. 代码冗余:每个接口都要写一遍try-catch
  2. 格式不统一:有的返回{"code": 500},有的返回{"status": "error"},前端处理起来非常痛苦。
  3. 事务失效风险:如果在catch块中吞掉了异常且没有手动回滚,数据库事务可能提交脏数据。

GlobalExceptionHandler的核心作用:

  1. 统一响应格式:无论发生什么错误,最终返回给前端的 JSON 结构永远是固定的(如CommonResult)。
  2. 代码解耦:业务逻辑(Service/Controller)只需关注“成功”的情况,失败直接抛出异常,由全局处理器兜底。
  3. 保障事务:让异常抛出 Service 层,触发 Spring 的@Transactional自动回滚,保证数据一致性。
  4. 集中日志管理:在一个地方统一打印异常堆栈,避免日志到处乱飞。

二、 核心注解与原理(用法)

要实现全局异常处理,主要依赖两个注解:

  1. @RestControllerAdvice
    • 它是@ControllerAdvice@ResponseBody的组合注解。
    • 含义:拦截项目中所有 Controller 的异常,并将处理结果直接以 JSON 格式返回。
  2. @ExceptionHandler(Exception.class)
    • 含义:标记在方法上,声明该方法负责处理哪一种类型的异常。

三、 实战代码示例(示例)

以下是一个标准的企业级异常处理器模板。

1. 定义统一返回对象

首先,我们需要一个标准的 JSON 包装类。

@DatapublicclassCommonResult<T>{privateIntegercode;privateStringmsg;privateTdata;publicstaticCommonResult<?>error(Integercode,Stringmsg){CommonResult<?>result=newCommonResult<>();result.code=code;result.msg=msg;returnresult;}}
2. 编写全局异常处理器
@Slf4j@RestControllerAdvicepublicclassGlobalExceptionHandler{// 忽略的错误信息(噪音过滤)publicstaticfinalSet<String>IGNORE_ERROR_MESSAGES=Set.of("无效的刷新令牌");/** * 1. 处理自定义业务异常 (ServiceException) * 场景:库存不足、账号密码错误 */@ExceptionHandler(ServiceException.class)publicCommonResult<?>handleServiceException(ServiceExceptionex){// 只有不在忽略名单里的错误,才打印日志,避免刷屏if(!IGNORE_ERROR_MESSAGES.contains(ex.getMessage())){log.warn("[业务异常] {}",ex.getMessage());}returnCommonResult.error(ex.getCode(),ex.getMessage());}/** * 2. 处理参数校验异常 (JSON 格式) * 场景:@RequestBody + @Valid 校验失败 */@ExceptionHandler(MethodArgumentNotValidException.class)publicCommonResult<?>handleMethodArgumentNotValidException(MethodArgumentNotValidExceptionex){// 从异常中提取第一个具体的错误提示StringerrorMessage=ex.getBindingResult().getFieldError().getDefaultMessage();log.warn("[参数校验异常] {}",errorMessage);returnCommonResult.error(400,String.format("请求参数不正确: %s",errorMessage));}/** * 3. 处理参数校验异常 (表单/URL 参数格式) * 场景:GET 请求 @Valid 校验失败 */@ExceptionHandler(BindException.class)publicCommonResult<?>handleBindException(BindExceptionex){StringerrorMessage=ex.getBindingResult().getFieldError().getDefaultMessage();log.warn("[参数绑定异常] {}",errorMessage);returnCommonResult.error(400,String.format("请求参数不正确: %s",errorMessage));}/** * 4. 处理必填参数缺失 * 场景:@RequestParam 没传 */@ExceptionHandler(MissingServletRequestParameterException.class)publicCommonResult<?>handleMissingServletRequestParameterException(MissingServletRequestParameterExceptionex){returnCommonResult.error(400,String.format("请求参数缺失: %s",ex.getParameterName()));}/** * 5. 兜底异常处理 (Exception) * 场景:空指针、数据库连接超时、代码 Bug */@ExceptionHandler(Exception.class)publicCommonResult<?>handleGlobalException(Exceptionex){// 这里必须打印 ERROR 级别的堆栈日志,方便排查 Buglog.error("[系统异常]",ex);returnCommonResult.error(500,"系统内部错误,请联系管理员");}}

四、 进阶:如何处理 Filter 中的异常?

这是面试和实战中的高频考点。

问题@RestControllerAdvice只能捕获Controller 层之后的异常。如果Filter(如 Token 认证过滤器)抛出异常,它是抓不到的。

解决方案
yudao架构中,通常会提供一个“手动分发器”方法。Filter 捕获异常后,手动调用这个方法。

代码片段:

// 在 GlobalExceptionHandler 中添加publicCommonResult<?>allExceptionHandler(HttpServletRequestrequest,Throwableex){if(exinstanceofServiceException){returnhandleServiceException((ServiceException)ex);}// ... 手动判断其他类型returnhandleGlobalException((Exception)ex);}// 在 Filter 中调用try{chain.doFilter(request,response);}catch(Exceptione){// 手动转交给全局异常处理器CommonResult<?>result=globalExceptionHandler.allExceptionHandler(request,e);ServletUtils.writeJSON(response,result);}

五、 总结

GlobalExceptionHandler是 Spring Boot 工程化开发的基石。

它像一个污水净化器

  1. 输入:各种乱七八糟的异常(ServiceException, NullPointerException, ValidationException)。
  2. 处理:记录日志、提取关键信息、过滤噪音。
  3. 输出:标准、干净、前端友好的 JSON 数据。

通过它,我们实现了后端代码的快速失败,Service 层只需关注业务逻辑,遇到问题直接抛异常,剩下的全交给它处理。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/5 20:56:59

除了抓包失败,Burp Suite还有哪些新手常遇到的配置问题?

除了抓包失败&#xff0c;Burp Suite新手还常遇到以下配置问题&#xff1a;一、证书配置问题证书未正确信任是新手最常遇到的HTTPS抓包问题。即使下载了Burp的CA证书&#xff0c;如果未导入到浏览器的"受信任的根证书颁发机构"存储区&#xff0c;浏览器仍会提示"…

作者头像 李华
网站建设 2026/8/6 10:08:26

Spring Boot 开发入门:从 0 到 1 搭建第一个 Web 项目

前言 Spring Boot 是由 Pivotal 团队推出的基于 Spring 框架的轻量级开发框架&#xff0c;它简化了 Spring 应用的配置流程&#xff0c;通过 “约定大于配置” 的核心思想&#xff0c;让开发者无需繁琐的 XML 配置就能快速搭建和运行项目。本文将从环境准备、项目创建、核心代…

作者头像 李华
网站建设 2026/8/5 5:02:14

JSP 指令

JSP 指令 引言 JavaServer Pages(JSP)是一种用于创建动态网页的技术。在JSP页面中,指令是一种特殊的元素,用于在JSP页面中提供配置信息。JSP指令可以影响JSP页面的编译、加载和执行过程。本文将详细介绍JSP指令的相关知识,包括其类型、语法和用途。 JSP指令的类型 JSP…

作者头像 李华
网站建设 2026/8/5 23:36:47

月视图统计-Cordovaopenharmony长期习惯分析

一、功能概述 如果说周视图帮助用户了解短期变化趋势&#xff0c;那么月视图则更适合观察长期习惯。本篇文章围绕“月视图统计”页面&#xff0c;介绍如何在 Cordova Web 层 以日为单位聚合整个月的喝水数据&#xff0c;并通过 OpenHarmony ArkTS 提供原生侧的月度概览展示&…

作者头像 李华
网站建设 2026/8/5 22:26:58

Java常见技术分享-09-模版方法模式

什么是模版方法模式&#xff1f; 首先 模版方法模式&#xff0c; 应用于 假如你需要实现多个算法&#xff0c; 同时这些算法的 整体流程 一样&#xff0c; 只是在一些环节 上有自己独特的处理&#xff0c; 就可以用这个模式。 通常包含两个组件&#xff0c; 一个是抽象父类&…

作者头像 李华
网站建设 2026/8/6 14:53:39

SQLite - PHP 数据库交互指南

SQLite - PHP 数据库交互指南 引言 SQLite 是一款轻量级的数据库,被广泛应用于各种场合,包括嵌入式设备、网站和应用软件。PHP 是一种流行的服务器端脚本语言,与 SQLite 数据库的结合使用使得数据库的创建、查询、更新和删除操作变得异常简便。本文将详细探讨如何在 PHP 中…

作者头像 李华