SpringBoot Global Exception Handling Tutorial with Custom Error Codes and Response Wrapper
This article demonstrates how to set up global exception handling in a SpringBoot application by preparing the development environment, adding Maven dependencies, defining a base error interface, custom enums, exception classes, a unified response body, and a controller advice that captures business, null‑pointer, and generic exceptions, followed by testing the implementation with Postman.
This article explains how to implement global exception handling in a SpringBoot project, covering environment preparation, Maven dependencies, custom error interfaces, enums, exception classes, a unified response wrapper, and a controller advice for handling various exceptions.
Development Preparation
Required JDK version: 1.8; SpringBoot version: 1.5.17.RELEASE.
Maven Dependencies
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.17.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Boot Web dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test dependency -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
</dependencies>Custom Base Error Interface
public interface BaseErrorInfoInterface {
/** error code */
String getResultCode();
/** error description */
String getResultMsg();
}Custom Enum Implementing the Interface
public enum CommonEnum implements BaseErrorInfoInterface {
SUCCESS("200", "Success!"),
BODY_NOT_MATCH("400", "Request data format does not match!"),
SIGNATURE_NOT_MATCH("401", "Signature does not match!"),
NOT_FOUND("404", "Resource not found!"),
INTERNAL_SERVER_ERROR("500", "Internal server error!"),
SERVER_BUSY("503", "Server is busy, try later!");
private String resultCode;
private String resultMsg;
CommonEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() { return resultCode; }
@Override
public String getResultMsg() { return resultMsg; }
}Custom Business Exception
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(errorCode); this.errorCode = errorCode; this.errorMsg = errorMsg; }
// getters and setters omitted for brevity
@Override
public Throwable fillInStackTrace() { return this; }
}Unified Response Body
public class ResultBody {
private String code;
private String message;
private Object result;
public ResultBody() {}
public ResultBody(BaseErrorInfoInterface errorInfo) {
this.code = errorInfo.getResultCode();
this.message = errorInfo.getResultMsg();
}
public static ResultBody success() { return success(null); }
public static ResultBody success(Object data) {
ResultBody rb = new ResultBody();
rb.setCode(CommonEnum.SUCCESS.getResultCode());
rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
rb.setResult(data);
return rb;
}
public static ResultBody error(BaseErrorInfoInterface errorInfo) {
ResultBody rb = new ResultBody();
rb.setCode(errorInfo.getResultCode());
rb.setMessage(errorInfo.getResultMsg());
rb.setResult(null);
return rb;
}
public static ResultBody error(String code, String message) {
ResultBody rb = new ResultBody();
rb.setCode(code);
rb.setMessage(message);
rb.setResult(null);
return rb;
}
// getters, setters and toString omitted for brevity
}Global Exception Handler
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = BizException.class)
@ResponseBody
public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {
logger.error("Business exception occurred: {}", e.getErrorMsg());
return ResultBody.error(e.getErrorCode(), e.getErrorMsg());
}
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
logger.error("Null pointer exception occurred:", e);
return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
logger.error("Unknown exception occurred: {}", e);
return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
}
}Entity Class (User)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
// getters, setters, constructors and toString omitted for brevity
}REST Controller
@RestController
@RequestMapping("/api")
public class UserRestController {
@PostMapping("/user")
public boolean insert(@RequestBody User user) {
if (user.getName() == null) {
throw new BizException("-1", "User name cannot be empty!");
}
return true;
}
@PutMapping("/user")
public boolean update(@RequestBody User user) {
String str = null;
str.equals("111"); // triggers NullPointerException
return true;
}
@DeleteMapping("/user")
public boolean delete(@RequestBody User user) {
Integer.parseInt("abc123"); // triggers NumberFormatException
return true;
}
@GetMapping("/user")
public List<User> findByUser(User user) {
List<User> list = new ArrayList<>();
User u = new User();
u.setId(1);
u.setName("xuwujing");
u.setAge(18);
list.add(u);
return list;
}
}Application Entry Point
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
System.out.println("Application is running...");
}
}Testing
The application can be tested with Postman. GET http://localhost:8181/api/user returns the sample user. POST with a missing name returns
{"code":"-1","message":"User name cannot be empty!","result":null}. PUT triggers a null‑pointer error and returns code 400 with the corresponding message. DELETE triggers a generic exception and returns code 500 with the internal server error message.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.
