程序地带

SpringBoot使用Validator校验框架


Hibernate Validator 简介

Hibernate Validator是Hibernate项目中的一个数据校验框架,是Bean Validation 的参考实现,Hibernate Validator除了提供了JSR 303规范中所有内置constraint 的实现,还有一些附加的constraint。


Hibernate Validator 作用
数据校验逻辑和业务代码分离,程序解耦性提高统一且规范的校验格式,规避了大量重复的数据校验代码精力更加集中于业务代码
Hibernate Validator 使用

项目中,主要通过接口API的接口入参校验和封装工具类在代码中使用两种方式


引入jar包
<!-- 使用SpringBoot框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 直接引用jar包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.9.Final</version>
</dependency>
Java对象添加约束

级联校验需要添加@Valid注解


import com.ai.chinapost.crm.mdb.mgr.common.ValidateGroup;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.Valid;
import java.util.List;
/**
* @date 2021/01/11
*/
@Data
public class CltMktOccuAndIncmBO {
/**
* 保存或修改标识 1:保存 2:修改
*/
@NotBlank(message = "保存或修改标识不能为空" ,groups = ValidateGroup.CltMktOccuAndIncm.class)
private String saveOrUpdate;
/**
* 更新人编码
*/
@NotBlank(message = "更新人编码必填" ,groups = ValidateGroup.CltMktOccuAndIncm.class)
private String updatedByUserCode;
/**
* 更新人所属机构编码
*/
@NotBlank(message = "更新人所属机构编码必填" ,groups = ValidateGroup.CltMktOccuAndIncm.class)
private String updatedByOrgCode;
/**
* 统计时间
*/
@NotBlank(message = "统计时间必填" ,groups = ValidateGroup.CltMktOccuAndIncm.class)
private String statisDate;
@Valid
private List<CltMktOccuAndIncmDetailBO> cltMktOccuAndIncmDetailList;
}
校验组设置
/**
* @date 2020/7/21
*/
public interface ValidateGroup {
interface CltMktOccuAndIncm {
}
}
API接口入参校验
定义接口   接口入参需要添加@Validated注解,进行参数校验
@PostMapping("/saveDist")
@ResponseBody
public ResponseEntity dist(@Validated(ValidateGroup.CltMktOccuAndIncm.class) @RequestBody TrgtMktOcBase entity) throws CommonException {
ResponseEntity resp = distTrgtFacadeConsumer.dist(entity);
return resp;
}
postMan测试结果
请求报文:
{
"saveOrUpdate": "",
"updatedByUserCode": "20000",
"updatedByOrgCode": "100",
"statisDate": "",
"cltMktOccuAndIncmDetailList": [
{
"provId": "",
"provName": "安徽"
},
{
"provId": "370000",
"provName": "山东"
}
]
}
响应报文:
{
"code": 400,
"message": "statisDate:统计时间必填 saveOrUpdate:保存或修改标识不能为空 cltMktOccuAndIncmDetailList[0].provId:省份编码必填 参数值有误"
}
封装工具类校验
工具类中的Validator对象有两种方式获取(选其一即可)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.Validator;
/**
* @date 2021/01/13
*/
@Component
public class ValidatorConfig {
@Bean(name = "validator")
@Primary
public Validator validator() {
return new LocalValidatorFactoryBean();
}
}
import lombok.Data;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* 校验工具类
*
* @date 2021/01/13
*/
@Component
public class ValidationUtil implements ApplicationContextAware {
private static final ValidationUtil Instance = new ValidationUtil();
public static ValidationUtil getInstance() {
return Instance;
}
private static Validator validator;
// 结合ValidatorConfig类通过Spring容器获取
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ValidationUtil.validator = (Validator) applicationContext.getBean("validator");
}
// 直接通过Validation类获取对象
// 开启快速结束模式 failFast (true)
private static Validator validator1 = Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
/**
* 校验对象
*
* @param obj bean对象
* @param groups 校验组,必须是一个接口
* @param <T>
* @return Optional<ValidResult>
*/
public <T> Optional<ValidResult> validateBean(T obj, Class<?> groups) {
ValidResult result = Instance.new ValidResult();
Set<ConstraintViolation<T>> violationSets = validator.validate(obj, groups);
if (CollectionUtils.isEmpty(violationSets)) {
return Optional.empty();
}
for (ConstraintViolation<T> violation : violationSets) {
result.addError(violation.getPropertyPath().toString(), violation.getMessage());
}
return Optional.of(result);
}
/**
* 校验对象的某一个属性
*
* @param obj bean对象
* @param propertyName 属性名称
* @param <T>
* @return Optional<ValidResult>
*/
public <T> Optional<ValidResult> validateProperty(T obj, String propertyName) {
ValidResult result = Instance.new ValidResult();
Set<ConstraintViolation<T>> violationSets = validator.validateProperty(obj, propertyName);
if (CollectionUtils.isEmpty(violationSets)) {
return Optional.empty();
}
for (ConstraintViolation<T> violation : violationSets) {
result.addError(violation.getPropertyPath().toString(), violation.getMessage());
}
return Optional.of(result);
}
@Data
public class ValidResult {
/**
* 错误信息
*/
private List<ErrorMessage> errors;
public ValidResult() {
this.errors = new ArrayList<>();
}
/**
* 获取所有验证信息
*
* @return 集合形式
*/
public List<ErrorMessage> getAllErrors() {
return errors;
}
/**
* 获取所有验证信息
*
* @return 字符串形式
*/
public String getErrors() {
StringBuilder sb = new StringBuilder();
for (ErrorMessage error : errors) {
sb.append(error.getPropertyPath()).append(":").append(error.getMessage()).append(" ");
}
return sb.toString();
}
public void addError(String propertyName, String message) {
this.errors.add(new ErrorMessage(propertyName, message));
}
}
@Data
private class ErrorMessage {
private String propertyPath;
private String message;
public ErrorMessage() {
}
public ErrorMessage(String propertyPath, String message) {
this.propertyPath = propertyPath;
this.message = message;
}
}
}
测试代码

也可不指定分组(groups),会默认使用Default.class分组


public ResponseEntity saveCltMktOccuAndIncm(String params) {
// 校验参数
Class cltMktOccuAndIncm = ValidateGroup.CltMktOccuAndIncm.class;
CltMktOccuAndIncmBO cltMktOccuAndIncmBO = JSON.parseObject(params, CltMktOccuAndIncmBO.class);
Optional<ValidationUtil.ValidResult> validResult = ValidationUtil.getInstance().validateBean(cltMktOccuAndIncmBO, cltMktOccuAndIncm);
if (validResult.isPresent()) {
ValidationUtil.ValidResult errMessage = validResult.get();
return ResponseEntity.fail(ResponseEnum.DATA_ERROR, errMessage.getErrors());
}
return cltMktOccuAndIncmFacade.saveOrModifyCltMktOccuAndIncm(cltMktOccuAndIncmBO);
}
测试结果
响应报文:
{
"code": 400,
"message": "statisDate:统计时间必填 saveOrUpdate:保存或修改标识不能为空 cltMktOccuAndIncmDetailList[0].provId:省份编码必填 参数值有误"
}
其他常用的constranint
@AssertFalse @AssertTrue 检验boolean类型的值
@DecimalMax @DecimalMin 限定被标注的属性的值的大小
@Digits(intege=,fraction=) 限定被标注的属性的整数位数和小数位数
@Future 检验给定的日期是否比现在晚
@Past 校验给定的日期是否比现在早
@Max 检查被标注的属性的值是否小于等于给定的值
@Min 检查被标注的属性的值是否大于等于给定的值
@NotNull 检验被标注的值不为空
@Null 检验被标注的值为空
@Pattern(regex=,flag=) 检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配
@Size(min=,max=) 检查被标注元素的长度
@Valid 递归的对关联的对象进行校验

文章借鉴处


https://www.jianshu.com/p/0bfe2318814f

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Little1Pudding/article/details/112689513

随机推荐

用go写一个docker(4)-linux的namespace(上)

​温馨提示:之后环境使用的系统如无特殊说明,都是用Linux,代码要在Linux上跑,在Windows或macos上是跑不起来的。这里使用的内核...

小卡车7号 阅读(235)

Hadoop完全分布式运行模式

Hadoop环境的搭建1.配置克隆主机的环境(1)准备虚拟机(最小化安装Linux-模板机)(2)对模板机进行数据初始化配置(登录root用户)--ip地址要进行修改[root@hadoop1...

神龙龙 阅读(173)

【十大排序算法系列】冒泡排序

写在前面之前学习了初始的数据结构,数组,链表,树,堆栈,队列等。现在开始更新一些排序算法。常见的十大排序算法有:冒泡...

嘘,一般人我不告诉他 阅读(778)