类似JDBC规范
,Java提出Jsr-303规范
用于数据校验
,hivernate-validator
是Jsr303规范的实现
。
Spring-mvc集成了hibernate-valdator,支持自动校验。
🌳JSR-303 - 校验注解
Jsr-303提供了很多校验注解
,如下
注解 | 说明 |
---|---|
@NotNull | 不是null |
@NotEmpty | 不为空 |
@Length | str长度 |
@Min、@DecimalMin | 数值最大值 |
@Max、@DecimalMax | 数值最小值 |
@Range、@DecimalRange | 数值范围 |
@Size | 集合大小 |
@Past | 过去date |
@Feature | 未来date |
@Pattern | 正则格式 |
另外,还有@Valid
、@Validated
、@Constraint
注解 | 作用 |
---|---|
@Valid | 用在param上 ,表示校验(不支持分组校验 )。用在Field上 ,表示嵌套校验 。 |
@Validated | 用在param上,表示校验(支持分组校验)。用在Controller 上,表示校验基本类型 。 |
@Constraint | 自定义校验注解指定ConstraintValidator |
🌾基本类型 - 校验
对于基本类型校验
,步骤如下
- 配置
MethodValidationPostProcessor后置处理器
- 在
Controller上使用@Validated注解
(参数上不加@Valid或者@Validated)
1️⃣ 配置MethodValidationPostProcessor
<!--- 数据校验 - MethodValidationPostProcessor - 用于支持基本类型校验 -->
<bean id="methodValidationPostProcessor"
class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor" />
2️⃣ 在Controllter上添加@Validated。
/*
* 数据验证 - JSR303
* */
@Controller
@Validated
public class ValidateController {
/*
* MARK 基本类型验证 - 解决方案 - 配置MethodValidationPostProcessor
*
* 1. 配置MethodValidationPostProcessor - MethodValidation后置处理器
* 2. 在Controller上添加@Validated
* */
@GetMapping("/validate2")
@ResponseBody
public String validate1(@RequestParam("username") @Length(min = 7,message = "name min is {0}") String username){
return "基本类型验证";
}
}
🍀 Pojo类型 - 校验
Pojo类型校验,直接在Param上添加@Valid或者@Validated
,对于校验结果
- 可以
使用BindingResult接收校验结果
- 不用BindingResult,
校验出错,抛出400错误
/*
* MARK 实体类校验 - @Valid
* MARK 嵌套校验
*
* @Valid - 用在requestMapping方法上
* @Valid - 用在Field上,表示嵌套校验 (@Valided不能用在Field)
* BindResult - 接收校验结果
* - hasErrors()
* - getFieldErrors()
* - getField()、getRejectedValue()、getDefaultMessage()、getCode()
* */
@GetMapping("/validate1")
@ResponseBody
public String validate2(@Valid User user,BindingResult bindingResult){
printBindResult(bindingResult);
return "验证成功";
}
private void printBindResult(BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
System.out.println(fieldError.getField()); // 字段名称
System.out.println(fieldError.getRejectedValue()); // 提供的值
System.out.println(fieldError.getDefaultMessage()); // 错误信息
System.out.println(fieldError.getCode()); // 错误信息
System.out.println("===================================");
}
}
}
🌱 嵌套校验
对于嵌套校验
,把对应Pojo的Field使用@Valid标注
,就可以实现嵌套校验
。
@Data
public class User {
@Valid
private Car car;
}
🌴分组校验
分组校验
步骤如下
- 给
Pojo类提供校验组
。对于通用校验
写一个BaseGroup.class,然后不同的组去继承BaseGroup
。 - 校验时,给
@Validated提供groups属性
1️⃣ 给Pojo提供校验注解
和校验组
@Data
public class User {
/*
* 分组校验 - 组别
* */
public interface InsertGroup extends AllGroup{}
public interface UpdateGroup extends AllGroup {}
public interface AllGroup{}
/*
* 分组验证测试 - 分组验证
* */
@Min(value = 12,message = "最小是#{value}",groups = InsertGroup.class)
@NotNull(groups = InsertGroup.class)
private Integer id;
/*
* 所有验证 - 因为InsertGroup和UpdateGrop实现了AllGroup,对于@Validated(InserGroup)会验证该Field
* */
@Min(value = 1000, message = "{Min}",groups = AllGroup.class)
private Double salary;
/*
* 不属于任何组 - 只有@Validated({}) 或者 @Validated 可以验证
**/
@Length(min = 7,message = "长度最少是{0}")
private String username;
}
2️⃣ 给@validated提供groups属性
/*
* MARK 分组校验 - @Validated
*
* 1. 分组 - 对于通用验证,卸一个Default.class,然后其他组继承Default.class
* 2. @Validated({Group.class}) 指定组
* */
@GetMapping("/validInsert")
@ResponseBody
public String validInsert(@Validated({User.InsertGroup.class}) User user, BindingResult bindingResult){
printBindResult(bindingResult);
return "基本类型验证";
}
@GetMapping("/validUpdate")
@ResponseBody
public String validUpdate(@Validated({User.UpdateGroup.class}) User user,BindingResult bindingResult){
printBindResult(bindingResult);
return "基本类型验证";
}
🍃 自定义校验 - 自定义校验注解
我们可以提供自定义校验注解
,步骤如下
- 提供
自定义校验注解
(需要提供groups
和payload属性
),使用@Constraint
指定Validator
- 提供
校验器(Validator)
,实现ConstraintValidator
1️⃣ 自定义校验注解
/*
* 验证 值是 value中的 - 类似mysql的check约束
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ColorCheckValidator.class) // 哪个了Validator验证
public @interface ColorCheck {
// values
String[] value() default {};
// errorMessage
String message() default "颜色不符合";
// group - 分组校验
Class<?>[] groups() default {};
// payload - 承载信息
Class<? extends Payload>[] payload() default {};
}
2️⃣ 实现ConstraintValidator
/*
* ConstraintValidator - 约束验证
* */
public class ColorCheckValidator implements ConstraintValidator<ColorCheck,String> {
private HashSet<String> colorSet = new HashSet<>();
@Override
public void initialize(ColorCheck constraintAnnotation) {
// 可以根据 payload 承载的信息 - 进行 - 初始化
for (String color : constraintAnnotation.value()) {
colorSet.add(color);
}
}
/*
* true = 通过
* false = 不通过
* */
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return colorSet.contains(value);
}
}
使用校验注解
@Data
public class Cat {
@ColorCheck(value = {"red","green","blue"})
private String color;
}
进行校验
/*
* MARK 自定义 - 校验注解 - @
*
* 1. 定义校验注解 - groups表示分组验证,payload用于承载信息
* 2. @Constraint - 指定Validator
* 3. 实现Validator - 继承ConstraintValidator
*
*
* 如果 自定义校验 和 基本属性校验一起,也就是 在Controller上用了@Validated,那么对于自定义校验,
* - 使用@Valid,无法使用BindingResult - 直接跑出500.
* - 应该用@Validated
*
* */
@GetMapping("/validCustom")
@ResponseBody
public String validCustom(@Valid Cat cat,BindingResult bindingResult) {
printBindResult(bindingResult);
if(bindingResult.hasErrors()) {
return "Cat颜色错误";
}
return "验证Cat成功";
}