Elegant global exception handling method of Spring Boot project

preface

Exceptions are common in daily project development, but how to deal with exception information more efficiently and enable us to quickly locate bugs is very important. It can not only improve our development efficiency, but also make your code look more comfortable. The SpringBoot project has handled some exceptions, but it may not be suitable for our developers, Therefore, we need to capture and handle these exceptions uniformly.

1, Global exception handling method 1

In SpringBoot, @ ControllerAdvice can enable global exception handling. Using this annotation indicates that global exception capture is enabled. We just need to customize a method, use the @ ExceptionHandler annotation, and then define the type of exception captured to handle these captured exceptions uniformly.

1.1 custom global exception class

/**
 * @description: Custom exception handling
 * @author: DT
 * @date: 2021/4/19 21:17
 * @version: v1.0
 */
@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e){
        System.out.println("Global exception capture>>>:"+e);
        return "Global exception capture,Cause of error>>>"+e.getMessage();
    }
}

1.2 throw exception manually

 @GetMapping("/getById/{userId}")
public CommonResult<User> getById(@PathVariable Integer userId){
    // Throw exception manually
    int a = 10/0;
    return CommonResult.success(userService.getById(userId));
}

1.3 test printing

 

Obviously, the effect of such user experience is extremely poor. Although this can let us know the reasons for the abnormality, in many cases, it may not be humanized enough and does not meet our requirements.

2, Global exception handling method 2

2.1 defining basic interface classes

/**
 * @description: Service interface class
 * @author: DT
 * @date: 2021/4/19 21:39
 */
public interface BaseErrorInfoInterface {

    /**
     *  Error code
     * @return
     */
    String getResultCode();

    /**
     * Error description
     * @return
     */
    String getResultMsg();
}

2.2 defining enumeration classes

/**
 * @description: Exception handling enumeration class
 * @author: DT
 * @date: 2021/4/19 21:41
 * @version: v1.0
 */
public enum ExceptionEnum implements BaseErrorInfoInterface{
    
    // Data operation error definition
    SUCCESS("2000", "success!"),
    BODY_NOT_MATCH("4000","The requested data format does not match!"),
    SIGNATURE_NOT_MATCH("4001","The requested digital signatures do not match!"),
    NOT_FOUND("4004", "The resource was not found!"),
    INTERNAL_SERVER_ERROR("5000", "Server internal error!"),
    SERVER_BUSY("5003","The server is busy. Please try again later!");

    /**
     * Error code
     */
    private final String resultCode;

    /**
     * Error description
     */
    private final String resultMsg;

    ExceptionEnum(String resultCode, String resultMsg) {
        this.resultCode = resultCode;
        this.resultMsg = resultMsg;
    }

    @Override
    public String getResultCode() {
        return resultCode;
    }

    @Override
    public String getResultMsg() {
        return resultMsg;
    }
}

2.3 custom exception class

/**
 * @description: Custom exception class
 * @author: DT
 * @date: 2021/4/19 21:44
 * @version: v1.0
 */
public class BizException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    /**
     * Error code
     */
    protected String errorCode;
    /**
     * error message
     */
    protected String errorMsg;

    public BizException() {
        super();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface) {
        super(errorInfoInterface.getResultCode());
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.getResultMsg();
    }

    public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
        super(errorInfoInterface.getResultCode(), cause);
        this.errorCode = errorInfoInterface.getResultCode();
        this.errorMsg = errorInfoInterface.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 BizException(String errorCode, String errorMsg, Throwable cause) {
        super(errorCode, cause);
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }


    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    @Override
    public Throwable fillInStackTrace() {
        return this;
    }
}

2.4 user defined data transmission

/**
 * @description: Custom data transfer
 * @author: DT
 * @date: 2021/4/19 21:47
 * @version: v1.0
 */
public class ResultResponse {
    /**
     * Response code
     */
    private String code;

    /**
     * Response message
     */
    private String message;

    /**
     * Response results
     */
    private Object result;

    public ResultResponse() {
    }

    public ResultResponse(BaseErrorInfoInterface errorInfo) {
        this.code = errorInfo.getResultCode();
        this.message = errorInfo.getResultMsg();
    }

    public String getCode() {
        return code;
    }

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

    public String getMessage() {
        return message;
    }

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

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    /**
     * success
     *
     * @return
     */
    public static ResultResponse success() {
        return success(null);
    }

    /**
     * success
     * @param data
     * @return
     */
    public static ResultResponse success(Object data) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(ExceptionEnum.SUCCESS.getResultCode());
        rb.setMessage(ExceptionEnum.SUCCESS.getResultMsg());
        rb.setResult(data);
        return rb;
    }

    /**
     * fail
     */
    public static ResultResponse error(BaseErrorInfoInterface errorInfo) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(errorInfo.getResultCode());
        rb.setMessage(errorInfo.getResultMsg());
        rb.setResult(null);
        return rb;
    }

    /**
     * fail
     */
    public static ResultResponse error(String code, String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode(code);
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    /**
     * fail
     */
    public static ResultResponse error( String message) {
        ResultResponse rb = new ResultResponse();
        rb.setCode("-1");
        rb.setMessage(message);
        rb.setResult(null);
        return rb;
    }

    @Override
    public String toString() {
        return JSONObject.toJSONString(this);
    }

}

Custom global exception handling

/**
 * @description: Custom exception handling
 * @author: DT
 * @date: 2021/4/19 21:51
 * @version: v1.0
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * Handle custom business exceptions
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
        logger.error("Business exception occurred! as a result of:{}",e.getErrorMsg());
        return ResultResponse.error(e.getErrorCode(),e.getErrorMsg());
    }

    /**
     * Exception handling null pointer
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e){
        logger.error("Null pointer exception occurred! as a result of:",e);
        return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
    }

    /**
     * Handle other exceptions
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, Exception e){
        logger.error("Unknown exception! as a result of:",e);
        return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }
}

2.6 test code

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    //If the name is empty, a custom exception will be thrown manually!
    if(user.getName()==null){
        throw  new BizException("-1","User name cannot be empty!");
    }
    return true;
}

 @PutMapping("/update")
public boolean update(@RequestBody User user) {
    //Here, a null pointer exception is deliberately caused and is not handled
    String str = null;
    str.equals("111");
    return true;
}

 @DeleteMapping("/delete")
public boolean delete(@RequestBody User user)  {
    //An exception is deliberately created here and is not handled
    Integer.parseInt("abc123");
    return true;
}

If we want to catch this type conversion exception, can we add another exception handling method.

/**
* Handle type conversion exception
 * @param req
 * @param e
 * @return
 */
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e){
    logger.error("Type conversion exception occurred! as a result of:",e);
    return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}
PARAMS_NOT_CONVERT("4002","Incorrect type conversion!"),

In addition to the above data format, user-defined global exception handling can also handle page Jump. Just fill in the jump path on the return processing of the new exception method without using the ResponseBody annotation.

summary

Exception handling can reduce the repetition and complexity of code, is conducive to code maintenance, and can quickly locate bugs, which greatly improves our development efficiency.


Author: Chen Bai
Link: https://juejin.cn/post/6959520793063587848
Source: rare earth Nuggets
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.

 

 

Tags: Java Spring Spring Boot

Posted by Azala on Fri, 15 Apr 2022 10:02:15 +0930