@Validated和@Valid实现接口参数校验

目的是优雅的实现参数校验,避免使用if-else。

@Valid是javax提供的,可以用在方法、构造函数、方法参数和成员属性(字段)上。可实现嵌套验证。
@Validates是spring框架validation类提供的,可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上。可实现分组验证。

常用校验
实体中参数需要参数校验注解,比如@NotNull等,在文章最后会做一个总结。

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

	/**
	 * 品牌id
	 */
	@NotNull(message = "修改必须指定品牌id")
	@Null(message = "新增不能指定id")
	@TableId
	private Integer id;
	/**
	 * 品牌名称
	 */
	@NotBlank(message = "品牌名必须提交")
	private String name;
	/**
	 * 品牌图片地址
	 */
	@NotBlank()
	@URL(message = "logo必须是一个合法的url地址")
	private String image;
	/**
	 * 品牌的首字母
	 */
	@NotEmpty()
	@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母")
	private String letter;
	/**
	 * 排序
	 */
	@NotNull()
	@Min(value = 0, message = "排序必须大于等于0")
	private Integer seq;

}

然后再controller中方法参数上,使用@Validated和@Valid,即可以实现入参校验

@RestController
@RequestMapping("product/brand")
public class BrandController {
    @Autowired
    private BrandService brandService;

    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Validated @RequestBody BrandEntity brand){
		brandService.save(brand);

        return R.ok();
    }

	/**
     * 修改
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:brand:update")
    public R update(@Valid @RequestBody BrandEntity brand){
		brandService.updateById(brand);

        return R.ok();
    }
}

分组
@Validated可以实现分组校验
例如上边的实体,在保存和编辑修改时,都需要用到,那么这样的话,每个字段的校验在保存和修改时,就可能会不一样,这时,就可以用分组校验来,达到我们不同方法,公用实体了。

首先需要定义分组接口

public interface AddGroup {
}

public interface UpdateGroup {
}

然后在实体字段上,利用group来指定分组接口

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

	/**
	 * 品牌id
	 */
	@NotNull(message = "修改必须指定品牌id", groups = {UpdateGroup.class})
	@Null(message = "新增不能指定id", groups = {AddGroup.class})
	@TableId
	private Integer id;
	/**
	 * 品牌名称
	 */
	@NotBlank(message = "品牌名必须提交", groups = {AddGroup.class, UpdateGroup.class})
	private String name;
	/**
	 * 品牌图片地址
	 */
	@NotBlank(groups = {AddGroup.class})
	@URL(message = "logo必须是一个合法的url地址", groups = {AddGroup.class, UpdateGroup.class})
	private String image;
	/**
	 * 品牌的首字母
	 */
	@NotEmpty(groups = {AddGroup.class})
	@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母", groups = {AddGroup.class, UpdateGroup.class})
	private String letter;
	/**
	 * 排序
	 */
	@NotNull(groups = {AddGroup.class})
	@Min(value = 0, message = "排序必须大于等于0", groups = {AddGroup.class, UpdateGroup.class})
	private Integer seq;

}

controller中,在@Validated注解中也得指定分组接口

@RestController
@RequestMapping("product/brand")
public class BrandController {
    @Autowired
    private BrandService brandService;

    /**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
		brandService.save(brand);

        return R.ok();
    }

	/**
     * 修改
     */
    @RequestMapping("/update")
    //@RequiresPermissions("product:brand:update")
    public R update(@Valid({AddGroup.class}) @RequestBody BrandEntity brand){
		brandService.updateById(brand);

        return R.ok();
    }
}

这样就可以实现分组校验了。

嵌套验证
什么是嵌套验证呢?有两实体,Apartment和Room,在Apartment实体中,包装了Room实体,有一个字段是List,如下所示:

public class Apartment{

    @NotNull(message = "apartmentId不能为空")
    @Min(value = 1, message = "apartmentId必须为正整数")
    private Long apartmentId;

    @NotNull(message = "rooms不能为空")
    @Size(min = 1, message = "至少要有一个属性")
    private List<Room> rooms;
}
public class Room{

    @NotNull(message = "roomId不能为空")
    @Min(value = 1, message = "roomId必须为正整数")
    private Long roomId;

    @NotNull(message = "regionId不能为空")
    @Min(value = 1, message = "regionId必须为正整数")
    private Long regionId;

    @NotBlank(message = "roomNumber不能为空")
    private String roomNumber;
}

现在在controller中有一个方法,入参是apartment,apartment中的参数需要验证,Room中的参数也需要验证

@RestController
public class ApartmentController {

    @RequestMapping("/apartment/add")
    public void addApartment(@Validated Apartment apartment, BindingResult bindingResult) {
        doSomething();
    }
}

像上边这样,无论是使用@Validated还是@Valid,Spring Validation框架都只会对Apartment中的字段验证,都不会对Room中的字段进行验证。
想要实现嵌套验证,必须手动在Apartment实体的rooms字段上明确指出这个字段里面的实体也要进行验证,@Valid可以用到字段上,所以用@Valid就行,@Validated是不能用在字段上的。Apartment实体如下即可:

public class Apartment{

    @NotNull(message = "apartmentId不能为空")
    @Min(value = 1, message = "apartmentId必须为正整数")
    private Long apartmentId;

	@Valid // 嵌套验证必须用@Valid
    @NotNull(message = "rooms不能为空")
    @Size(min = 1, message = "至少要有一个属性")
    private List<Room> rooms;
}

这样,我们在controller的addApartment方法的参数上再使用@Validated或@Valid,就可以实现嵌套验证了。

总结下:想要嵌套验证,在实体字段上必须使用@Valid,然后在controller方法入参上配合使用@Validated或@Valid,即可实现嵌套验证。

常用实体参数校验注解:
@NotNull 限制必须不为null
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Pattern(regexp = “”) 正则表达式校验参数
@Size(max,min) 限制字符长度必须在min到max之间
@Min(value) 限制最小值
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@Range(min = 0, max = 10) / Max / @Min 校验最大值/最小值,参数类型为整形(pageNo, pageSize)

你可能感兴趣的:(【框架】--,Spring,spring,入参校验)