00:00
前面我们测试了一下数据校验,但是现在还有一个问题,就是后来我们很多业务里边的这些新增修改都需要加入我们这些校验功能,而且这一块代码又是重复的,每一个上来都要检查它是否校验成功了,如果不成功提交这些数据,如果成功了才执行业务逻辑提交成功,这样做呢太麻烦了,我们可以做一个统一的处理,这要统一处理该怎么做呢?我们在这来写一个集中处理所有异常的类,那这个类呢,就要使用到我们spring mvc为我们提供的controller advice功能,我们来到这个主程序,这基本的校验呢,我们就可以使用了。第四个我们现在要做一个统一的异常处理,这个统一异常处理可以使用MVC提供的controller advice功能,它的使用步骤呢,我们来给大家说一下,首先第一步我们来抽取一个异常处理类。
01:00
我们假设呢,将这个类全部放在我们这个异常处理包下边,我们就叫exception。在这里边呢,我们来写一个叫controller advice,鼓励没有异常exception controller advice。我们把它呢,标注一个注解叫ant controller advice。它的作用就是来统一处理异常的,而且呢,我们看到它也标注了at component这个注解,说明它也是一个组件,而且我们这个controller advice是处理哪些controller出现的异常,我们可以在这用一个属性叫base packages我们来告诉他,所以我们这个里边,这个controller里边任何人出现的异常我都处理,那既要处理这个异常,我们就可以让这些controltrler将数据校验错误的异常抛出去。
02:02
想要抛出去其实非常简单,我们写了帮ing result,那就是接收异常了,我不写帮ing result,那它一校验出错了,异常就会被抛出去,所以呢,我的这一块代码最终就变成了非常干净,我把这儿放到这儿,我把bonding result呢蛀掉了,就是这一块的bonding result我们不用了,不用了,不去感知这些错误处理的异常了,那出现异常它自然就会抛出去,我们把这段代码呢注释一下。我们只在这儿考虑正确的逻辑,那出异常以后,所有的异常我们都希望它来感知,它的作用就是集中处理所有异常。怎么集中处理呢?我们只需要来编写一个方法,这个方法呢,我先来写VO,我们来处理一个handle数据校验的异常,比如我们就叫valid exception。所有数据校验相关的异常我们都放在这处理,那我怎么要感知这些异常?结合一个注解叫exception handler,这个注解告诉spring mvc,我们这个集中的异常处理器类,这个方法呢,能处理什么异常?我们在这可以来写一个异常类,我们在这来指定我们能处理什么异常,用VALUE6来指定,这是一个数组,相当于能处理很多异常,那VALUE6我们来指定呢?我先来指定一个exception,那就是所有异常那都能处理了,那我怎么感知这个异常?我们只需要在参数位置编写一个参数。
03:33
它的类型叫exception,那由controller给我们抛过来的异常,比如我们在这儿数据校验的时候,我们品牌在这儿校验失败了,由这个controller po来的异常就会来到我们这儿交给我们,那我们在这儿就相当于能感知到,我们可以日志记录一下这个异常,想要日志记录,我们导了long back,我们只需要用一个注解叫cell附接,然后呢,我们在这log.error,我们来记录一下,记录什么呢?我们说数据校验出现问题,出现什么问题,我们把这个异常原因打印一下,我们1.getmessages,包括我们出现问题这个异常类型,异常类型我们也可以打印一下,看一下数据校验错误是什么,异常类型1.getclass,而这一块的返回值,如果我们能处理页面,比如,我们可以返回一个model and view。
04:33
相当于呢,我们去跳转一个页面,但是我们现在都是返回杰森数据,所以我我还是返回一个R,那将所有的这个异常信息呢,我们给他返回return,像以前一样返回哪个字段出现什么异常,但我们现在好像没法知道到底刚才抛的这个异常,哪些字段出了什么异常,那我就先来返回一个L放在这,由于这个东西啊要以杰son出方式写出去,所以我们给它标注response body注解,包括呢,我们以后所有的异常处理方法都要将这个数据以杰森的方式写出去,我们就可以给这类上标注response body注解,那要给类上标注responsibility注解了,那就又有一个新的注解叫rest controller advice,它的作用我们可以看一下,其实就是controller advice和responsibility的合体,那我们有了它。
05:26
我把这个复制来,上边这两个那就可以不用了。我们这个统一的异常处理类,我们就写好了,我们在这来测试一下。好,现在我们来发送请求,Send。还没启动完全,我们再顺一下。好,我们发现呢,响应的是500未知异常,为什么是未知异常,那就是来到我们这儿了,而且我们这个log a也已经有打印了,我们数据校验出现了问题,这个问题是什么问题?第一个我们打印的是错误消息,这个错误消息挺长的。
06:00
有这么一长串,然后呢,我们还打印了一个异常的类型,异常类型是method argument not valued异常,所以我们这个方法就成功启动处理异常了,那为了能真正的感知到这些数据,校验错误异常,那我们就把这个异常精确一点,我们就说这个方法就是处理这个异常的,那就是处理这个异常的,那既然是这个异常,我们通过这个异常看能不能获取到具体的信息,1.get,我们在get呢,我们发现直接有一个帮ing result,那就相当于我们拿到了。这个数据校验的错误结果,我们通过这个结果还是像之前的那段代码一样,我们先拿到所有的错误消息,我们直接get field errorrows,我们进行一通遍历,那们将所有的字段错误们全部遍历出来,Item,那么这个field errorrow呢?我们将每一个错误我们都放进这个map里边,最终返回string string,那么这个就叫a map等于new,一个哈希map。
07:07
那么这个map里边呢,就给它去来放哪个字段,出现了哪个异常,我们怎么知道哪个字段,那只需要从F的AR里边。点一个get,这是我们校验错误的字段,以及这个字段错误的提示,error.get defat message,那放完了以后呢,我们直接r.L那错误呢,比如我们假设也叫400,我们都叫数据校验出现问题,包括真正的问题内容,我们给它put放到data里边。来提示我们的前端,如果前端给我们发请求了,来提示他们。就是这个错误,Map里边封装了所有的字段,错误提示,好来return一下。我们现在来重新测试一下,还是这个name logo ABC,我们来点一个send。
08:01
好,现在的这个响应就回到以前我们需要的这种模型了,那我们最终呢,就用统一的异常处理来替换在每一个controller处来编写我们这个数据校验的逻辑。当然统一的异常处理呢,能处理非常多的异常,这是我们第一种异常,以后呢,我们有更多其他的异常,我们都可以来处理,那我再来写一个其他的公共方法,我们就叫handle exception。它的最大特点呢,就是如果我们出现了异常,能精确匹配上这个异常,那就启动这一块处理,如果不能精确匹配,那么就来到最大的这个异常处理,那么这一块我直接给它能处理exception,我们直接来一个throughable,能处理任意类型的异常,我们直接把这个异常呢给这一放,所有其他任何出现的异常,那我们全部都先给他,给一个默认返回error。
09:04
包括我们后来业务会出现各种各样的异常,那我们推荐大家在编码的时候呢,如果有什么问题就放心大胆的自己把异常抛出去,对于异常的所有处理,我们统一用这个controller advice来感知,感知到异常以后,我们在这进行封装返回,但是由于后来我们的业务代码众多,业务逻辑众多,我们这一块的业务的这个异常状态嘛,这就会非常有用了,我们系统中给钱呢,会返回各种各样的扣的状态码。前端就要根据文档来判断我们这个状态码是什么问题,该怎么解决,这都是我们公司累积的一些规范与解决方案,那这个状态码呢,我们推荐大家这么来做,我这儿呢给大家了一个文档,这个状态码呢,我们推荐写五位数字,这五位数字呢,前两位表示我们的业务场景,比如一零,那就是通用的一些错误格式校验错误,服务器内部异常等等等等,那一一,比如是商品模块一,二是订单模块一,三是购物车模块一,四是物流等等等等,前两位呢是我们模块编码,后三位是我们错误代码,比如001是系统未知异常,002是参数校验错误等等,那么最终系统呢,就希望用他们规范起来,而且每一种错误代码到底是什么样的错误,有他的错误描述,我们可以将它们呢,以枚举的方式展示出来,那举一个例子,以后所有处理错误啊,我这个扣就不写死了,这些错误状态码。
10:40
是我们公司统一规定的,比如我们把它放在common里边,因为很多其他服务都依赖common,都要用公共的错误状态码,那就放在这,我们把它呢放到exception里边,我们来创建一个包,那就叫exception这个包,这个包里边呢,有一些业务的这些状态码,那么比如叫杯子code。
11:02
它呢,我们推荐做成一个枚举,我们把它变成一个枚举,这个业务状态码呢,有非常多的状态码,比如按照要求我们有数据校验错误等等等等,我把这一块复制过来,我们系统的这些状态码就是来这么来定义,那么来先来定义第一个枚举,比如参数校验有问题,我们就叫valid exception。这个参数校验问题呢,假设状态码就是10000001吧,好,它的提示呢就是。参数格式校验失败。这是我们定义的第一个状态码,第二个业务状态码,比如我们系统未知异常,On no exception,比如我们定义的是10000。我们就叫系统未知异常,我们将它们的定义过来,枚曲最大的特点呢,它其实是一个私有构造器,我们拿它来封装我们这个状态码,首先我们第一个是一个inte code,我们的状态码,或者我们直接来写都行,还有我们string的message。
12:15
我们的提示消息,我们来编写我们的构造器,杯子扣枚举这个构造器,这个构造器呢,接收两个参数。编写出这个枚举。那这两个枚举呢,其实就相当于这个类的两个对象,好this.code第一个枚举传来100,那它的这个状态码呢,我们给它保存一下,那就是这个100,然后呢,包括它的提示消息点message等于传过来的在构造时用的message,包括我们后来还要经常获取这个code以及message,所以呢,我给他编上这个get code方法以及get message方法。那以后controller advice在处理的时候,我们这数据校验出现的错误,那我们就这么来写,我们就叫b code,枚举点一个,我们现在是一个va的exception数据校验错误,校验错误的状态码我们用我们系统规定的,校验错误的提示消息我们也用我们系统规定的,自己就不写了。第一个。
13:20
Get message,包括其他的这些错误状态码,我们就用系统规定的,比如默认呢,都是no exception,第2GET code,然后提示消息,那都是base code没取的。No exception get message,那相当于对它做了一个抽取和封装来重新启动。那以后我们会有越来越多的业务状态码在这进行加入。如果出现错误。我们就在这儿会统一处理,那现在来看一下我们的效果。还是数据校验,以前呢叫数据校验出现问题,我们现在来点一个send。
14:03
好,现在的状态码是10001,参数格式校验失败,失败的参数,包括他们的提示,我们都在这儿返回了,那至此呢,我们这个统一异常处理我们就结束了。
我来说两句