基于SpringBoot 设计业务逻辑异常统一处理

在我们平时的项目研发过程中,异常一般都是程序员最为头疼的问题,异常的抛出、捕获、处理等既涉及事务回滚,还会涉及返回前端消息提醒信息。那么我们怎么设计可以解决上面的两个的痛点呢?我们可不可以统一处理业务逻辑然后给出前端对应的异常提醒内容呢?

本章目标

基于 平台构建业务逻辑异常统一处理,异常消息内容格式化。

简书SpringBoot 企业级核心技术学习专题

构建项目

我们将逻辑异常核心处理部分提取出来作为单独的 供其他模块引用,创建项目在 项目 添加公共使用的依赖,配置内容如下所示:

项目创建完成后除了 、 、 保留,其他的都删除。

异常处理核心子模块

我们创建一个名为 的子模块,在该模块内自定义一个 运行时异常类,继承 并重写构造函数,代码如下所示:

在重写的构造函数内需要传递两个参数 、 ,其目的是为了初始化类内的全局变量。

:该字段是对应的异常码,我们在后续文章内容中创建一个存放异常错误码的枚举,而 就是枚举对应的字符串的值。

:这里是对应 字符串含义描述时所需要的参数列表。

:格式化后的业务逻辑异常消息描述,我们在构造函数内可以看到调用了 ,这个方法作用是通过异常码在数据库内获取未格式化的异常描述,通过传递的参数进行格式化异常消息描述。

创建异常核心包的目的就是让其他模块直接添加依赖,那异常描述内容该怎么获取呢?

定义异常消息获取接口

我们在 模块内添加一个接口 ,该接口提供通过异常码获取未格式化的异常消息描述内容方法,接口定义如下所示:

在需要加载 依赖的项目中,创建实体类实现 接口并重写 方法我们就可以通过 获取实现类实例进行操作获取数据,下面我们在编写使用异常模块时会涉及到。

格式化异常消息工具类

下面我们再回头看看构造函数格式化异常消息工具类 ,该工具类内提供 方法用于获取格式化后的异常消息描述,代码实现如下所示:

注意:由于我们的工具类都是静态方法调用方式,所以无法直接使用 注解注入的方式获取 实例。

由于无法注入实例,在 方法内,我们通过工具类 来获取 上下文实例,再通过上下文来获取指定类型的 ;获取到 实例后调用 方法,根据传入的 就可以直接从接口实现类实例中获取到未格式化的异常描述!

当然实现类可以是以 、 、 、 作为数据来源。

获取到未格式化的异常描述后通过 方法以及传递的参数直接就可以获取格式化后的字符串,如:

具体的格式化特殊字符含义可以去查看 文档,如何获取 上下文对象,请访问第三十二章:如何获取SpringBoot项目的applicationContext对象查看。

我们再回到 构造函数内,这时 字段对应的值就会是格式化后的异常消息描述,在外部我们调用 方法就可以直接得到异常描述。

到目前为止,我们已经将 模块代码编码完成,下面我们来看下怎么来使用我们自定义的业务逻辑异常并且获取格式化后的异常消息描述。

异常示例模块

基于 我们来创建一个名为 的子模块项目,项目内需要添加一些额外的配置依赖,当然也需要将我们的 依赖添加进入, 配置文件内容如下所示:

下面我们来配置下我们示例项目 文件需要的配置,如下所示:

在上面我们有讲到 获取的内容可以从很多种数据源中读取,我们还是采用数据库来进行读取,建议正式环境放到 缓存内!!!

异常信息表

接下来在数据库内创建异常信息表 ,语句如下:

我们通过 来实现数据读取,下面对应数据表创建对应的 。

异常信息实体

异常信息数据接口

在数据接口内通过 方法查询方式,通过 读取异常信息实体内容。

在开发过程中异常跑出时所用到的 一般存放在枚举类型或者常量接口内,在这里我们选择可扩展相对来说比较强的 ,代码如下:

异常码枚举内容项是需要根据数据库异常信息表对应变动的,能够保证我们在抛出异常时,在数据库内有对应的信息。

LogicExceptionMessage实现类定义

我们在 核心模块内添加了 接口定义,需要我们实现该接口的 方法核心模块,这样才可以获取数据库内对应的异常信息,实现类如下所示:

在 方法内通过 数据接口定义的 方法获取指定异常吗的异常信息,当存在异常信息时返回未格式化的异常描述。

统一返回实体定义

对于接口项目(包括前后分离项目)在处理返回统一格式时,我们通常会采用固定实体的方式,这样对于前端调用接口的开发者来说解析内容是比较方便的,同样在开发过程中会约定遇到系统异常、业务逻辑异常时返回的格式内容,当然这跟请求接口正确返回的格式是一样的,只不过字段内容有差异。 统一返回实体 如下:

在 实体内,采用了 的构造者设计模式 注解,配置该注解的实体会自动在 文件内添加内部类实现设计模式,部分自动生成代码如下:

到目前为止,我们并未添加全局异常相关的配置,而全局异常配置这块,我们采用之前章节讲到的 来实现, 相关的内容请访问第二十一章:SpringBoot项目中的全局异常处理。

全局异常通知定义

我们本章节仅仅添加业务逻辑异常的处理,具体编码如下所示:

最近技术群内有同学问我,既然我们用的是 为什么这里还需要配置 ?这里给大家一个解释,我们控制器通知确实是监听的 ,而 注解的控制器统一都是返回 格式的数据。那么我们在遇到异常后,请求已经不再控制器内了,已经交付给控制器通知类,那么我们通知类如果同样想返回 数据,这里就需要配置 注解来实现。

我们来看上面 方法,该方法返回值是我们定义的统一返回实体,目的是为了遇到业务逻辑异常时同样返回与正确请求一样的格式。

配置了将要处理 类型的异常,也就是只要系统遇到 异常并且抛给了控制器,就会调用该方法。

配置了返回的状态值,因为我们遇到业务逻辑异常前端肯定需要的不是500错误,而是一个200状态的 业务异常描述。

在方法返回时使用 并将异常消息传递给 方法,这样就实现了字段 的赋值。

测试

异常相关的编码完成,下面我们来创建一个测试的控制器模拟业务逻辑发生时,系统是怎么做出的返回? 测试控制内容如下所示:

根据上面代码含义,当我们在访问 时就会发生 业务逻辑异常,按照我们之前的全局异常配置以及统一返回实体实例化,访问后会出现 格式 数据,下面我们运行项目访问查看效果。 界面输出内容如下所示:

而在控制台由于我们编写了日志信息,也同样有对应的输出,如下所示:

如果业务逻辑异常在 层时,我们根本不需要去操心事务回滚的问题,因为 本身就是运行时异常,而项目中抛出运行时异常时事务就会自动回滚。

我们把业务逻辑异常屏蔽掉,把 改成 查看正确时返回的格式,如下所示:

如果想把对应的 改成空字符串,请访问查看第五章:配置使用FastJson返回Json视图。

总结

本章将之前章节的部分内容进行了整合,主要是全局异常、统一格式返回等;这种方式是目前我们公司产品中正在使用的方式,已经可以满足平时的业务逻辑异常定义以及返回,将异常消息存放到 中我们可以随时更新提示内容,这一点还是比较易用的。

本章源码已经上传到码云: SpringBoot配套源码地址:https://gitee.com/hengboy/spring-boot-chapter SpringCloud配套源码地址:https://gitee.com/hengboy/spring-cloud-chapter SpringBoot相关系列文章请访问:目录:SpringBoot学习目录 QueryDSL相关系列文章请访问:QueryDSL通用查询框架学习目录 SpringDataJPA相关系列文章请访问:目录:SpringDataJPA学习目录,感谢阅读!

加入知识星球,恒宇少年带你走以后的技术道路!!!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180629G0AU2D00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券