Spring MVC 使用介绍(十六)数据验证 (三)分组、自定义、跨参数、其他
一、概述
除了依赖注入、方法参数,Bean Validation 1.1定义的功能还包括:
1、分组验证
2、自定义验证规则
3、类级别验证
4、跨参数验证
5、组合多个验证注解
6、其他
二、分组验证
通过分组,可实现不同情况下的不同验证规则,示例如下:
1、定义分组接口
public interface AddView {
} public interface UpdateView {
}
2、定义实体
public class Person { @Null(groups = AddView.class) @NotNull(groups = {UpdateView.class, Default.class}) private Integer id; ... }
注:不指定分组,即为Default分组
3、业务类
@Service @Validated public class PersonService { @Validated(AddView.class) public void addPerson(@Valid Person person) {} @Validated({UpdateView.class}) public void updatePerson(@Valid Person person) {} public void defaultOp(@Valid Person person) {} }
4、测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-context.xml") public class ValidTest { @Autowired private PersonService testService; @Test(expected = ConstraintViolationException.class) public void test1() { Person person = new Person(); person.setId(12); testService.addPerson(person); } @Test(expected = ConstraintViolationException.class) public void test2() { Person person = new Person(); testService.updatePerson(person); } @Test(expected = ConstraintViolationException.class) public void test3() { Person person = new Person(); testService.defaultOp(person); } }
三、自定义验证规则
系统预定义的验证注解不能满足需求时,可自定义验证注解,示例如下:
1、自定义注解
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = ForbiddenValidator.class) @Documented public @interface Forbidden { //默认错误消息 String message() default "{forbidden.word}"; //分组 Class<?>[] groups() default { }; //负载 Class<? extends Payload>[] payload() default { }; //指定多个时使用 @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented @interface List { Forbidden[] value(); } }
2、自定义注解处理类
public class ForbiddenValidator implements ConstraintValidator<Forbidden, String> { private String[] forbiddenWords = {"admin"}; @Override public void initialize(Forbidden constraintAnnotation) { //初始化,得到注解数据 } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if(StringUtils.isEmpty(value)) { return true; } for(String word : forbiddenWords) { if(value.contains(word)) { return false;//验证失败 } } return true; } }
3、默认错误消息
# format.properties
forbidden.word=包含敏感词汇
4、实体类
public class Person { @Forbidden private String name; ... }
5、业务类
@Service @Validated public class PersonService { public void defaultOp(@Valid Person person) { } }
6、测试
@Test(expected = ConstraintViolationException.class) public void test4() { Person person = new Person(); person.setName("admin"); testService.defaultOp(person); }
四、类级别验证
定义类级别验证,可实现对象中的多个属性组合验证,示例如下:
1、定义注解
@Target({ TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Documented @Constraint(validatedBy = CheckPasswordValidator.class) public @interface CheckPassword { //默认错误消息 String message() default ""; //分组 Class<?>[] groups() default { }; //负载 Class<? extends Payload>[] payload() default { }; //指定多个时使用 @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented @interface List { CheckPassword[] value(); } }
2、定义处理类
public class CheckPasswordValidator implements ConstraintValidator<CheckPassword, Person> { @Override public void initialize(CheckPassword constraintAnnotation) { } @Override public boolean isValid(Person person, ConstraintValidatorContext context) { if(person == null) { return true; } //没有填密码 if(!StringUtils.isEmpty(person.getNewPassword())) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("{password.null}") .addPropertyNode("password") .addConstraintViolation(); return false; } if(!StringUtils.isEmpty(person.getConfirmPassword())) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("{password.confirmation.null}") .addPropertyNode("confirmation") .addConstraintViolation(); return false; } //两次密码不一样 if (!person.getNewPassword().equals(person.getConfirmPassword())) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("{password.confirmation.error}") .addPropertyNode("confirmation") .addConstraintViolation(); return false; } return true; } }
3、实体
@CheckPassword public class Person { private String newPassword; private String confirmPassword; ... }
4、业务类
@Service @Validated public class PersonService { public void checkClassValidation(@Valid Person person) { } }
5、测试
@Test(expected = ConstraintViolationException.class) public void test4() { Person person = new Person(); person.setNewPassword("asd"); person.setConfirmPassword("12132"); testService.checkClassValidation(person); }
五、跨参数验证
使用跨参数验证,可实现方法级别中的多个参数组合验证,示例如下:
1、定义注解
@Constraint(validatedBy = CrossParameterValidator.class) @Target({ METHOD, CONSTRUCTOR, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented public @interface CrossParameter { String message() default "{password.confirmation.error}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
2、定义处理类
@SupportedValidationTarget(ValidationTarget.PARAMETERS) public class CrossParameterValidator implements ConstraintValidator<CrossParameter, Object[]> { @Override public void initialize(CrossParameter constraintAnnotation) { } @Override public boolean isValid(Object[] value, ConstraintValidatorContext context) { if(value == null || value.length != 2) { throw new IllegalArgumentException("must have two args"); } if(value[0] == null || value[1] == null) { return true; } if(value[0].equals(value[1])) { return true; } return false; } }
3、业务类
@Service @Validated public class PersonService { @CrossParameter public void checkParaValidation(String pw1, String pw2) { } }
4、测试
@Test(expected = ConstraintViolationException.class) public void test5() { testService.checkParaValidation("asd", "123"); }
六、组合多个验证注解
可将多个注解组合成一个注解,示例如下:
1、定义注解
@Target({ FIELD}) @Retention(RUNTIME) @Documented @NotNull @Min(1) @Constraint(validatedBy = { }) public @interface NotNullMin { String message() default ""; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
2、实体
public class Person { @NotNullMin private Integer id; ... }
3、业务类
@Service @Validated public class PersonService { public void checkCompositionValidation(@Valid Person person) { } }
4、测试
@Test(expected = ConstraintViolationException.class) public void test6() { Person person = new Person(); testService.checkCompositionValidation(person); }
七、其他
Bean Validation 1.1还支持本地化、脚本验证器,详细见参考文档
参考:
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC