SpringBoot使用Validator校验框架

2023-10-27

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringBoot使用Validator校验框架 的相关文章

随机推荐

  • 蓝桥杯习题-砝码称重(动态规划)Python实现

    问题描述 你有一架天平和 N 个砝码 这 N 个砝码重量依次是 W1 W2 WN 请你计算一共可以称出多少种不同的重量 注意砝码可以放在天平两边 输入的第一行包含一个整数 N 第二行包含 N 个整数 W1 W2 W3 WN输出一个整数代表答
  • Android实现倒计时跳转和延时操作

    App启动页倒计时3秒跳转到App的首页 这种操作在很多App中都很常见 如果需要做一个延时操作呢 写一个子线程停留3秒然后执行操作 这样的话需要特别的注意的是UI操作必须放在主线程里 那么还需要转化成主线程 NO 使用Handler轻松实
  • 运维的最终目标是什么?

    序言 闲来无事 聊聊运维的终极目标 反正是瞎扯 毕竟么有风 天气还这么寒冷 思维不能灵动 不能起一丝波澜 歌曲不错 偶尔也可以听听 毕竟也是南征北战 风言风语 运维 从来都不能登上大雅之堂 WHY 纵观整个软件的开发周期 需求 设计 编码
  • 模板类重载>>(输入)和<<(输出)运算符

    在模板类中输入运算符 gt gt 和输出运算符 lt lt 的重载 使用友元在类内声明 在类外实现 include
  • C++模板与模板的重载

    include
  • Restful 多参数请求,包含中文解决办法-postman

    首先 要知道postman restful多参数请求的写法 http ip port user 参数值1 参数值2 参数值3 例如 http localhost 6666 user 如果爱 部 0000121 postman当遇到上述 ur
  • ANSIBLE大全

    运维自动化之ANSIBLE 本章内容 运维自动化发展历程及技术应用 Ansible命令使用 Ansible常用模块详解 YAML语法简介 Ansible playbook基础 Playbook变量 tags handlers使用 Playb
  • 查看 jvm 参数

    文章目录 VM 参数 jdk 提供的命令行参数 查看堆概要信息 VM 参数 XX PrintCommandLineFlags 可以打印出传递给虚拟机的显示和隐式参数 隐式参数未必是通过命令行直接给出的 它可能是由虚拟机启动时自行设置的 XX
  • 用递归法求n!(函数定义)

    用递归法求n 函数定义 include
  • C++中mutimap简单用法

    mutimap和map基本用法都是一样的 map中键值对中的键是唯一的 而mutimap中的键可以重复 mutimap在现实中也是很常用的 比如部门和员工的关系 mutimap和map的头文件都是 都是关联容器 都是需要通过迭代器来访问元素
  • P1018 [NOIP2000 提高组] 乘积最大

    题目 题目链接 题解 状态定义 dp i j 表示前i个数分成j段 即需要j 1个 的最大乘积 状态转移 dp i j max dp k 1 j 1 a k i dp i j 表示在第k 1和第k个数之间加上一个 得到的最大值 其中前k 1
  • yolov5模型在安卓android平台上部署(一)demo运行

    一 下载 配置 1 1 下载源文件 ncnn android yolov5下载传送门 Tencent ncnn下载传送门 下拉 下载该版本是因为自带vulkan加速 Android studio安装 Android studio下载传送门
  • 二叉树高度、结点个数、判断;

    1 二叉树的高度 2 二叉树的叶子结点个数 3 二叉树第k层的节点个数 4 判断节点是否在二叉树中 pragma once include
  • Vue将两个组件合并成一个

    使用webpack中的语法
  • 【官方教程】ChatGLM-6B 微调,最低只需 7GB 显存

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入 内容来自 GLM大模型 自3月14日开源以来 ChatGLM 6B 模型广受各位开发者关注 截止目前仅 Huggingface 平台已经有 32w 下载 Github Star
  • vue3 el-upload 上传附件及预览 限制只能上传一个图片或者pdf格式的文件

    vue3 el upload 上传附件及预览 限制只能上传一个图片或者pdf格式的文件 效果如图 直接看代码吧 template部分 div class file upload div
  • office全家桶_告别office“全家桶”,自定义选择组件安装,用户体验一级棒

    相信点进来看的朋友们对Office都不会陌生 在安装office的时候不知道大家有没有发现 就算是最便宜的一套 安装包里面除了Word Excel PowerPoint三兄弟之外 其中还还包含了Outlook Publisher Acces
  • 多行输入实现

    C while scanf d d a b 2 如果a和b都被成功读入 那么scanf的返回值就是2 如果只有a被成功读入 返回值为1 如果a和b都未被成功读入 返回值为0 如果遇到错误或遇到end of file 返回值为EOF 且返回值
  • 笔记——什么是鉴权

    前言 鉴权是自动化测试路上的拦路虎 故以此记录鉴权到底是怎么回事 一 什么是鉴权 为什么要鉴权 鉴权 是指验证用户是否有访问系统的权利 为什么要鉴权 对用户进行鉴权 防止非法用户占用网络资源 非法用户接入网络 被骗取关键信息 二 鉴权方式
  • SpringBoot使用Validator校验框架

    Hibernate Validator 简介 Hibernate Validator是Hibernate项目中的一个数据校验框架 是Bean Validation 的参考实现 Hibernate Validator除了提供了JSR 303规