@ControllerAdvice 统一处理controller异常

783 阅读2分钟

前言

以下内容保证都是来自生产一线的经验、客户真实反馈的需求,而不是自己妄想的理论。
仅适合有一定工程经验的人士查看,欢迎交流。

老规矩,有关@ControllerAdvice注解的使用,请自行google学习,这里我分享一下我在使用这个注解进行controller层异常统一处理的一些经验、心得。

前置知识

经典的web三层结构如下:

  1. dao(数据持久层,封装数据操作)
  2. service(封装业务逻辑)
  3. controller(对外服务层,参数检查、封装service结果)

因为controller层基本做的参数检查与结果封装的工作,因此每个controller方法的异常处理基本都是大同小异,无非就是:参数异常、权限异常等等,因此我们使用@ControllerAdvice来统一处理异常,减少代码的冗余。

代码品鉴

    private static final Integer MAX_MESSAGE_LEN = 25;
    private static final String DEFAULT_MESSAGE = "服务异常";

    @ExceptionHandler(Throwable.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseResponse handleAny(HttpServletRequest req, Throwable ex) {
        String message = ex.getMessage().length() > MAX_MESSAGE_LEN ? DEFAULT_MESSAGE : ex.getMessage();
        return new BaseResponse(ErrorCode.SYSTEM_ERROR.getCode(), message);
    }
  1. 为什么需要一个handleAny方法?

controller层需要一个处理任何异常的方法,避免直接将异常返回给前端

  1. 为什么要限制message的最大长度?

controller层的异常,一般都是我们自定义的参数异常、权限异常等等,message清晰明了。

但是如果是controller之下的dao层抛出了异常,比如唯一键重复的数据库异常,那message就会令用户比较难懂,会让客户(客户完全不懂技术)觉得一脸懵逼,不知道当前出了啥问题。

我们这样转化一次,对于长度过长的,直接就变成一个简洁的:后端异常。用户看到这个错误信息,心里就有谱了。

需求原因

  1. 我是什么情况下实现了这么一份代码,对message进行再处理?

后端某一次抛出了唯一键索引冲突的异常,然后大佬看到这个异常信息觉得很懵逼。

  1. 用户提出这个需求的动机猜测:

大佬们都不太喜欢有超出自己控制、自己不懂的东西。

我在使用这个东西,出现问题我得知道是个啥原因,可以直接跟客服(产品)说,你们后端出bug了,赶紧修。

补充

BaseReponse:

一般controller层结果,我们都会封装成如下的一个统一格式, 便于前端处理:

{
    "code":"异常编号",
    "message":"返回附加信息,一般就是异常信息",
    "data":"返回给前端的数据"
}