3. 分组校验一个vo对象在新增的时候某些字段为必填,在更新的时候又非必填。如上面的validvo中 id`` 和 appid 属性在新增操作时都是 非必填 ,而在编辑操作时都为 必填 ,name在新增操作时为 必填 ,面对这种场景你会怎么处理呢? 在实际开发中我见到很多同学都是建立两个vo对象,validcreatevo,valideditvo来处理这种场景,这样确实也能实现效果,但是会造成类膨胀。
其实validator校验框架已经考虑到了这种场景并且提供了解决方案,就是 分组校验 ,只不过很多同学不知道而已。
要使用分组校验,只需要三个步骤。
3.1. 第一步,定义分组接口public interface validgroup extends default { interface crud extends validgroup{ interface create extends crud{ } interface update extends crud{ } interface query extends crud{ } interface delete extends crud{ } }}这里我们定义一个分组接口validgroup让其继承javax.validation.groups.default,再在分组接口中定义出多个不同的操作类型,create,update,query,delete。
3.2. 第二步,在模型中给参数分配分组@datapublic class validvo { @null(groups = validgroup.crud.create.class) @notnull(groups = validgroup.crud.update.class, message = 应用id不能为空) private string id; @length(min = 6,max = 12,message = appid长度必须位于6到12之间) @null(groups = validgroup.crud.create.class) @notnull(groups = validgroup.crud.update.class, message = 应用id不能为空) private string appid; @notblank(message = 名字为必填项) @notblank(groups = validgroup.crud.create.class,message = 名字为必填项) private string name; @email(message = 请填写正确的邮箱地址) private string email; @enumstring(value = {f,m}, message=性别只允许为f或m) private string sex; @notempty(message = 级别不能为空) private string level;}给参数指定分组,对于未指定分组的则使用的是默认分组。
3.3. 第三步,给需要参数校验的方法指定分组@postmapping(value = /valid/add)public string add(@validated(value = validgroup.crud.create.class) validvo validvo){ log.info(validentity is {}, validvo); return test3 valid success;}@postmapping(value = /valid/update)public string update(@validated(value = validgroup.crud.update.class) validvo validvo){ log.info(validentity is {}, validvo); return test4 valid success;}这里我们通过value属性给add()和update()方法分别指定create和update分组
3.4. 测试post http://localhost:8080/valid/addcontent-type: application/x-www-form-urlencodedname=javadaily&level=12&email=476938977@qq.com&sex=fcreate操作在create时我们 没有传递id和appid参数 ,校验通过。
{ status: 100, message: 操作成功, data: test3 valid success, timestamp: 1652186105359}update操作使用同样的参数调用update方法时则提示参数校验错误
{ status: 400, message: id不能为空; 应用id不能为空, data: null, timestamp: 1652186962377}复制代码默认校验生效操作由于email属于默认分组,而我们的分组接口validgroup已经继承了default分组,所以也是可以对email字段作参数校验的。故意写错email格式
post http://localhost:8080/valid/addcontent-type: application/x-www-form-urlencoded/valid/update?name=javadaily&level=12&email=476938977&sex=f{ status: 400, message: 请填写正确的邮箱地址; id不能为空; 应用id不能为空, data: null, timestamp: 1652187273865}4. 业务规则校验业务规则校验指接口需要满足某些特定的业务规则,举个例子:业务系统的用户需要保证其唯一性,用户属性不能与其他用户产生冲突,不允许与数据库中任何已有用户的用户名称、手机号码、邮箱产生重复。 这就要求在 创建用户时需要校验用户名称、手机号码、邮箱是否被注册 ; 编辑用户时不能将信息修改成已有用户的属性 。最优雅的实现方法应该是参考 **bean validation** 的标准方式,借助自定义校验注解完成业务规则校验。
4.1. 自定义注解首先我们需要创建两个自定义注解,用于业务规则校验:
uniqueuser:表示一个用户是唯一的,唯一性包含:用户名,手机号码、邮箱@documented@retention(runtime)@target({field, method, parameter, type})@constraint(validatedby = uservalidation.uniqueuservalidator.class)public @interface uniqueuser { string message() default 用户名、手机号码、邮箱不允许与现存用户重复; class?[] groups() default {}; class? extends payload[] payload() default {};}notconflictuser:表示一个用户的信息是无冲突的,无冲突是指该用户的敏感信息与其他用户不重合@documented@retention(runtime)@target({field, method, parameter, type})@constraint(validatedby = uservalidation.notconflictuservalidator.class)public @interface notconflictuser { string message() default 用户名称、邮箱、手机号码与现存用户产生重复; class?[] groups() default {}; class? extends payload[] payload() default {};}4.2. 实现业务校验规则想让自定义验证注解生效,需要实现 constraintvalidator 接口。接口的第一个参数是 自定义注解类型 ,第二个参数是 被注解字段的类 ,因为需要校验多个参数,我们直接传入用户对象。 需要提到的一点是 constraintvalidator 接口的实现类无需添加 @component 它在启动的时候就已经被加载到容器中了。
@slf4jpublic class uservalidation implements constraintvalidator { protected predicate这里使用predicate函数式接口对业务规则进行判断。
4.3. 测试代码@restcontroller@requestmapping(/senior/user)@slf4j@validatedpublic class usercontroller { @autowired private userrepository userrepository; @postmapping public user createuser(@uniqueuser @valid user user){ user saveduser = userrepository.save(user); log.info(save user id is {},saveduser.getid()); return saveduser; } @sneakythrows @putmapping public user updateuser(@notconflictuser @valid @requestbody user user){ user edituser = userrepository.save(user); log.info(update user is {},edituser); return edituser; }}使用很简单,只需要在方法上加入自定义注解即可,业务逻辑中不需要添加任何业务规则的代码。
post http://localhost:8080/valid/addcontent-type: application/json /senior/user{ username : 100001}{ status: 400, message: 用户名、手机号码、邮箱不允许与现存用户重复, data: null, timestamp: 1652196524725}5. 总结通过上面几步操作,业务校验便和业务逻辑就完全分离开来,在需要校验时用@validated注解自动触发,或者通过代码手动触发执行,可根据你们项目的要求,将这些注解应用于控制器、服务层、持久层等任何层次的代码之中。 这种方式比任何业务规则校验的方法都优雅,推荐大家在项目中使用。在开发时可以将不带业务含义的格式校验注解放到 bean 的类定义之上,将带业务逻辑的校验放到 bean 的类定义的外面。这两者的区别是放在类定义中的注解能够自动运行,而放到类外面则需要像前面代码那样,明确标出注解时才会运行。
跨界融合将会是智能家居行业发展的未来趋势
预计2023年深度学习市场价值超181亿美元,复合成长率或达最高水平
艾拉比受邀参加 | 2023英飞凌生态创新峰会
W波段超外差LO两种倍频链路的比较
基于D161A语音卡实现的异系统智能转接装置
SpringBoot Web应用如何进行参数校验?(下)
嵌入式领域的各大专业厂商认证
美国国家仪器推出NI-XNET CAN和FlexRay嵌入式
线上直播 | 看“Cat1+蓝牙”王牌组合如何助力新能源应用持续发光
iPhone8什么时候上市最新消息:对比iPhone7S和iPhone8,差别竟这么大!
为无线模块选择天线的三大关键
超实用,如何亲自动手制作HDMI线?
[组图]RC振荡电路的几种接法
博势Proceq便携硬度计Equotip 550 UCI的优势介绍
自动化系统的网络安全
5G基本架构解析
物联网落地三大困境破解
“我的世界”创造里程碑,已经卖出超过 2,500 万套
国内前十大芯片制造公司排名盘点
网件正式发布全球首款WiFi6Mesh路由器 售价约合5000元人民币