SpringBoot 添加全局异常统一处理代码

253 阅读2分钟

首先提供一个自定义异常,使用已定义好的错误码枚举ResultCode,用来在代码中对可预知的异常进行抛出处理。

package com.example.demo.exception;

import com.example.demo.result.ResultCode;
import lombok.Getter;

/**
 * 自定义异常
 * @auther wangbo
 * @date 2021-01-13 17:27
 */
@Getter
public class CustomException extends RuntimeException{

    private final ResultCode resultCode;

    public CustomException(ResultCode resultCode){
        super(resultCode.getMessage());
        this.resultCode = resultCode;
    }

}

接下来需要提供一个全局异常统一处理类,主要用到两个注解:@RestControllerAdvice@ExceptionHandler

package com.example.demo.exception;


import com.example.demovalidation.result.Result;
import com.example.demovalidation.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

import javax.validation.ConstraintViolationException;
import javax.xml.bind.ValidationException;

/**
 * 全局异常统一处理
 *
 * @author wangbo
 * @date 2021/05/12
 */
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerAdvice {

    /**
     * 通用异常处理
     */
    @ExceptionHandler(Exception.class)
    public Result<Void> exceptionHandler(Exception e) {
        log.error("通用异常处理", e);
        return Result.failure(ResultCode.PROGRAM_INSIDE_EXCEPTION);
    }

    /**
     * HTTP方法不支持的异常处理
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, WebRequest request) {
        log.info("HTTP方法不支持的异常处理");
        log.warn("http request method not support [{}] for [{}]", e.getMethod(), request.getDescription(false));
        return Result.failure(ResultCode.NOT_SUPPORT_METHOD);
    }

    /**
     * 自定义异常处理
     */
    @ExceptionHandler(CustomException.class)
    public Result<Void> customExceptionHandler(CustomException e) {
        log.info("自定义异常处理");
        return Result.failure(e.getResultCode());
    }

    /**
     * 请求体传参,参数校验结果异常处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.info("请求体传参,参数校验结果异常处理");
        BindingResult bindingResult = e.getBindingResult();
        FieldError fieldError = bindingResult.getFieldError();
        assert fieldError != null;
        return Result.failure(fieldError.getField() + " : " + fieldError.getDefaultMessage());
    }

    /**
     * URL传参,参数校验结果异常处理
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Void> constraintViolationExceptionHandler(ConstraintViolationException e) {
        log.info("URL传参,参数校验结果异常处理");
        return Result.failure(e.getMessage());
    }

    /**
     * 自定义参数校验过程异常处理
     */
    @ExceptionHandler(ValidationException.class)
    public Result<Void> validationExceptionHandler(ValidationException e) {
        log.error("参数校验过程异常处理", e);
        return Result.failure(ResultCode.PROGRAM_INSIDE_EXCEPTION);
    }
}

最后三个是有关参数校验的异常处理,在接口参数校验中会用到。

使用示例,直接进行抛出,抛出的异常会在全局异常处理类中统一进行处理:

@GetMapping("/list")
public List<User> list(){
    if (true){
    	//直接抛出异常,该自定义异常会被ExceptionHandlerAdvice类中的customExceptionHandler方法处理。
        throw new CustomException(ResultCode.REQUEST_PARAM_ERROR);
    }
    return userService.list();
}

这个接口会直接返回如下结果:

{
    "code":50002,
    "message":"请求参数错误",
    "data":null
}