springBoot自定义异常Exception 非传统做法

在开始之前还是带着问题为啥要自定义异常,我的这种自定义异常方案跟大部分方案有何不同,肯定有跟我类似的,但是我是没发现。。。

首先是为什么要自定义异常,任何程序都不能保证不出bug,尤其是web程序,如果出现异常没有友好的提示是不行的,直接返回后台的一堆500错误代码也是不安全的,而且异常有时候也不可控,比如突然数据库连接中断了,突然除数为0了,突然空指针异常了,等各种,程序员呢也是人,不可能任何逻辑都写得天衣无缝不出一点bug,程序报错有bug不要紧,但如何友好的输出异常并提示这也是系统设计比较重要的事情。

相信很多码友都用过各种系统或者软件,用着用着就点不动了,也不提示错误,也没任何反应,到底是啥问题也不知道,是不是很恼火呢?对于普通用户来说体验更差了,这就是没做好异常处理的问题,无论后端发生任何问题都需要给予操作者一个提示,这才是体验好的系统。

我这里的自定义异常方案和传统的异常自定方案有着很大的不同,包括我这么多年参与的系统都是用传统的自定义异常方案和提示,举一个例子,比如第一个用户在前端要删除一条记录,在当时查询的时候,这条记录是可以被删除的,有删除按钮,可是在这时有第二个人对这条记录进行了锁定,也就是不允许删除了,第一个用户按下了删除按钮后台就会提示此用户已经锁定无法删除,这种提示只有后端才能返回,或者返回自定义状态码,传统的自定义异常就是直接请求200正常,然后返回一个json对象{code: 622, msg: "此用户已经锁定", data: {}}这是传统的方式,相信很多码友都是这样返回的,但是这个返回有一个很大的弊端,就是请求状态http状态是200成功,前端如果用ajax或者axios请求,是不能在ajax异常里面捕获的而得在success中做if判断,判断code是多少,然后再取msg提示,是不是很不优雅,虽然可以对ajax等做拦截封装,匹配code提示,但是也不合理。

而且这种还有一个弊端就是,后端controller返回的数据格式得用一个模型统一封装,也就是controller里面的每个方法的返回值都得封装成前端统一的格式,而且很多系统都是这样做的,如果在做微服务调用就发现更不合理了,我认为异常是异常但不能放在200的请求成功里面进行提示,包括已知异常和未知异常,都不应该放在请求成功而且返回什么code,msg这种json串然后给前端判断,都是不合理的。

下面就说说我的设计方式

从图中可以看到后台报错,不管是已知和未知错误都会抛出异常跟正确的返回结果是完全不一样的,而且http状态码也不是200,这样前端ajax或者axios的异常拦截就能直接处理,而无需做if判断,而正确的状态码200则只返回需要的数据,json格式,不添加任何的什么code,msg等,我认为是无意义的,code和msg应该是属于后端返回的提示应该是属于异常的一部分,都已经请求200了还给提示干嘛?有人可能会说,那保存成功,删除失败,这种提示呢?这种提示也不应该放在200里面,像保存成功如果后端请求200前端就可以直接提示保存成功了,也不需要后端返回,直接看状态码就行了,如果是删除失败后端应该是直接抛出异常,那状态码就不是200了,直接就被前端异常机制捕获了,多合理。

下面就具体实践下怎么在springBoot中实现这种方案

1、在项目中创建一个exception包,新建三个自定义异常类

全局异常

资源找不到异常

警告提示

2、新建一个处理器包,handler,用于rest异常的处理

rest异常捕获和自定义返回结果

3、在model包中新建一个ErrorModel和一个枚举类ErrorStatus

错误模型

错误状态

4、修改UserServiceImpl业务实现类,抛出自定义异常

使用自定义异常

5、修改UserController对异常进行捕获

6、启动项目进行测试

如果为1就给与提示异常

如果为3,除数不能为0,全局异常自动捕获

如果id存在则直接返回结果

7、文章源码地址

码云:https://gitee.com/apgblogs/springBootStudy/tree/exception/

这样设计,只要是200那就是前端想要的数据,不是200那就是异常,前端就很方便处理,而且后端也不需要对返回结果封装,不仅方便还提高开发效率,如果有啥更好的方法可以在评论区留言,如果我这个设计有啥满足不了需求的也可以告诉我。

发表评论