SpringBoot系列-- SpringBoot自定义异常类封装

1. 项目环境

  • IDEA 2020.1.4
  • Maven 3.6
  • JDK 1.8
  • SpringBoot 2.x

项目文件在GitHub(欢迎star⭐):
https://github.com/Gang-bb/Gangbb-SpringBoot

注意:此节内容包含SpringBoot系列-- SpringBoot统一对象返回小节内容
SpringBoot系列-- SpringBoot统一对象返回
如有疑问或是建议,欢迎评论区留言或者QQ:949526365

2. 对Java异常的一些理解

  • CheckedException: 必须在编码时进行处理,不处理程序是无法通过编译的。可以向上throws抛出或者就地try/catch解决,比如记日志。(程序员可以处理)

    举例:1. B.C() B调用C方法,但C没有定义。 2. 读取文件,文件不存在。此时可能文件路径不对,改对就处理完成了

  • RunTimeException:运行时异常,可以通过编译,不强制要求要处理。

    举例:比如用户输入2000 id号。数据库找不到,就是一种RunTimeException

3. 处理异常

目标是每次返回的异常都是下面这种格式:

image-20210123095521770

3.1 定义统一异常类

public class ApiException extends RuntimeException{
    private final Integer code;
    private final String message;

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

    public ApiException(ApiExceptionEnum exceptionEnum) {
        this(exceptionEnum.getCode(), exceptionEnum.getMsg());
    }

    public Integer getCode() {
        return code;
    }

    @Override
    public String getMessage() {
        return message;
    }
}

3.2 定义全局异常拦截

import com.gangbb.gangbbspringbootexception.common.ApiRestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.ServletException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : Gangbb
 * @ClassName : GlobalExceptionHandler
 * @Description :
 * @Date : 2021/1/23 10:04
 */
//拦截异常注解 @ControllerAdvice表明这时一个异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {

    private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public Object handleHttpException(ServletException e) {
        log.error("ServletException: ", e);
        return ApiRestResponse.error(ApiExceptionEnum.HTTP_ERROR.getCode(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handleException(Exception e) {
        log.error("Default Exception: ", e);
        return ApiRestResponse.error(ApiExceptionEnum.SYSTEM_ERROR);
    }

    @ExceptionHandler(ApiException.class)
    @ResponseBody
    public Object handleFirstMallException(ApiException e) {
        log.error("ApiException: ", e);
        return ApiRestResponse.error(e.getCode(), e.getMessage());
    }

    /**
     * 参数校验异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ApiRestResponse handleMethodArgumentNotValidException(
            MethodArgumentNotValidException e) {
        log.error("MethodArgumentNotValidException: ", e);
        return handleBindingResult(e.getBindingResult());
    }
    //参数类型错误
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public Object handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.error("MethodArgumentTypeMismatchException: ", e);
        return ApiRestResponse.error(ApiExceptionEnum.PARAM_TYPE_ERROR.getCode(), "参数"+e.getName() + ":" + "字段类型错误");
    }
    //参数缺少
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public Object handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("MissingServletRequestParameterException: ", e);
        return ApiRestResponse.error(ApiExceptionEnum.PARAM_TYPE_ERROR.getCode(), e.getMessage());
    }

    private ApiRestResponse handleBindingResult(BindingResult result) {
        //把异常处理为对外暴露的提示
        List<String> list = new ArrayList<>();
        if (result.hasErrors()) {
            List<ObjectError> allErrors = result.getAllErrors();
            for (ObjectError objectError : allErrors) {
                String message = objectError.getDefaultMessage();
                list.add(message);
            }
        }
        if (list.size() == 0) {
            return ApiRestResponse.error(ApiExceptionEnum.REQUEST_PARAM_ERROR);
        }
        return ApiRestResponse
                .error(ApiExceptionEnum.REQUEST_PARAM_ERROR.getCode(), list.toString());
    }
}

3.3 测试使用

image-20210123101757499 image-20210123101857987

4. 后期迭代思路

  • 全局错误拦截类中,可以根据请求的Content-Type为json或html做不同处理。返回json或通用模板页面

  • 后期项目如果做大,错误码的定义可以用一个专门的配置文件记录,再通过一个类映射相应的值。可以方便国际化!

  • 关于错误码的定义和优化可以参照阿里开发手册中的一些设计思路。

    image-20210123102457804
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值