当请求参数很多,几乎每一个参数都需要后端去兜底校验时,你还在写if else去判断参数是否为空吗??要校验为空的参数三四个还好,要是十几个,业务逻辑还没开始就写二三十行代码开始堆山了嘛,教给大家一个简单实用的方法,让大家不再在屎堆上堆代码。
注解篇
先来了解几个常用的注解
注解 | 含义 | 怎样使用 |
---|---|---|
@NotBlank | 字符串不为null且非空格长度至少为1 | 注解在String类型的参数上 |
@Null | 必须为null | 用于Long、Integer、BigDecimal基本数据类型上 |
@NotNull | 必须不为null | 用于Long、Integer、BigDecimal基本数据类型上 |
@NotEmpty | 集合不为null且长度>0 | 用于集合校验 |
@AssertTrue | 为true | 用于Boolean类型上 |
@AssertFalse | 为false | 用于Boolean类型上 |
@Max | 小于或等于某个数 | 一个字段的最大值为xx |
@Min | 大于或等于某个数 | 一个字段的最小值为xx |
@Digits(integer=3, fraction=2) | 整数和小数长度 | — |
@Pattern | 正则匹配 | 手机号规则校验等 |
@Range(min=,max=) | 数值类型范围 | — |
@Length | 字符串长度范围 | ---- |
实战篇
请求参数
BizRequestDTO
import lombok.Data;import org.hibernate.validator.constraints.NotBlank;import javax.validation.Valid;import java.util.Date;import java.util.List;@Datapublic class BizRequestDTO { /** * 单据编号 */ @NotBlank(message = "headId (单据编号)不能为空") private String headId;/** * 金额 */ @NotNull(message = "amount (金额)不能为空") private BigDecimal amount; /** * 提单人 */ @Valid private EmpInfoDTO submitter; /** * 分摊人列表 */ @Valid private List<EmpInfoDTO> expenseSharerList;}
注解释义 @Valid
作用于对象
,作用于集合
对象内校验方式:
@Valid private EmpInfoDTO submitter;
EmpInfoDTO
/** * 工号 */ @NotBlank(message = "工号不能为空") private String workNo; /** * 姓名 */ @NotBlank(message = "姓名不能为空") private String nickName;
在代码中如何写?
引入依赖
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.16.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
引入一个工具类
import org.hibernate.validator.HibernateValidator;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import java.util.Set;public class ValidatorUtils { private static final Validator DEFAULT_VALIDATOR; static { DEFAULT_VALIDATOR = Validation.byProvider(HibernateValidator.class) .configure() .buildValidatorFactory() .getValidator(); } public static <T> Set<ConstraintViolation<T>> validate(T bean) { return DEFAULT_VALIDATOR.validate(bean); }}
实际应用
public ResponseResult<String> checkExpenseParams(RequestParamDTO requestDTO) { Set<ConstraintViolation<TaeExpenseLineCheckRequestDTO>> result = ValidatorUtils.validate(requestDTO); // 错误信息输出 StringBuilder resultInfo = new StringBuilder(); result.forEach(validateResult -> resultInfo.append(validateResult.getMessage()).append("\n")); if (StringUtils.isNotBlank(resultInfo)) { return ResponseResult.error(resultInfo.toString()); } // 若为空则参数校验通过 return ResponseResult.ok(null); }
输出示例
headId (单据编号)不能为空
amount (金额)不能为空
校验模式配置
Hibernate可以对校验模式的配置,支持快速失败,即在校验的过程中只要有一项不同过,剩余的参数就不再进行校验。默认使用的是全部校验完成后再返回,也就是在上面的例子中展示的那样。开启快速失败的具体的实现方式:
Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) .buildValidatorFactory() .getValidator();
校验工具类
import org.hibernate.validator.HibernateValidator;import javax.validation.ConstraintViolation;import javax.validation.Validator;import javax.validation.Validation;import java.util.Set;public class ValidatorUtils { private static final Validator DEFAULT_VALIDATOR; private static final Validator FAST_VALIDATOR; static { DEFAULT_VALIDATOR = Validation.byProvider(HibernateValidator.class) .configure() .buildValidatorFactory() .getValidator(); FAST_VALIDATOR = Validation.byProvider(HibernateValidator.class) .configure() .failFast(true) .buildValidatorFactory() .getValidator(); } public static <T> Set<ConstraintViolation<T>> validate(T bean) { return DEFAULT_VALIDATOR.validate(bean); }public static <T> Set<ConstraintViolation<T>> fastValidate(T bean) { return FAST_VALIDATOR.validate(bean); }}
快速校验使用方式同上,输出示例
headId (单据编号)不能为空
对象级联校验
包含级联对象的类
对象级联校验意味着,在一个对象中的属性可以包含另外一个校验对象,被级联的对象需要用@Valid注解修饰。上面也有给出?,本节再详细讲解一下。
例:
import lombok.Data;import org.hibernate.validator.constraints.NotBlank;import org.hibernate.validator.constraints.Range;import javax.validation.Valid;import javax.validation.constraints.NotNull;import javax.validation.constraints.Pattern;@Datapublic class ValidatorWithDefineExtraModel { @NotBlank(message="姓名不能为空") private String name; @NotNull(message = "年龄不能为空") @Range(min=1, max=200, message = "年龄必须大于1小于200") private Integer age; @NotBlank(message="性别不能为空") @Pattern(regexp = "([FM])", message = "性别只能为F(女)或者M(男)") private String sex; @NotNull(message = "validatorModelExtra不能为空") @Valid private ValidatorModelExtra validatorModelExtra;}
被级联的对象
@Datapublic class ValidatorModelExtra { @NotNull(message = "地址不能为空") @Length(max = 100, message = "地址长度不能大于100个字符") private String address;}
输出示例:
地址不能为空