SpringBoot系列: Spring项目异常处理最佳实践
===================================
自定义异常类
===================================
稍具规模的项目, 一般都要自定义一组异常类, 这样做的好处是:
1. 可以充分利用异常的中断特性, 简化代码的逻辑控制.
2. 在自定义的异常类, 可以设置 BusinessErrorCode 和 error message, 有了统一的 BusinessErrorCode, 排查和联调沟通就更容易了.
Java 异常的 Root 是 Throwable, 其下有 Error 和 Exception. Error 是 JVM 级的致命错误, 应用系统内部一般不用关心这类错误. Exception 是异常的父类, 其下分为两类, 一类是 Runtime Exception, 一类是 Checked Exception. Checked Exception 是那些编译器能检查到的异常, 如果一个函数中抛出了这类异常, 我们要么 catch 它, 要么在函数签名上继续抛出去, 否则程序将不能编译通过.
Runtime Exception 有, 包括 RuntimeException 和它的子类. 比如 ArrayIndexOutOfBoundsException/ClassCastException/被 0 除等.
Checked Exception 有: Exception 类和所有非 RuntimeException 类的异常都属于 checked exception, 比如 IoException 等.
自定义异常类的基类如何选择?
自定义异常类应该继承自 RuntimeException 类, 原因有:
1. Spring 事务控制只支持 RuntimeException 类的异常.
2. 如果我们想要在函数加 throw Exception 签名, Java 语言已经提供了非常丰富的选择, 总能找到一个很合适的类, 而不需要再自定义一个.
===================================
自定义类的最佳实践:
===================================
1. 先定义一个基类 BusinessException, 继承自 RuntimeException.
2. 定义一套 BusinessErrorCode 枚举类型, 包含 BusinessErrorCode/HttpStatus/BusinessErrorMessage, 这里的 BusinessErrorCode 不同于 HttpStatus, 它是业务上的错误代码 (int 型).
2. 在 BusinessException 基类上, 加上绑定 BusinessErrorCode 枚举类型的机制.
3. 基于 BusinessException 定义一组子类, 比如 UserNotLoginException/PermissionForbiddenException/DataNotFoundException 等等, 并将这些子类加入到一个 BusinessExceptionEnum 枚举中, 方便使用.
===================================
Spring 项目数据验证最佳实践
===================================
1. 针对 UI 输入检查, 如果 js 前端检查有困难, 可以在 Controller 层使用 Pojo validation 手段做检查, 然后前端使用 ajax 拿到校验结果. 检查过程没有触发 UI 完整渲染, 用户体验会很好.
2. Controller 层使用 validation 进行检查, 可以在视图函数的形参上检查, 或者在视图函数内部检查.
3. Service 层, 使用 org.springframework.util.Assert 进行数据验证, 比如 Assert.notNull(user, "user is not null.");
4. DAO 层, 不做任何数据验证, 因为所有数据问题应该在Service层或Controller层做个验证.
===================================
Spring 各层封装的手法
===================================
1. DAO 层, 函数的形参最好以 DO 类做参数, 而不是传入很多个字段参数. 这样的好处是, 避免Table增删字段, DAO层函数定义也要跟着修改, 上层的调用代码也要修改.
2. DAO 层, insert 和 update 要独立为两个函数. 到底是新增还是更新, 应由 Service 层进行逻辑控制.
3. Service 层函数的形参, 到底是使用 DO 类, 还是简单的属性清单, 看具体情况吧.
===================================
Spring 日志和异常处理的最佳实践
===================================
异常处理的基本思路是: 早抛出, 晚捕获. 日志输出的基本思路是, 详尽但不冗余.
落实到具体的项目中, 在不同分层中, 应采用不同的规则, 一般的分层有: DAO -> Service -> Controller -> 统一异常 Controller 层.
1. DAO 层:
(1) 尽量不 catch 任何异常, 该向上抛就抛.
(2) 不用记录 log 日志, 或者仅使用 logger.debug() 记录
2. Service 层的做法:
(1) @Transactional 注解应该加在 Service 层上.
(2) 对于一些关键问题, 比如 Checked Exception 或者数据的问题, 应该及时 throw new BusinessException 异常, 以确保事务完整.
(3) throw new BusinessException 时的日志, 为了避免日志重复, 不需要 log 日志输出.
(4) Service 层一般的日志级别, 应该用 logger.debug() 记日志.
(5) Service 层函数的返回值应该是 Optional 类型, 方便 Controller 做 null 判断.
3. Controller 层:
(1) Controller 层负责组装 Service, 在关键步骤上应该加日志输出 (info 级别)
(2) Controller 层不应再主动 throw 异常.
4. 统一异常 Controller 层:
(1) 通过 json 或 UI 返回详细的报错信息, 包括 HttpStatus 和详尽的 BusinessErrorCode/BusinessErrorMessage 以及 DetailErrorMessage(来源于 exception.getMessage()), 甚至包括 exception 的 stack trace.
(2) 对于 Exception 类的异常, 说明这是我们预料之外的报错, 应该使用 logger.error() 级别记录;
(3) 对于 BusinessException 和子类的异常, 则说明我们的程序已经预料到了, 事物该回滚也已经回滚了, 所以应该以 logger.warn() 或 logger.info() 记录日志.
(4) 对于 Spring Boot 缺省的 /error 进行定制, 增加一些"系统主页"和"返回"的链接, 改善用户体验.
===================================
参考:
===================================
https://blog.csdn.net/aiyaya_/article/details/78725755
https://blog.csdn.net/aiyaya_/article/details/78989226
https://blog.qinchuan.io/experience/2018/10/11/spring-boot-restful-api-error-handling-in-practice.html
https://zhuanlan.zhihu.com/p/38114882
http://tengj.top/2018/05/16/springboot13/
SpringBoot系列: Spring项目异常处理最佳实践的更多相关文章
- Spring Boot Admin最佳实践
本文不进行Spring Boot Admin入门知识点说明 在Spring Boot Actuator中提供很多像health.metrics等实时监控接口,可以方便我们随时跟踪服务的性能指标.Spr ...
- 开涛spring3(7.5) - 对JDBC的支持 之 7.5 集成Spring JDBC及最佳实践
7.5 集成Spring JDBC及最佳实践 大多数情况下Spring JDBC都是与IOC容器一起使用.通过配置方式使用Spring JDBC. 而且大部分时间都是使用JdbcTemplate类(或 ...
- Java异常处理最佳实践
总结一些Java异常的处理原则 Java异常处理最佳实践 不要忘记关闭资源 在finally里关闭资源 public void readFile() { FileInputStream fileInp ...
- SpringBoot系列——自定义统一异常处理
前言 springboot内置的/error错误页面并不一定适用我们的项目,这时候就需要进行自定义统一异常处理,本文记录springboot进行自定义统一异常处理. 1.使用@ControllerAd ...
- Java异常处理最佳实践及陷阱防范
前言 不管在我们的工作还是生活中,总会出现各种“错误”,各种突发的“异常”.无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现.所以我们 ...
- OPEN(SAP) UI5 学习入门系列之二: 最佳实践练习(上)
这篇博文难产了很久,原来是打算一周更新一篇的,上周原计划写MVC,但是写了一半,发现带入了太多的细节,不太符合这个入门系列的主题. 当我们学习一个新的技能的时候,如果一开始就面对大量的细节,很容易陷入 ...
- OPEN(SAP) UI5 学习入门系列之二: 最佳实践练习(下)
上期我们完成了一个简单的主从页面,但是页面是静态的,不能交互,功能也很简单,只有一个销售订单的列表. 我们今天就一鼓作气把代码全都写完,由于本次的代码量较大,所以只对重点代码部分进行讲解. 具体每个文 ...
- go项目dockerfile最佳实践
1. 前言 2. 不需要cgo情况下的最佳实践 3. 依赖cgo情况下的最佳实践 1. 前言 这几天在构建golang编写的web项目中,关于dockerfile编写的一些总结 可能是单纯我比较菜(大 ...
- 【SpringMVC】SpringMVC系列15之SpringMVC最佳实践
15.SpringMVC最佳实践 15.1.遵循Restful API最佳实践 参考:http://segmentfault.com/a/1190000002949234 15.2.统一返回字段 15 ...
随机推荐
- Redis操作string
Redis简介: ''' redis: 缓存,例如两个个程序A,B之间要进行数据共享,A可以把数据存在redis(内存里),其他程序都可以访问redis里的数据, 这样通过中间商redis就实现了两个 ...
- 模块简介:(logging)(re)(subprocess)
''' logging模块: logging的日志可以分为 debug():Detailed information, typically of interest only when diagnosi ...
- 【Linux基础】查看某一端口是否开放(1025为例)
1.使用lsof 命令来查看端口是否开放 lsof -i:1025 //如果有显示说明已经开放了,如果没有显示说明没有开放 lsof(list open files)是一个列出当前系统打开文件的工具. ...
- ASP+中文显示之两种解决方法
作者刚開始写ASP+程序时候碰到的第一个比較大的问题就是中文显示问题,执行后发现ASP+从数据库中读 取出来的中文所有变成了?????,有点相似jsp中的这个频率出现最高的中文显示问题了,查了资料发 ...
- 20175229许钰玮 2018-2019-2《Java程序设计》结对编程项目-四则运算 第一周 阶段性总结
20175229许钰玮 2018-2019-2<Java程序设计>结对编程项目-四则运算 第一周 阶段性总结 需求分析 自动生成四则运算题目(加.减.乘.除). 既可以用前缀算法(波兰算法 ...
- 爬虫基础(三)-----selenium模块应用程序
摆脱穷人思维 <三> : 培养"目标导向"的思维: 好项目永远比钱少,只要目标正确,钱总有办法解决. 一 selenium模块 什么是selenium?seleni ...
- Xshell 连接Linux服务器自动中断问题
Xshell连接上Linux服务器后经常自动中断连接,报错如下图: 解决方法如下,进入/etc/ssh目录打开sshd_config文件,找到下图两个参数并设置下图所示的值: 重启sshd即可解决,如 ...
- 原生Ajax XMLHttpRequest对象
一.Ajax请求 - 现在常见的前后端分离项目中,一般都是服务器返回静态页面后浏览器加载完页面,运行script中的js代码,通过ajax向后端api发送异步请求获取数据,然后调用回调函数,将数据添加 ...
- Vue项目搭建与部署
Vue项目搭建与部署 一,介绍与需求 1.1,介绍 Vue 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue两大核心思想:组件化和数据驱动.组 ...
- Shell命令-文件及内容处理之head、tail
文件及内容处理 - head.tail 1. head:显示文件内容头部 head命令的功能说明 head 命令用于显示文件头部内容,默认执行 head 命令会输出文件开头的 10 行. head命令 ...