前言
在日常开发中,你一定见过这样的代码:
try {
// 业务逻辑
} catch (exception e) {
e.printstacktrace();
}或者接口返回五花八门:
- 有的返回
500错误 - 有的返回一段文字
- 有的直接抛异常前端看不懂
- 每个接口都写一遍 try-catch
代码冗余、维护困难、前端对接痛苦、日志混乱,线上出问题还难定位。
统一异常处理,就是用来解决这些问题的。
今天这篇文章,带你从零到一实现 spring boot 全局统一异常处理,
包含:自定义异常、统一返回、全局捕获、异常分类、日志规范、实战案例。
看完直接落地到你的项目里。
一、为什么要做统一异常处理?
1. 现状痛点
- 每个接口都写 try-catch,代码重复
- 异常信息不规范,前端无法统一解析
- 错误信息暴露给用户,不安全
- 日志混乱,难以排查问题
- 系统稳定性差,容易直接崩接口
2. 统一异常处理的好处
- 代码更优雅,业务层不用处理异常
- 所有异常统一格式返回
- 异常可监控、可统计、可告警
- 安全:不把系统异常暴露给前端
- 提升开发效率与维护性
二、实现统一异常处理的核心组件
spring boot 提供两个最核心注解:
@restcontrolleradvice:全局捕获控制器异常@exceptionhandler:捕获指定类型异常
配合:
- 统一返回结果类
- 自定义业务异常
- 异常分类
- 日志规范
就能完成一套企业级异常体系。
三、第一步:定义统一返回格式
前端最需要的是固定结构。
创建 result.java:
import lombok.data;
@data
public class result<t> {
private int code;
private string msg;
private t data;
// 成功
public static <t> result<t> success(t data) {
result<t> r = new result<>();
r.setcode(200);
r.setmsg("success");
r.setdata(data);
return r;
}
// 失败
public static <t> result<t> fail(int code, string msg) {
result<t> r = new result<>();
r.setcode(code);
r.setmsg(msg);
r.setdata(null);
return r;
}
}以后所有接口统一返回 result。
四、第二步:自定义业务异常
系统异常和业务异常要分开。
创建 businessexception.java:
public class businessexception extends runtimeexception {
private int code;
private string msg;
public businessexception(string msg) {
super(msg);
this.code = 500;
this.msg = msg;
}
public businessexception(int code, string msg) {
super(msg);
this.code = code;
this.msg = msg;
}
// getter
}使用示例:
if (user == null) {
throw new businessexception(400, "用户不存在");
}五、第三步:定义全局异常捕获类(核心)
创建 globalexceptionhandler.java:
import lombok.extern.slf4j.slf4j;
import org.springframework.web.bind.annotation.exceptionhandler;
import org.springframework.web.bind.annotation.restcontrolleradvice;
@restcontrolleradvice
@slf4j
public class globalexceptionhandler {
/**
* 捕获业务异常
*/
@exceptionhandler(businessexception.class)
public result<?> handlebusinessexception(businessexception e) {
log.warn("业务异常:{}", e.getmsg());
return result.fail(e.getcode(), e.getmsg());
}
/**
* 捕获参数校验异常
*/
@exceptionhandler(illegalargumentexception.class)
public result<?> handleillegalargument(illegalargumentexception e) {
log.warn("参数异常:{}", e.getmessage());
return result.fail(400, e.getmessage());
}
/**
* 捕获空指针
*/
@exceptionhandler(nullpointerexception.class)
public result<?> handlenullpointer(nullpointerexception e) {
log.error("空指针异常", e);
return result.fail(500, "服务器内部错误");
}
/**
* 兜底:所有其他异常
*/
@exceptionhandler(exception.class)
public result<?> handleexception(exception e) {
log.error("系统异常", e);
return result.fail(500, "服务器繁忙,请稍后再试");
}
}作用:
所有 controller 抛出的异常,都会进入这里统一处理。
六、第四步:整合 validation 参数校验(非常实用)
前端传参错误,统一返回。
1. 引入依赖
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-validation</artifactid>
</dependency>2. dto 加校验
import jakarta.validation.constraints.notblank;
public class userlogindto {
@notblank(message = "用户名不能为空")
private string username;
@notblank(message = "密码不能为空")
private string password;
}3. 接口加@valid
@postmapping("/login")
public result<?> login(@valid @requestbody userlogindto dto) {
return result.success("login success");
}4. 捕获校验异常
import org.springframework.validation.bindexception;
import org.springframework.validation.fielderror;
@exceptionhandler(bindexception.class)
public result<?> handlebindexception(bindexception e) {
fielderror fielderror = e.getfielderror();
string msg = fielderror.getdefaultmessage();
log.warn("参数校验失败:{}", msg);
return result.fail(400, msg);
}效果:
前端收到干净的:
{
"code": 400,
"msg": "用户名不能为空",
"data": null
}七、第五步:规范日志级别(线上必备)
- 业务异常:warn
- 参数异常:warn
- 系统异常:error
示例:
log.warn("业务异常:{}", e.getmsg());
log.error("空指针异常", e);便于日志平台筛选、告警。
八、第六步:实际业务中怎么用?(最真实示例)
service 层:
@service
public class userservice {
public user login(string username, string password) {
user user = usermapper.selectbyusername(username);
if (user == null) {
throw new businessexception(400, "用户名或密码错误");
}
if (!user.getpassword().equals(password)) {
throw new businessexception(400, "用户名或密码错误");
}
return user;
}
}controller 层:
@postmapping("/login")
public result<user> login(@valid @requestbody userlogindto dto) {
user user = userservice.login(dto.getusername(), dto.getpassword());
return result.success(user);
}没有 try-catch!
代码极度清爽。
九、企业级异常分类规范
你可以直接在项目里使用这套异常码:
- 200 成功
- 400 参数错误
- 401 未登录
- 403 无权限
- 404 不存在
- 500 系统错误
- 1001~1999 业务自定义
示例:
throw new businessexception(401, "请先登录"); throw new businessexception(403, "无此权限"); throw new businessexception(1001, "余额不足");
以上就是springboot统一异常处理的实用方案的详细内容,更多关于springboot统一异常处理的资料请关注代码网其它相关文章!
发表评论