springboot 全局异常处理器

1、GlobalExceptionHandler  全局异常处理拦截器,捕获400,405和自定义等controller之后的异常

import com.dm.exception.BSException;
import com.dm.model.Result;
import com.dm.model.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.net.BindException;

/**
 * 解决Controller之后的异常
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({HttpMessageNotReadableException.class, MissingServletRequestParameterException.class, BindException.class,
            ServletRequestBindingException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class})
    public Result handleHttpMessageNotReadableException(Exception e) {
        log.error("------err------Bad Request: " + e.getMessage(), e);
        return new Result(StatusCode.BAD_REQUEST, "参数解析失败");
    }

    /**
     * 405 - Method Not Allowed
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("------err------Method Not Allowed: " + e.getMessage(), e);
        return new Result(StatusCode.METHOD_NOT_ALLOWED, "不支持当前请求方法");
    }

    /**
     * 自定义异常在此捕获
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Throwable.class)
    public Result handleException(Throwable e) {
        log.error("------err------Service Run Exception: " + e.getMessage(), e);
        if (e instanceof BSException) {
            return new Result(((BSException) e).getCode(), ((BSException) e).getMsg());
        }
        return new Result(StatusCode.SYSTEM_ERR, "服务器运行异常");
    }
} 

注意:自定义异常在方法handleException中进行捕获

2、FrontErrHandler,404异常是全局异常捕获不到的,所以放在FrontErrHandler进行处理

import com.dm.model.Result;
import com.dm.model.StatusCode;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 解决Controller之前的异常
 */
@RestController
@Slf4j
@Api(tags = "FrontErrHandler", description = "FrontErrHandler相关接口")
public class FrontErrHandler implements ErrorController {
    @Override
    public String getErrorPath() {
        return "/error";
    }

    @GetMapping(value = "/error")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Object error(HttpServletRequest request, HttpServletResponse response) {

        log.error("------err------Response Error,HttpCode: " + response.getStatus());

        // 错误处理逻辑
        int status = response.getStatus();
        if (status == 404) {
            return new Result(StatusCode.REQUEST_NOT_FOUND, "访问地址不存在");
        } else if (status == 500) {
            return new Result(StatusCode.SYSTEM_ERR, "服务器运行异常");
        } else if (status >= 100 && status < 200) {
            return new Result(StatusCode.HTTP_ERROR_100, null);
        } else if (status >= 300 && status < 400) {
            return new Result(StatusCode.HTTP_ERROR_300, null);
        } else if (status >= 400 && status < 500) {
            return new Result(StatusCode.HTTP_ERROR_400, null);
        } else {
            return new Result(StatusCode.SYSTEM_ERR, "服务器运行异常");
        }
    }
}

3、捕获到异常以后将返回结果统一封装到Result中,封装Result时有两种方式,

1)采用普通返回码,如返回正常,400,500等可以直接从普通返回码类中拿CODE进行返回的直接封装

return new Result(StatusCode.OK, "添加成功")
return new Result(StatusCode.SYSTEM_ERR, "服务器运行异常"); 

2)从自定义异常中拿到code和msg封装最终返回,code和msg来自异常枚举

return new Result(((BSException) e).getCode(), ((BSException) e).getMsg());

3)Result定义

import io.swagger.annotations.ApiModel;

/**
 * 返回结果实体类
 */
@ApiModel(description = "Result",value = "Result")
public class Result<T> {

    private Integer code;//返回码
    private String message;//返回消息

    private T data;//返回数据

    public Result(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = (T)data;
    }

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

    public Result() {
        this.code = StatusCode.OK;
        this.message = "执行成功";
    }

    public Integer getCode() {
        return code;
    }

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

    public String getMessage() {
        return message;
    }

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

    public T getData() {
        return data;
    }

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

4)普通返回码定义

/**
 * 普通返回码
 */
public class StatusCode {

    public static final int OK = 200;//成功
    public static final int SYSTEM_ERR = 500;//服务器运行异常
    public static final int REQUEST_NOT_FOUND = 404;//访问地址不存在
    public static final int HTTP_ERROR_100 = 100;//1XX错误
    public static final int HTTP_ERROR_300 = 300;//3XX错误
    public static final int HTTP_ERROR_400 = 400;//4XX错误
    public static final int HTTP_ERROR_500 = 500;//5XX错误

    public static final int BAD_REQUEST = 407;//参数解析失败
    public static final int METHOD_NOT_ALLOWED = 405;//不支持当前请求方法
}

4、exception目录下定义异常类和异常枚举

1)自定义异常类

public class BSException extends RuntimeException {

    private int code;
    private String msg;

    public BSException(ErrorEnum errEnum, Exception e) {
        super(e);
        this.code = errEnum.getCode();
        this.msg = errEnum.getMsg();
    }

    public int getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

2)自定义异常枚举

/**
 * 自定义异Enum
 */
public enum ErrorEnum {

    //CUSTOM_EXCEPTION(6007, "自定义异常7"),
    CUSTOM_EXCEPTION(6008, "自定义异常8");

    private final Integer code;
    private final String msg;

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    ErrorEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

5、自定义异常的使用

    /**
     * 根据ID查询BsCategory
     */
    @Override
    public BsCategory findById(Integer id) {
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            log.info("...err:::{}", e.getMessage());
            throw new BSException(ErrorEnum.CUSTOM_EXCEPTION,e);
        }
        return bsCategoryMapper.selectById(id);

    } 

6、总结

通过两个全局异常处理器将controller之前和之后的异常全部捕获到,然后通过Result通过封装结果进行返回,利用自定义异常和枚举来定义自己想要处理的异常。

原文地址:https://www.cnblogs.com/songjn/p/13438514.html