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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于Spring Boot数据校验,可以使用Hibernate Validator来实现。Hibernate Validator是一个基于JSR 380规范的校验框架,可以方便地在Spring Boot应用中进行数据校验。 首先,需要在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> ``` 接下来,在需要校验的实体类上使用注解来定义校验规则。例如,可以使用`@NotBlank`注解来验证字符串不能为空,`@Min`和`@Max`注解来验证数字的范围,等等。示例如下: ```java public class User { @NotBlank(message = "用户名不能为空") private String username; @Size(min = 6, max = 20, message = "密码长度必须在6到20之间") private String password; @Email(message = "邮箱格式不正确") private String email; // getters and setters } ``` 在需要校验的Controller的请求参数上使用`@Valid`注解,然后通过`BindingResult`参数获取校验结果。示例如下: ```java @RestController public class UserController { @PostMapping("/users") public ResponseEntity<String> createUser(@Valid @RequestBody User user, BindingResult bindingResult) { if (bindingResult.hasErrors()) { // 处理校验失败的情况 StringBuilder errorMessage = new StringBuilder(); for (FieldError error : bindingResult.getFieldErrors()) { errorMessage.append(error.getDefaultMessage()).append(". "); } return ResponseEntity.badRequest().body(errorMessage.toString()); } // 校验通过,执行创建用户的逻辑 // ... return ResponseEntity.ok("用户创建成功"); } } ``` 这样,当请求参数不满足校验规则时,会自动返回校验失败的错误信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值