目的是优雅的实现参数校验,避免使用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)