spring boot统一异常处理

项目开发过程中,会遇到两种类型的异常情况,这里分开来讨论。

一、请求正确被分发了,但是处理请求过程中,出现异常。

这种情况,我们可以自定义一个Controller增强类,并加上@ControllerAdvice,要确保该注解能被Spring自动扫描到。

@Slf4j
@ControllerAdvice
public class BaseController {

    /**
     * 系统异常处理
     *
     * @param request Http请求
     * @param ex 异常对象
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    protected ApiResp exceptionProcess(HttpServletRequest request, Exception ex) {

        log.error("[System Exception] url: {}", request.getRequestURL().toString(), ex);
        return ApiResp
            .retFail(BaseError.SYSTEM_EXCEPTION.getCode(), BaseError.SYSTEM_EXCEPTION.getMsg());
    }
}

注意,如果是返回JSON的数据格式,该处理方法需要加上@ResponseBody注解。

另外,除了最后兜底的Exception外,还可以自定义特殊处理一些其他的异常,已给出更加精确的返回结果,例如,参数校验异常等等。

    /**
     * 参数校验异常
     *
     * @param request Http请求
     * @param ex 异常对象
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    protected ApiResp exceptionProcess(HttpServletRequest request, MethodArgumentNotValidException ex) {

        List<ObjectError> list = ex.getBindingResult().getAllErrors();
        List<String> detailMsg = Lists.newArrayList();
        for (ObjectError objectError : list) {
            detailMsg.add(objectError.getDefaultMessage());
        }

        int code = BaseError.SYSTEM_ARGUMENT_NOT_VALID.getCode();
        String msg = BaseError.SYSTEM_ARGUMENT_NOT_VALID.getMsg();
        ArgumentNotValidMsg data = new ArgumentNotValidMsg();
        data.setDetailMsg(detailMsg);

        log.info("[Method Args Exception] URL: {}, ERROR: {}", request.getRequestURL().toString(),
            StringUtils.join(detailMsg, ","));
        return ApiResp.retFail(code, msg, data);

    }

这样配置后,当出现参数校验不通过时,提示信息更明确,效果如下:

二,第二种情况是,请求没有被正确分发,比如请求地址404,或者权限不足等等。

这种情况下,SpringBoot内置了一个BasicErrorController来进行处理。但是其返回格式不满足我们的项目要求,所以实现ErrorController,重写里面的处理方法。

@RestController
@RequestMapping("/error")
public class ErrorHandleController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    private final ServerProperties serverProperties;

    @Autowired
    public ErrorHandleController(ErrorAttributes errorAttributes,
        ServerProperties serverProperties) {
        this.errorAttributes = errorAttributes;
        this.serverProperties = serverProperties;
    }

    @RequestMapping("")
    public ApiResp error(HttpServletRequest request, HttpServletResponse response) {

        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request));

        response.setStatus(HttpStatus.OK.value());

        int code = (int) body.get("status");
        String msg = "'" + body.get("path") + "' " + body.get("error");
        return ApiResp.retFail(code, msg);
    }

    @Override
    public String getErrorPath() {
        return "/error";
    }

    private Map<String, Object> getErrorAttributes(HttpServletRequest request,
        boolean includeStackTrace) {

        WebRequest webRequest = new ServletWebRequest(request);
        return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace);
    }

    private boolean isIncludeStackTrace(HttpServletRequest request) {

        ErrorProperties.IncludeStacktrace include = this.serverProperties.getError().getIncludeStacktrace();
        if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
            return true;
        }
        if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
            return getTraceParameter(request);
        }
        return false;
    }

    private boolean getTraceParameter(HttpServletRequest request) {

        String parameter = request.getParameter("trace");
        if (parameter == null) {
            return false;
        }
        return !"false".equals(parameter.toLowerCase());
    }
}

处理前效果:

处理后效果:

将默认的返回消息格式,转成了项目要求的自定义格式。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值