SpringBoot Global Exception Handling Tutorial with Custom Error Responses

This article demonstrates how to implement global exception handling in a SpringBoot project, covering environment setup, Maven dependencies, custom error interfaces, enums, exception classes, response wrappers, and controller advice, along with testing via Postman to verify handling of custom, null pointer, and generic exceptions.

Top Architect
Top Architect
Top Architect
SpringBoot Global Exception Handling Tutorial with Custom Error Responses

The article explains how to set up and use global exception handling in a SpringBoot application. It starts with the required environment (JDK 1.8, SpringBoot 1.5.17.RELEASE) and Maven dependencies, including Spring Boot Web, Test, and FastJSON.

<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>

Configuration files need no changes; the focus is on code implementation.

Custom Base Interface

public interface BaseErrorInfoInterface {
    /** 错误码 */
    String getResultCode();
    /** 错误描述 */
    String getResultMsg();
}

CommonEnum 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;
    // constructor and getters omitted for brevity
}

BizException – custom runtime exception

public class BizException extends RuntimeException {
    protected String errorCode;
    protected String errorMsg;
    public BizException() { super(); }
    public BizException(BaseErrorInfoInterface errorInfo) {
        super(errorInfo.getResultCode());
        this.errorCode = errorInfo.getResultCode();
        this.errorMsg = errorInfo.getResultMsg();
    }
    // other constructors and getters/setters omitted for brevity
    @Override
    public String getMessage() { return errorMsg; }
    @Override
    public Throwable fillInStackTrace() { return this; }
}

ResultBody – unified response wrapper

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;
    }
    @Override
    public String toString() { return JSONObject.toJSONString(this); }
    // getters and setters omitted for brevity
}

GlobalExceptionHandler using @ControllerAdvice

@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

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
    private int age;
    // constructors, getters, setters, toString omitted for brevity
}

REST controller providing CRUD endpoints

@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"); // triggers NullPointerException
        return true;
    }
    @DeleteMapping("/user")
    public boolean delete(@RequestBody User user) {
        Integer.parseInt("abc123"); // triggers generic Exception
        return true;
    }
    @GetMapping("/user")
    public List<User> findByUser(User user) {
        User u = new User();
        u.setId(1);
        u.setName("xuwujing");
        u.setAge(18);
        return Collections.singletonList(u);
    }
}

Application entry point

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
        System.out.println("程序正在运行...");
    }
}

After starting the application, the article shows how to use Postman to test each endpoint. GET returns the user data, POST with missing name returns a JSON error with code "-1", PUT triggers the null‑pointer handler returning code "400", and DELETE triggers the generic handler returning code "500". The tests demonstrate that more specific exception handlers are invoked before the generic one.

The article also notes that using @RestControllerAdvice would automatically convert responses to JSON, while @ControllerAdvice gives more flexibility for custom response handling or page redirects.

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.

JavaSpringBootrestexceptionhandlingGlobalExceptionHandling
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.