在上一节STEP8.1 统一返回封装中,我们设计了自己的返回实体,并作了一次访问正确流程的试验。在本节中,我们主要着眼于异常流程的部分,来研究一下如何对异常情况作出统一的处理。
首先来自定义一个异常枚举类,在这个类里可以维护我们的各种运行时异常信息:
EnumExceptionType.java
public
在类的开头处"PARAM_ILLEGAL(1000, "参数非法")"就是我们当前已经设计好的一个异常情况,它的异常状态码是1000,含义是“参数非法”。我们也可以定义各种其他的异常写在这里,例如USER_NOT_EXISTS(1001,"用户不存在")等等。
然后再来为我们的Result类加两个方法,是利用EnumExceptionType来生成对应的返回信息:
public
最后是我们的关键部分:写一个统一异常处理的类
import
在解释整个代码逻辑之前,先简单提一下gson,不知道你是否还记得。如果你不记得了,也没关系,只要知道我们在这里用它来把java对象转化成json字符串而已。如果你还想好好回忆一下gson,传送门:
孑辞:STEP6.3 GSON库zhuanlan.zhihu.com接下来解释下代码。整个代码的含义简单来说就是:
通过@RestControllerAdvice来指定这是我们整个项目的统一异常处理器;
通过@ExceptionHandler(value = Exception.class)来指定Controller层抛出的所有Exception异常都会被defaultErrorHandler方法处理。
而defaultErrorHandler方法的两个参数:
- HttpServletRequest request
这其实就是我们用户在访问我们后台服务时,传进来的http请求信息。简单来说,它包含了cookie会话信息(什么是会话?STEP4.3 会话)还有请求参数(比如@RequestParam指定的参数)等。
- Exception e
这就是我们统一异常处理器捕获的由我们的Controller抛出的异常。
而对于我们defaultErrorHandler方法里的具体内容,基本上通过注释就可以理解了。我们主要做了这几件事:
- 把用户传进来的参数取出来打印
- 把捕获的异常情况打印
- 对于不同的异常进行一些额外的自定义处理(可有可无)
- 最后返回Result实体(返回给前端或者用户)
最后简单梳理一下我们的逻辑:
我们的Controller层如果抛出了异常,会由我们的GlobalExceptionHandler捕获,进入我们的统一异常处理方法defaultErrorHandler里。在这个方法中,我们做一些处理操作,例如打印参数、打印异常信息等等,最后把结果返回。
那么打印出来有什么用呢?当然就是帮助我们进行错误排查了,简单点说就是方便我们debug。
让我们来简单做一个示例:
MyController.java
import
MyService.java
public
MyServiceImpl.java
import
最后运行项目,利用我们的postman来做一下测试:
我们看到这里的返回信息,也就是我们异常处理代码中最后返回的内容:
return
这里补一个tip,可能我们会产生一个疑问:
直接在Controller里把异常捕获掉,然后打印信息不可以吗?为什么需要建一个统一异常处理类呢?
其实很简单,无非就是提升代码的复用性。同时,统一异常处理也帮助我们进行解耦,让Controller层无需关心如何处理异常,而是在发生异常时只要将它抛出就可以了。
而在下一节中,我们会以把日志输出到文件的形式来替换打印,这样的话,在项目部署到线上之后,我们也可以通过日志文件进行在线的异常排查。
最后附我们的项目地址:
exception-handle