Springboot内置的工具类之Assert

前言

突然想起以前一个同事刚入项目的时候干过的一件有趣的事,入项分配给他的第一个开发任务,在项目里引入了几十个util工具类,据说是多年珍藏,有的还是自己写的,然后上灰度的时候发现各种的maven冲突,相信有很新手都干过类似的事吧。大部分的项目基本是ssh的框架,像一些断言、字符串、对象、集合、文件相关的工具类不可能还需要自己来封装,为什么呢?Spring家族生态这么茂盛,Spring以及其他一些框架技术内部的肯定少不了会用到断言、对象、集合、文件读取相关的操作方法,Spring都封装的这么好,这些小的内容大概率自己也会封装好。去找找源码,一看还真有。既然有,那就拿来用呗,基本不用担心有bug。当然如果不适合自己的需要,可以继承再重写呗,至少不用自己逞能搞了一堆,可能还有bug。后面陆续用几篇文章,一起学习这些工具类的用法。

org.springframework.util.Assert

断言是一个很普通的东西,用于数据的合法性检查,如果经常去看Spring的源码的话,会经常看到。举个例子:查询员工信息详情的时候,至少要传员工id或编号之类的一个唯一性标识,如果不传就抛出异常;保存员工信息的时候,要求员工编号一定不能为空;更新员工信息时,员工id一定不能为空;遍历员工信息集合时,集合一定不能为空,类似这些场景都可以用到断言。

但是实际的业务开发中,我发现很多人喜欢这样写:

kotlin 复制代码
@GetMapping("/info")
public ResResult employee(Integer id){
    if (null==id) {
       return ResResult.fail("查询员工详情时,id不能为空");
    }
    //查询员工详情然....
    return ResResult.success("");
}

其实这样写也不是不对,是不太优雅,其实可以用断言来写看起来会更好,编写Spring、mybaits的大佬们都是这样写的,所以经常看源码的另外一个好处就是可以向大神学习如何优雅的写代码:

Assert.isNull

用伪代码演示一下isNull的用法,正常情况下对外暴露查询员工基本信息时,一些敏感字段是不允许输出的,如果有类似的场景,可以这样写:

less 复制代码
@PostMapping("/baseInfo")
@PostMapping("/baseInfo")
public Employee baseInfo(@RequestBody Employee employee){
    //查询员工基本信息
    Employee result=new Employee();
    result.setRealName("zhangsan");
    result.setSex("男");
    result.setAddress("北京市东直门八大碗胡同11号");
    result.setPhone("155032718xx");
    result.setEmail("xxxxx@163.com");
    Assert.isNull(result.getAddress(), "员工家庭地址是敏感信息,输出基本信息时不能包含此字段");
    Assert.isNull(result.getPhone(), "员工手机号码是敏感信息,输出基本信息时不能包含此字段");
    Assert.isNull(result.getEmail(), "员工邮箱地址是敏感信息,输出基本信息时不能包含此字段");
    return result;
}

如果对外输出的员工基本信息的结果中,没有包含地址、手机号码、邮箱地址,则正常通过断言;如果包含有这些敏感信息,则为抛出异常信息并携带定制的异常提示;

Assert.notNull

在如保存员工信息等类似场景时,会要求某些字段不能空,这个时候可以这样写:

less 复制代码
@PostMapping("/save")
 public Employee save(@RequestBody Employee employee){
    Assert.notNull(employee.getEmpNo(), "保存员工信息时,请先给员工分配员工编号");
    //保存入库逻辑
    return employee;
}

如果保存员工信息时未给员工分配员工编号,则不能通过断言,并抛出异常,终止业务程序执行;如果保存员工信息时已经分配过员工编号,则通过断言继续向下执行;

Assert.isTrue

有时候也会遇到一些逻辑真判断,如:更新员工信息前,要先确认待更新员工是否存在,可以这样写:

less 复制代码
@PostMapping("/update")
 public Employee update(@RequestBody Employee paramObj){
     //查询员工是否存在,结果为false
     boolean isExist=false;
     Assert.isTrue(isExist, "待更新员工信息不存在,更新失败");
    return paramObj;
}

Assert.notEmpty

在对一些集合类参数校验非空校验的时候,可以使用Assert.notEmpty,如在遍历集合前需要校验集合不null并且有元素的时候:

csharp 复制代码
public void iterEmployeeList(){
    List<Employee> list = new ArrayList<>();
    Assert.notEmpty(list, "员工信息集合为null或集合内无任何元素,遍历失败");
    for (Employee employee : list) {
        System.out.println(employee.getRealName());
    }
}

如果遍历的集合是null或集合内没有任何元素,则不能通过断言,终止程序执行并抛出异常;如果遍历集合至少有一个元素,则继续执行遍历操作;

总结

可以这么理解断言:在输出结果后,对结果集定义一个期望值,如果满足了期望值,则正常通过断言;如果不满足期望值,则会触发断言,触发断言的结果就是会抛出一个IllegalArgumentException异常,这个异常属于运行时异常。最后,再搞一个异常的统一处理,简直不要太完美。

typescript 复制代码
 @RestControllerAdvice
public class CommonExceptionHandler {
         @ExceptionHandler(value = IllegalArgumentException.class)
        public String illegalArgumentException(IllegalArgumentException e){
            //统一异常处理可以捕获到该异常,并统一处理
            String message = e.getMessage();
        return message;
    }
}

另外断言肯定不止这几个,这里只是对用到频率比较高的作一个抛砖引玉,更多更好玩的断言使用可以从org.springframework.util.Assert类探索一翻。

Springboot扩展点系列实现方式、工作原理集合:

Springboot扩展点之ApplicationContextInitializer

Springboot扩展点之BeanDefinitionRegistryPostProcessor

Springboot扩展点之BeanFactoryPostProcessor

Springboot扩展点之BeanPostProcessor

Springboot扩展点之InstantiationAwareBeanPostProcessor

Springboot扩展点之SmartInstantiationAwareBeanPostProcessor

Springboot扩展点之ApplicationContextAwareProcessor

Springboot扩展点之@PostConstruct

Springboot扩展点之InitializingBean

Springboot扩展点之DisposableBean

Springboot扩展点之SmartInitializingSingleton

Springboot核心功能工作原理:

Springboot实现调度任务的工作原理

Springboot事件监听机制的工作原理

相关推荐
一 乐10 分钟前
校务管理|基于springboot + vueOA校务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·spring
摇滚侠25 分钟前
面试实战 问题三十四 对称加密 和 非对称加密 spring 拦截器 spring 过滤器
java·spring·面试
xqqxqxxq26 分钟前
Java 集合框架之线性表(List)实现技术笔记
java·笔记·python
L0CK34 分钟前
RESTful风格解析
java
程序员小假43 分钟前
我们来说说 ThreadLocal 的原理,使用场景及内存泄漏问题
java·后端
何中应1 小时前
LinkedHashMap使用
java·后端·缓存
tryxr1 小时前
Java 多线程标志位的使用
java·开发语言·volatile·内存可见性·标志位
talenteddriver1 小时前
java: Java8以后hashmap扩容后根据高位确定元素新位置
java·算法·哈希算法
云泽8081 小时前
STL容器性能探秘:stack、queue、deque的实现与CPU缓存命中率优化
java·c++·缓存