Backend Development 10 min read

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.

Top Architecture Tech Stack
Top Architecture Tech Stack
Top Architecture Tech Stack
Global Exception Handling in SpringBoot: Custom Handlers, Enums, and Response Wrappers

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.

backendJavaSpringBootExceptionHandlingCustomExceptionGlobalException
Top Architecture Tech Stack
Written by

Top Architecture Tech Stack

Sharing Java and Python tech insights, with occasional practical development tool tips.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.