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.

Top Architect
Top Architect
Top Architect
SpringBoot Global Exception Handling Tutorial with Custom Error Codes and Response Wrapper

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpringBootexceptionhandlingGlobalExceptionHandling
Top Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

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.