Global Exception Handling in SpringBoot: Custom Handlers, Enums, and Response Wrappers
This article explains how to implement unified global exception handling in SpringBoot by using @ControllerAdvice with @ExceptionHandler, defining a base error interface, custom enums, exception classes, and a standardized response wrapper, while also providing test code examples and best‑practice recommendations.
Introduction
In everyday SpringBoot projects, exceptions are inevitable; handling them efficiently helps developers locate bugs quickly, reduces code duplication, and improves overall code readability and maintainability.
Global Exception Handling Method One
1.1 Custom Global Exception Class
By annotating a class with @ControllerAdvice and defining methods with @ExceptionHandler , SpringBoot can capture all uncaught exceptions globally.
/**
* @description Custom exception handling
* @author DT
* @version v1.0 */
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String exceptionHandler(Exception e) {
System.out.println("全局异常捕获>>>:" + e);
return "全局异常捕获,错误原因>>>" + e.getMessage();
}
}1.2 Manually Throwing an Exception
Developers can deliberately trigger an exception to test the global handler.
@GetMapping("/getById/{userId}")
public CommonResult
getById(@PathVariable Integer userId) {
// 手动抛出异常
int a = 10 / 0;
return CommonResult.success(userService.getById(userId));
}1.3 Test Output
The console output shows the captured exception message, but the raw stack trace is not user‑friendly.
Global Exception Handling Method Two
2.1 Define a Base Error Interface
public interface BaseErrorInfoInterface {
String getResultCode();
String getResultMsg();
}2.2 Define an Enum for Error Codes
public enum ExceptionEnum implements BaseErrorInfoInterface {
SUCCESS("2000", "成功!"),
BODY_NOT_MATCH("4000", "请求的数据格式不符!"),
SIGNATURE_NOT_MATCH("4001", "请求的数字签名不匹配!"),
NOT_FOUND("4004", "未找到该资源!"),
INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
SERVER_BUSY("5003", "服务器正忙,请稍后再试!"),
PARAMS_NOT_CONVERT("4002", "类型转换不对!");
private final String resultCode;
private final String resultMsg;
ExceptionEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() { return resultCode; }
@Override
public String getResultMsg() { return resultMsg; }
}2.3 Custom Business Exception Class
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
protected String errorCode;
protected String errorMsg;
public BizException() { super(); }
public BizException(BaseErrorInfoInterface errorInfo) {
super(errorInfo.getResultCode());
this.errorCode = errorInfo.getResultCode();
this.errorMsg = errorInfo.getResultMsg();
}
public BizException(String errorMsg) { super(errorMsg); this.errorMsg = errorMsg; }
public BizException(String errorCode, String errorMsg) {
super(errorMsg);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
// getters and setters omitted for brevity
@Override
public Throwable fillInStackTrace() { return this; }
}2.4 Standard Response Wrapper
public class ResultResponse {
private String code;
private String message;
private Object result;
public ResultResponse() {}
public ResultResponse(BaseErrorInfoInterface errorInfo) {
this.code = errorInfo.getResultCode();
this.message = errorInfo.getResultMsg();
}
public static ResultResponse success() { return success(null); }
public static ResultResponse success(Object data) {
ResultResponse rb = new ResultResponse();
rb.setCode(ExceptionEnum.SUCCESS.getResultCode());
rb.setMessage(ExceptionEnum.SUCCESS.getResultMsg());
rb.setResult(data);
return rb;
}
public static ResultResponse error(BaseErrorInfoInterface errorInfo) {
ResultResponse rb = new ResultResponse();
rb.setCode(errorInfo.getResultCode());
rb.setMessage(errorInfo.getResultMsg());
rb.setResult(null);
return rb;
}
public static ResultResponse error(String code, String message) {
ResultResponse rb = new ResultResponse();
rb.setCode(code);
rb.setMessage(message);
rb.setResult(null);
return rb;
}
// getters and setters omitted for brevity
@Override
public String toString() { return JSONObject.toJSONString(this); }
}2.5 Custom Global Exception Handler
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = BizException.class)
@ResponseBody
public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e) {
logger.error("发生业务异常!原因是:{}", e.getErrorMsg());
return ResultResponse.error(e.getErrorCode(), e.getErrorMsg());
}
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e) {
logger.error("发生空指针异常!原因是:", e);
return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, Exception e) {
logger.error("未知异常!原因是:", e);
return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e) {
logger.error("发生类型转换异常!原因是:", e);
return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}
}2.6 Test Endpoints
@PostMapping("/add")
public boolean add(@RequestBody User user) {
// 如果姓名为空就手动抛出一个自定义的异常!
if (user.getName() == null) {
throw new BizException("-1", "用户姓名不能为空!");
}
return true;
}
@PutMapping("/update")
public boolean update(@RequestBody User user) {
// 故意制造空指针异常
String str = null;
str.equals("111");
return true;
}
@DeleteMapping("/delete")
public boolean delete(@RequestBody User user) {
// 故意制造类型转换异常
Integer.parseInt("abc123");
return true;
}Conclusion
Unified exception handling reduces repetitive code, simplifies debugging, and improves maintainability, thereby significantly boosting development efficiency in SpringBoot backend projects.
Top Architecture Tech Stack
Sharing Java and Python tech insights, with occasional practical development tool tips.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.