valid 和validated
@Validation对@Valid进行了二次封装,在使用上并没有区别,但在分组、注解位置、嵌套验证等功能上有所不同,这里主要就这几种情况进行说明
嵌套属性校验
在嵌套对象上添加注解 valid,在请求对象前面添加注解 valid
@Data
public class User {
@Min(value = 10,message = "年龄必须大于10岁")
private Integer age;
}
@Data
public class UserClass {
private String className;
@Valid
private User user;
}
@PostMapping("checkBodyMultilevelParam")
public String checkBodyMultilevelParam(@RequestBody @Valid UserClass userClass){
return "ok";
}
校验get参数
在controller上加注解
@RestController
@RequestMapping("/paramTest")
@Validated
public class ParamTestController {
@GetMapping("checkParam")
public String checkParam(@RequestParam @Max(value = 99, message = "不能大于99岁") Integer age) {
return "ok";
}
@GetMapping("checkPath/{id}")
public String checkPath(@PathVariable @Pattern(regexp = "^[0-9]*$", message = "id参数值必须是正整数") String id) {
return "ok";
}
}
参考链接:https://mp.weixin.qq.com/s/T_5KQEfbF4G-24-yLajJ4Q
校验post参数
添加用户时,不需要校验id是否为空,
修改用户时就需要校验id是否为空。
定义分组(分组也可以放到用户dto中)
public class ValidGroup {
// 新增使用(配合spring的@Validated功能分组使用)
public interface Insert{}
// 更新使用(配合spring的@Validated功能分组使用)
public interface Update{}
// 删除使用(配合spring的@Validated功能分组使用)
public interface Delete{}
// 属性必须有这两个分组的才验证(配合spring的@Validated功能分组使用)
public interface All{}
}
在实体类中将参数用分组进行标记
//只能引用Delete和Update分组的时候才能够进行生效.
@Min(value = 1,message = "ID不能小于1",groups = {ValidGroup.Delete.class,ValidGroup.Update.class})
private int id;
@NotBlank(message = "用户名不能为空",groups = {ValidGroup.Update.class,ValidGroup.Insert.class})
private String username;
@NotBlank(message = "密码不能为空",groups = {ValidGroup.Update.class,ValidGroup.Insert.class})
@Length(min = 6,max = 20,message = "密码长度在6-20之间")
private String password;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不合理")
private String email;
//一个参数分别放到了不同的分组中:默认分组和update分组
@NotBlank(message = "昵称不为空")
@Size(message = "昵称长度 [1-3] ", min = 1, max = 3,groups = ValidGroup.Update.class)
private String nickname;
使用分组:controller中@Validated指定需要的分组
//没有指定用哪个分组,只对提交过来的参数中的email和nickname进行校验
@RequestMapping("/saveUserInfo")
public UserInfo saveUserInfo(@Validated() UserInfo userInfo){
return userInfo;
}
//使用了Update分组,所以回对Update分组中的id,username,password,nickname参数进行校验
@RequestMapping("/updateUserInfo")
public UserInfo updateUserInfo(@Validated({ValidGroup.Update.class}) UserInfo userInfo){
return userInfo;
}
//使用了delete分组,所以回对delete分组中的id参数进行校验
@RequestMapping("/deleteUserInfo")
public UserInfo deleteUserInfo(@Validated({ValidGroup.Delete.class}) UserInfo userInfo){
return userInfo;
}
组序列
默认情况下 不同级别的约束验证是无序的,但是在一些情况下,顺序验证却是很重要。
一个组可以定义为其他组的序列,使用它进行验证的时候必须符合该序列规定的顺序。在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证
定义组序列:
@GroupSequence({Default.class, IGroupA.class, IGroupB.class})
public interface IGroup {
}
需要校验的Bean,分别定义IGroupA对age进行校验,IGroupB对className进行校验:
public class StudentBean implements Serializable{
@Min(value = 18, message = "年龄不能小于18岁", groups = IGroupA.class)
private Integer age;
@notblank(message = "className不能为空",groups = IGroupB.class)
private String className;
测试代码:
@RestController
public class CheckController {
@PostMapping("stu")
public String addStu(@Validated({IGroup.class}) @RequestBody StudentBean studentBean){
return "add student success";
}
}
如果age出错,那么对组序列在IGroupA后的IGroupB不进行校验,即例子中的className不进行校验
自定义校验器@AssertTrue
有时候,我们需要对多个字段进行复杂的逻辑校验,例如需要两个字段相互比较或执行自定义的校验逻辑。
在这种情况下,我们可以使用自定义的校验器(Validator)来实现。
@AssertTrue注解来标记自定义的校验方法 isEndDateAfterStartDate()。该方法检查 endDate是否晚于 startDate,如果校验失败,将返回指定的错误提示信息。
publicclassUserDto{
@NotNull(message = "起始日期不能为空")
private LocalDate startDate;
@NotNull(message = "结束日期不能为空")
private LocalDate endDate;
@AssertTrue(message = "结束日期必须晚于起始日期")
private boolean isEndDateAfterStartDate(){
if (startDate == null || endDate == null) {
returntrue;
}
return endDate.isAfter(startDate);
}
}
自定义校验注解
自定义注解:定义一个名为 Email的注解,并指定了它的校验器 EmailValidator。
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {EmailValidator.class})
public @interface Email {
String message()default "邮箱格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
自定义校验器
public class EmailValidator implements ConstraintValidator<Email, String> {
@Override
public void initialize(Email constraintAnnotation){
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context){
// 在这里编写自定义的校验逻辑
// 返回true表示校验通过,返回false表示校验失败
}
}
使用自定义注解
publicclassUserDto{
@Email
private String email;
}
关于分组抛出的异常处理
参考链接:
https://mp.weixin.qq.com/s/x6_mNdtb6i2XmTiyz4kXrg