Technology Sharing

SpringBoot: SpringBoot unified response and unified exception handling

2024-07-06

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

I. Introduction

When developing Spring Boot applications, the way to handle response results and exceptions has a crucial impact on the maintainability, scalability and team collaboration of the project. Dispersed response results and exception handling logic often lead to redundant code, which is difficult to understand and maintain. Therefore, unified result return and unified exception handling are one of the key strategies to improve project quality.

2. Unified result return

Unifying the response usually means defining a standard response format for all controller methods. This can be achieved by creating one or more response entity classes that contain common fields such as status code, message, and data. After processing the business logic, the controller method will fill in these fields and return it to the client.

Next, let's take a look at how to achieve unified result return in SpringBoot.

1. Define a common response object

Create a generic response object, define the success and failure return scenarios, and ensure that the generic return object is used in the interface.

public class ResponseResult {

    private int code;

    private String message;

    private Object data;

    public static ResponseResult success(Object data) {
        ResponseResult responseResult = new ResponseResult();
        responseResult.setData(data);
        responseResult.setCode(ResultEnum.SUCCESS.code);
        return responseResult;
    }

    public static ResponseResult error(ResultEnum resultEnum) {
        return error(resultEnum, resultEnum.message);
    }

    public static ResponseResult error(ResultEnum resultEnum, String message) {
        ResponseResult responseResult = new ResponseResult();
        responseResult.setCode(resultEnum.code);
        responseResult.setMessage(message);
        return responseResult;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

2. Define the interface response status code

Defining a set of common status codes is one of the core keys to unified result return. This approach not only improves the usability and maintainability of the API, but also enables clients to parse and process response data more efficiently, while also providing API developers with a clear and consistent standard to follow.

public enum ResultEnum {

    SUCCESS(200 ,"请求处理成功"),
    SERVICE_ERROR(500, "服务器异常,请稍后重试");

    public final Integer code;

    public final String message;

    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

3. Define a unified approach to success and failure

public class ResponseResult {

    private int code;

    private String message;

    private Object data;

    public static ResponseResult success(Object data) {
        ResponseResult responseResult = new ResponseResult();
        responseResult.setData(data);
        responseResult.setCode(ResultEnum.SUCCESS.code);
        return responseResult;
    }

    public static ResponseResult error(ResultEnum resultEnum) {
        return error(resultEnum, resultEnum.message);
    }

    public static ResponseResult error(ResultEnum resultEnum, String message) {
        ResponseResult responseResult = new ResponseResult();
        responseResult.setCode(resultEnum.code);
        responseResult.setMessage(message);
        return responseResult;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

4. Controller unified response results

@GetMapping("/testResult")
 public ResponseResult test() {
     // 模拟业务逻辑
     try {
         // 假设这里有一些业务逻辑
         return ResponseResult.success("success");
     } catch (Exception e) {
         // 捕获异常并返回错误信息
         return ResponseResult.error(ResultEnum.SERVICE_ERROR);
     }
 }

3. Unified exception handling

Unified exception handling uses a global exception handler to capture and handle exceptions thrown in the controller. This approach avoids writing duplicate exception handling code in each controller method and also makes the exception handling logic more centralized and easier to manage.

@RestControllerAdvice
@RestControllerAdvice is a composite annotation that is a combination of @ControllerAdvice and @ResponseBody. It is mainly used to provide global configuration for the controller layer, such as exception handling, data binding, data preprocessing, etc. Since it contains @ResponseBody, all methods processed by @RestControllerAdvice will write the return value to the HTTP response body by default and set the appropriate Content-Type.

@ExceptionHandler
The @ExceptionHandler annotation is used to mark a method that is used to handle exceptions thrown in the controller. When a method in a controller throws an exception, Spring will look for a method annotated with @ExceptionHandler that can handle the exception. If so, the method is called and its response is returned.

Notice

当使用@ControllerAdvice时,我们需要将@ResponseBody添加到异常处理方法上。
如果我们使用@RestControllerAdvice,就不需要添加。

1. Define business exception class

Unified exception classes can help you better manage errors and exceptions, making error handling throughout the system more consistent and predictable.

public class BusinessException extends RuntimeException{

    private final ResultEnum resultEnum;

    public BusinessException(ResultEnum resultEnum, String message) {
        super(message);
        this.resultEnum = resultEnum;
    }

    public BusinessException(ResultEnum resultEnum) {
        this(resultEnum, resultEnum.message);
    }


}

2. Global exception handler

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({BusinessException.class})
    public ResponseResult handleBusinessException(BusinessException businessException, HttpServletRequest request) {
        // 想处理的业务
        return ResponseResult.error(ResultEnum.SERVICE_ERROR, businessException.getMessage());
    }

    /**
     * 其他异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public ResponseResult handleOtherExceptions(Exception e) {
        // 这里可以根据不同的异常类型返回不同的状态码和消息
        // 但为了简单起见,这里只返回一个通用的错误信息
        return ResponseResult.error(ResultEnum.SERVICE_ERROR);
    }

}

3. Unified processing and use

@GetMapping("/testException1")
    public ResponseResult test1() {
        if (true) {
            // 业务场景
            throw new BusinessException(ResultEnum.SERVICE_ERROR);
        }

        return ResponseResult.success("success");
    }

Benefits of using unified exception handling

Code Reuse: Avoid writing similar response results and exception handling code in multiple places.

Easy to maintain: When you need to modify the response format or exception handling logic, you only need to modify it in one place.

Teamwork:Team members can more easily understand and follow unified coding standards.

Scalability: If you need to add new response types or exception handling logic, just expand on the existing ones.