Master SpringBoot Global Exception Handling: From Setup to Testing
This article explains how to set up SpringBoot 1.5.17 with Maven, define custom error interfaces, enums, and exception classes, implement a global @ControllerAdvice handler, and verify the behavior through Postman tests for various CRUD endpoints, demonstrating unified error responses.
SpringBoot Global Exception Preparation
Explanation: If you want to get the project directly, download the code from the link at the bottom.
Development Preparation
Environment Requirements : JDK 1.8, SpringBoot 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>
<relativePath />
</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>Configuration files generally do not need changes; global exception handling is implemented in code.
Code Implementation
SpringBoot provides some default exception handling, but we need a unified capture using @ControllerAdvice and @ExceptionHandler.
Example handler:
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(value = Exception.class)
public String exceptionHandler(Exception e){
System.out.println("未知异常!原因是:" + e);
return e.getMessage();
}
}Define a base error interface:
public interface BaseErrorInfoInterface {
String getResultCode();
String getResultMsg();
}Define an enum implementing the interface:
public enum CommonEnum implements BaseErrorInfoInterface {
SUCCESS("200","成功!"),
BODY_NOT_MATCH("400","请求的数据格式不符!"),
SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"),
NOT_FOUND("404","未找到该资源!"),
INTERNAL_SERVER_ERROR("500","服务器内部错误!"),
SERVER_BUSY("503","服务器正忙,请稍后再试!");
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 class:
public class BizException extends RuntimeException {
private String errorCode;
private 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;
}
public String getErrorCode(){ return errorCode; }
public String getErrorMsg(){ return errorMsg; }
@Override
public String getMessage(){ return errorMsg; }
@Override
public Throwable fillInStackTrace(){ return this; }
}Result wrapper class:
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());
return rb;
}
public static ResultBody error(String code, String message){
ResultBody rb = new ResultBody();
rb.setCode(code);
rb.setMessage(message);
return rb;
}
// getters and setters omitted for brevity
@Override
public String toString(){ return JSONObject.toJSONString(this); }
}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("发生业务异常!原因是:{}", e.getErrorMsg());
return ResultBody.error(e.getErrorCode(), e.getErrorMsg());
}
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e){
logger.error("发生空指针异常!原因是:", e);
return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultBody exceptionHandler(HttpServletRequest req, Exception e){
logger.error("未知异常!原因是:", e);
return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
}
}Entity class User and a REST controller with CRUD methods intentionally throwing exceptions to test the handlers:
@RestController
@RequestMapping("/api")
public class UserRestController {
@PostMapping("/user")
public boolean insert(@RequestBody User user){
if(user.getName()==null){
throw new BizException("-1","用户姓名不能为空!");
}
return true;
}
@PutMapping("/user")
public boolean update(@RequestBody User user){
String str=null;
str.equals("111");
return true;
}
@DeleteMapping("/user")
public boolean delete(@RequestBody User user){
Integer.parseInt("abc123");
return true;
}
@GetMapping("/user")
public List<User> findByUser(User user){
User u = new User();
u.setId(1L);
u.setName("xuwujing");
u.setAge(18);
return Arrays.asList(u);
}
}Application entry point:
@SpringBootApplication
public class App {
public static void main(String[] args){
SpringApplication.run(App.class, args);
System.out.println("程序正在运行...");
}
}Functional Testing
After starting the program, use Postman to test each endpoint. GET returns the user data, POST with missing name returns
{"code":"-1","message":"用户姓名不能为空!","result":null}, PUT triggers a NullPointerException and returns code 400 with message "请求的数据格式不符!", DELETE triggers a generic exception and returns code 500 with message "服务器内部错误!". The following images illustrate the responses.
The article notes that the global exception handler can also perform page redirects by omitting @ResponseBody, and that using @ControllerAdvice versus @RestControllerAdvice changes whether the response is automatically converted to JSON.
Other
Project address: https://github.com/xuwujing/springBoot-study/tree/master/springboot-exceptionHandler
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.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
