在现代应用程序中,异常的处理是不可忽视的一部分。Spring Boot 提供了强大的异常处理机制,但默认的异常响应格式往往不能满足我们对可读性和用户友好的需求。因此,我们需要自定义异常处理,统一异常返回格式,提高系统的健壮性和用户体验。
本文将展示如何在 Spring Boot 中实现 Controller 层的异常统一处理,设计自定义异常类,捕获异常并按照统一格式返回异常信息。
1. 定义自定义异常类
首先,我们需要定义一个自定义异常类,这个类继承自 RuntimeException
,并且可以包含一些自定义的字段,例如 code
和 msg
,用于返回更加详细的错误信息。
@Data
public class MyException extends RuntimeException {
private Integer code; // 异常码
private String msg; // 异常消息
// 只传递异常消息
public MyException(String message) {
super(message);
}
// 传递异常码和异常消息
public MyException(Integer code, String message) {
super(message);
this.code = code;
}
}
在 MyException
类中:
code
表示错误码,通常用来标识不同类型的错误。msg
表示错误消息,详细描述错误的具体信息。- 通过构造方法,我们可以在抛出异常时传递不同的错误码和消息。
2. Controller 层的异常抛出
在 Controller 层,我们可以根据实际业务逻辑抛出自定义异常 MyException
,并返回统一格式的异常信息。
@RestController
public class ExceptionController {
@RequestMapping("/exception")
public void processException() {
// 抛出自定义异常
throw new MyException(100, "出错了");
}
}
上面的代码中,当用户访问 /exception
时,Controller 会抛出一个 MyException
异常。默认情况下,Spring Boot 会返回系统默认的错误信息,但这并不够友好,因此我们需要进行统一的异常处理。
3. 创建全局异常处理器
为了统一处理 Controller 层的异常,我们需要创建一个全局异常处理器,使用 @RestControllerAdvice
注解。这个类将捕捉到所有 Controller 层的异常,并返回一个标准化的响应格式。
定义统一的异常处理器
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@Order(Ordered.HIGHEST_PRECEDENCE) // 保证异常处理器优先级最高
@RestControllerAdvice
@Slf4j
public class MyExceptionHandler {
// 捕获所有异常
@ExceptionHandler(value = Exception.class)
public ResponseData baseErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ResponseData result;
// 如果是我们定义的 MyException 异常,则返回自定义异常的消息
if (MyException.class.isAssignableFrom(e.getClass())) {
MyException applicationException = (MyException) e;
result = new ResponseData(applicationException.getCode(), applicationException.getMsg());
result.setMsg(applicationException.getMessage());
} else {
// 其他异常,统一返回内部服务器错误的提示
result = new ResponseData(500, "内部服务器错误");
result.setMsg(e.getMessage());
}
// 记录异常日志
log.error("Exception occurred: ", e);
return result;
}
}
在 MyExceptionHandler
类中:
@RestControllerAdvice
:用于定义全局异常处理器,作用类似于 Spring MVC 的@ControllerAdvice
,不过它的返回值会自动转化为 JSON 格式。@ExceptionHandler(value = Exception.class)
:这个注解表示我们要捕获所有类型的异常(包括自定义的MyException
和其他异常)。在捕获异常后,使用ResponseData
统一返回处理结果。- 我们根据异常的类型判断是否是
MyException
,如果是,则使用其错误码和消息;如果是其他异常,则统一返回500
错误码和错误提示信息。
4. 自定义返回格式
为了统一异常的响应格式,我们定义了一个 ResponseData
类,所有异常信息都会通过该类返回给前端。
@Data
public class ResponseData {
private Integer code; // 错误码
private String msg; // 错误消息
// 默认构造方法
public ResponseData() {}
// 构造方法
public ResponseData(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
ResponseData
类的作用是封装返回给客户端的错误信息,它包括:
code
:错误码,用于标识错误的类型,方便前端进行处理。msg
:错误消息,用于详细描述错误的具体信息。
5. 返回增强:日志记录与调试
为了更好地调试和排查问题,我们可以在异常处理器中记录详细的日志。在 baseErrorHandler
方法中,通过 log.error("Exception occurred: ", e)
记录异常的详细信息,便于后期排查问题。
6. 效果展示
假设我们访问 http://localhost:8080/exception
,抛出 MyException
异常后,响应将是:
{
"code": 100,
"msg": "出错了"
}
对于其他未知异常,响应将是:
{
"code": 500,
"msg": "内部服务器错误"
}
这样,前端可以根据返回的 code
来判断错误类型,进行相应的处理,同时用户能够看到更清晰和友好的错误提示信息。
7. 总结
本文详细介绍了如何在 Spring Boot 中实现 Controller 层的异常统一处理。通过自定义异常类、全局异常处理器、统一返回格式,我们能够捕获并处理应用中的异常,避免系统默认的异常堆栈信息暴露给用户,从而提供更友好的错误提示。同时,借助日志记录功能,能够在后台快速定位和排查问题。
实现异常统一处理和标准化返回格式,能够提高系统的可维护性,减少前后端的沟通成本,提升用户体验。