[Java] How to write a global capture exception under SpringBoot?

foreword

In daily project development, exceptions are common, but how to handle exception information more efficiently so that we can quickly locate the BUG is very important. It can not only improve our development efficiency, but also make your code look more comfortable. The SpringBoot project has already handled certain exceptions, but it may not be suitable for our developers, so we need to capture and process these exceptions uniformly.

1. Global exception handling method 1

In SpringBoot, @ControllerAdvice can enable global exception handling. Use this annotation to indicate that the capture of global exceptions is enabled. We only need to use the @ExceptionHandler annotation in a custom method and define the type of caught exception to uniformly process these caught exceptions.

The @ControllerAdvice annotation is a new annotation in Spring 3.2. Its scientific name is the Controller enhancer . Its function is to add unified operations or processing to the Controller controller. For @ControllerAdvice, we are more familiar with the use of combination @ExceptionHandlerfor global exception handling, but its role is more than that. ControllerAdviceTaken apart, it is Controller Advice. Regarding Advice, in Spring's AOP, it is used to encapsulate all attributes of an aspect, including the entry point and the aspect logic that needs to be woven. ControllerAdviceThis can also be understood here .

1.1 Custom global exception class

/**
 * @description: 自定义异常处理
 */
@ControllerAdvice
public class MyExceptionHandler {
    
    

    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public String exceptionHandler(Exception e){
    
    
        System.out.println("全局异常捕获>>>:"+e);
        return "全局异常捕获,错误原因>>>"+e.getMessage();
    }
}

1.2 Manually throwing exceptions

 @GetMapping("/getById/{userId}")
public CommonResult<User> getById(@PathVariable Integer userId){
    
    
    // 手动抛出异常
    int a = 10/0;
    return CommonResult.success(userService.getById(userId));
}

1.3 Test printing

insert image description here
insert image description here

Obviously, such a user experience effect is extremely poor. Although this can let us know the cause of the abnormality, in many cases, it may not be humane enough to meet our requirements.

2. Global exception handling method 2

2.1 Define the basic interface class

/**
 * @description: 服务接口类
 */
public interface BaseErrorInfoInterface {
    
    

    /**
     *  错误码
     * @return
     */
    String getResultCode();

    /**
     * 错误描述
     * @return
     */
    String getResultMsg();
}

2.2 Define enumeration class

/**
 * @description: 异常处理枚举类
 */
public enum ExceptionEnum implements BaseErrorInfoInterface{
    
    
    
    // 数据操作错误定义
    SUCCESS("2000", "成功!"),
    BODY_NOT_MATCH("4000","请求的数据格式不符!"),
    SIGNATURE_NOT_MATCH("4001","请求的数字签名不匹配!"),
    NOT_FOUND("4004", "未找到该资源!"),
    INTERNAL_SERVER_ERROR("5000", "服务器内部错误!"),
    SERVER_BUSY("5003","服务器正忙,请稍后再试!");

    /**
     * 错误码
     */
    private final String resultCode;

    /**
     * 错误描述
     */
    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: 自定义异常类
 */
public class BizException extends RuntimeException{
    
    

    private static final long serialVersionUID = 1L;

    /**
     * 错误码
     */
    protected String errorCode;
    /**
     * 错误信息
     */
    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 Custom data transmission

/**
 * @description: 自定义数据传输
 */
public class ResultResponse {
    
    
    /**
     * 响应代码
     */
    private String code;

    /**
     * 响应消息
     */
    private String message;

    /**
     * 响应结果
     */
    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;
    }

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

    /**
     * 成功
     * @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;
    }

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

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

    /**
     * 失败
     */
    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);
    }

}

2.5 Custom global exception handling

/**
 * @description: 自定义异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    
    
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseBody
    public ResultResponse bizExceptionHandler(HttpServletRequest req, BizException e){
    
    
        logger.error("发生业务异常!原因是:{}",e.getErrorMsg());
        return ResultResponse.error(e.getErrorCode(),e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, NullPointerException e){
    
    
        logger.error("发生空指针异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.BODY_NOT_MATCH);
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    @ResponseBody
    public ResultResponse exceptionHandler(HttpServletRequest req, Exception e){
    
    
        logger.error("未知异常!原因是:",e);
        return ResultResponse.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
    }
}

2.6 Test code

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    
    
    //如果姓名为空就手动抛出一个自定义的异常!
    if(user.getName()==null){
    
    
        throw  new BizException("-1","用户姓名不能为空!");
    }
    return true;
}

insert image description here

 @PutMapping("/update")
public boolean update(@RequestBody User user) {
    
    
    //这里故意造成一个空指针的异常,并且不进行处理
    String str = null;
    str.equals("111");
    return true;
}

insert image description here

 @DeleteMapping("/delete")
public boolean delete(@RequestBody User user)  {
    
    
    //这里故意造成一个异常,并且不进行处理
    Integer.parseInt("abc123");
    return true;
}

insert image description here

If we want to catch this type conversion exception, is it necessary to add another legacy processing method?

/**
* 处理类型转换异常
 * @param req
 * @param e
 * @return
 */
@ExceptionHandler(value = NumberFormatException.class)
@ResponseBody
public ResultResponse exceptionHandler(HttpServletRequest req, NumberFormatException e){
    
    
    logger.error("发生类型转换异常!原因是:",e);
    return ResultResponse.error(ExceptionEnum.PARAMS_NOT_CONVERT);
}
PARAMS_NOT_CONVERT("4002","类型转换不对!"),

insert image description here

In addition to handling the above data formats, custom global exception handling can also handle page jumps. You only need to fill in the jump path in the return processing of the newly added exception method without using the ResponseBody annotation.

Summarize

Exception handling can reduce code repetition and complexity, facilitate code maintenance, and quickly locate bugs, greatly improving our development efficiency.

Guess you like

Origin blog.csdn.net/u011397981/article/details/131860239