@Validated
@Service
public class ValidatorService {
private static final Logger logger = LoggerFactory.getLogger(ValidatorService.class);
public String show(@NotNull(message = "不能为空") @Min(value = 18, message = "最小18") String age) {
logger.info("age = {}", age);
return age;
}
}
分组校验
有时候对于不同的接口,需要对 DTO 进行不同的校验规则。还是以上面的 UserDTO 为列,另外一个接口可能不需要将 age 限制在 18 ~ 50 之间,只需要大于 18 就可以了。
这样上面的校验规则就不适用了。分组校验就是来解决这个问题的,同一个 DTO,不同的分组采用不同的校验策略。
public class UserDTO {
public interface Default {
}
public interface Group1 {
}
private Integer userId;
//注意:@Validated 注解中加上groups属性后,DTO中没有加group属性的校验规则将失效
@NotEmpty(message = "姓名不能为空",groups = Default.class)
private String name;
//注意:加了groups属性之后,必须在@Validated 注解中也加上groups属性后,校验规则才能生效,不然下面的校验限制就失效了
@Range(min = 18, max = 50, message = "年龄必须在18和50之间",groups = Default.class)
@Range(min = 17, message = "年龄必须大于17", groups = Group1.class)
private Integer age;
}
使用方式
@PostMapping("/saveUserGroup")
@ResponseBody
//注意:如果方法中的参数是对象类型,则必须要在参数对象前面添加 @Validated
//进行分组校验,年龄满足大于 17
public Response<UserDTO> saveUserGroup(@Validated(value = {UserDTO.Group1.class}) @RequestBody UserDTO userDTO){
userDTO.setUserId(100);
Response response = Response.success();
response.setData(userDTO);
return response;
}
使用 Group1 分组进行校验,因为 DTO 中,Group1 分组对 name 属性没有校验,所以这个校验将不会生效。
分组校验的好处是可以对同一个 DTO 设置不同的校验规则,缺点就是对于每一个新的校验分组,都需要重新设置下这个分组下面每个属性的校验规则。
分组校验还有一个按顺序校验功能。
考虑一种场景:一个 bean 有 1 个属性(假如说是 attrA),这个属性上添加了 3 个约束(假如说是@NotNull、@NotEmpty、@NotBlank)。默认情况下,validation-api 对这 3 个约束的校验顺序是随机的。也就是说,可能先校验@NotNull,再校验@NotEmpty,最后校验@NotBlank,也有可能先校验@NotBlank,再校验@NotEmpty,最后校验@NotNull。
那么,如果我们的需求是先校验@NotNull,再校验@NotBlank,最后校验@NotEmpty。@GroupSequence 注解可以实现这个功能。
public class GroupSequenceDemoForm {
@NotBlank(message = "至少包含一个非空字符", groups = {First.class})
@Size(min = 11, max = 11, message = "长度必须是11", groups = {Second.class})
private String demoAttr;
public interface First {
}
public interface Second {
}
@GroupSequence(value = {First.class, Second.class})
public interface GroupOrderedOne {
// 先计算属于 First 组的约束,再计算属于 Second 组的约束
}
@GroupSequence(value = {Second.class, First.class})
public interface GroupOrderedTwo {
// 先计算属于 Second 组的约束,再计算属于 First 组的约束
}
}
使用方式
// 先计算属于 First 组的约束,再计算属于 Second 组的约束
@Validated(value = {GroupOrderedOne.class}) @RequestBody GroupSequenceDemoForm form
嵌套校验
前面的示例中,DTO 类里面的字段都是基本数据类型和 String 等类型。
但是实际场景中,有可能某个字段也是一个对象,如果我们需要对这个对象里面的数据也进行校验,可以使用嵌套校验。
假如 UserDTO 中还用一个 Job 对象,比如下面的结构。需要注意的是,在 job 类的校验上面一定要加上@Valid 注解。
public class UserDTO1 {
private Integer userId;
@NotEmpty
private String name;
@NotNull
private Integer age;
@Valid
@NotNull
private Job job;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Job getJob() {
return job;
}
public void setJob(Job job) {
this.job = job;
}
/**
* 这边必须设置成静态内部类
*/
static class Job {
@NotEmpty
private String jobType;
@DecimalMax(value = "1000.99")
pri