普通校验

(1)给Bean的属性添加注解:javax.validation.constraints.xxx (2)在Controller方法参数上加注解:@Valid

@TableName("brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

    // 品牌id
	@Null(message = "新增不能指定id")
	@TableId
	private Long brandId;
	
	// 品牌名
	@NotBlank(message = "品牌名必须提交")
	private String name;
	
	// 品牌名
	@NotEmpty
	@URL
	private String logo;
	
	// 显示状态[0-不显示;1-显示]
	private Integer showStatus;
	
	// 检索首字母
	@Pattern(regexp="/^[a-zA-Z]$/]", message = "第一个字符必须是字母")
	private String firstLetter;
	
	// 排序
	@Min(value = 0, message = "排序字段值必须大于零")
	private Integer sort;
}
// 保存
// 校验错误会被封装到BindingResult 类中,如果没有写BindingResult 参数,会自动抛出异常
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
    if(result.hasErrors()) {
        Map<String, String> map = new HashMap<>();
        result.getFieldErrors().forEach(item -> {
            String message = item.getDefaultMessage();
            String field = item.getField();
            map.put(field, message);
        });
        // R是自定义类用来封装返回值
        return R.error(400, "提交数据不合法").put("data", map);
    }else {
        brandService.save(brand);
        return R.ok();
    }
}

分组校验

复杂场景下,对于同一个字段,不同情况下的校验规则不一样,就需要用到分组校验。
(1)自定义不同组接口
(2)在校验注解中使用groups属性指定分组类
(3)在Controller方法中使用@Validated注解指定在这个方法中,哪个注解生效

// 新增
public interface AddGroup {
}
// 更新
public interface UpdateGroup {
}
// 品牌id
@NotNull(message = "修改必须指定品牌id", groups = {UpdateGroup.class})
@Null(message = "新增不能指定id", groups = {AddGroup.class})
@TableId
private Long brandId;

// 品牌名
@NotBlank(message = "品牌名必须提交", groups = {UpdateGroup.class, AddGroup.class})
private String name;

// 品牌logo地址
@NotEmpty
@URL
private String logo;
// 分组校验需要使用@Validated注解指定分组
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand, BindingResult result){
    if(result.hasErrors()) {
        Map<String, String> map = new HashMap<>();
        result.getFieldErrors().forEach(item -> {
            String message = item.getDefaultMessage();
            String field = item.getField();
            map.put(field, message);
        });
        return R.error(400, "提交数据不合法").put("data", map);
    }else {
        brandService.save(brand);
        return R.ok();
    }
}

Java 注解校验日期不能为空_校验器

自定义注解

引入jar:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

JSR303规范中,注解必须要有三个属性:

// 默认错误提示信息从哪里获取,这里是从ValidationMessages.properties配置文件中获取
String message() default "{javax.validation.constraints.Min.message}";
// 分组
Class<?>[] groups() default {};
// 自定义信息
Class<? extends Payload>[] payload() default {};

必须要有如下元数据信息:

// 注解可以作用在哪些位置
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
// 该注解可以在运行时获取到
@Retention(RUNTIME)
@Documented
// 使用哪个校验器
@Constraint(
    validatedBy = {}
)
自定义注解实现

(1)编写一个自定义校验注解
(2)编写一个自定义校验器 实现ConstraintValidator接口
(3)关联自定义校验器和自定义校验注解:@Constraint( validatedBy ={ListValueConstraintValidator.class} )

// 显示状态[0-不显示;1-显示]
@ListValue(vals={0, 1})
private Integer showStatus;

自定义校验注解:

@Documented
// 使用自定义校验器
@Constraint(
        validatedBy = {ListValueConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
    // 指定在配置文件中取com.atguigu.common.valid.ListValue.message信息
    String message() default "{com.atguigu.common.valid.ListValue.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

	// 自定义添加一个vals属性
    int[] vals() default {};
}

自定义配置文件 resources/ValidationMessages.properties:

com.atguigu.common.valid.ListValue.message=the specified value must be submitted

自定义校验器:

/**
 * 自定义校验器,必须实现ConstraintValidator接口
 * ConstraintValidator接口后的泛型,第一个参数指定注解,第二个参数表示校验什么类型的数据
 * 这是校验的是Integer字段类型,如果需要校验其他类型,需要再写一个校验器,然后用
 * @Constraint注解的validatedBy 属性指定多个校验器
 */
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
    private Set<Integer> set = new HashSet<>();

    /**
     * 初始化方法
     * @param constraintAnnotation 注解下的属性详细信息
     */
    @Override
    public void initialize(ListValue constraintAnnotation) {
        // 案例中指定showStatus字段必须取值为0或者1,所以这个数组vals就是[0, 1]
        int[] vals = constraintAnnotation.vals();
        for (int val : vals) {
            set.add(val);
        }
    }

    /**
     * 判断是否检验成功
     * @param value 提交给这个注解下属性字段的值(也就是提交过来的showStatus值)
     * @param constraintValidatorContext
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        // value的值是否存在set集合中
        return set.contains(value);
    }
}

Java 注解校验日期不能为空_自定义_02