「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」
一、高级约束注解
- 校验参数
- 校验返回值
- 校验构造方法
新建service包,新增UserService类,含有一个User属性、有参数和无参数构造方法以及另外两个成员方法
public class UserService {
private User user;
// 无参构造函数
public UserService(){}
// 包含User的有参构造函数
public UserService(User user){
}
}
新增一个UserServiceTest
public class UserServiceTest {
private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
private Set<ConstraintViolation<UserService>> set;
// 打印结果
@After
public void after(){
set.forEach(item -> {
// 输出错误信息
System.out.println(item.getMessage());
});
}
}
校验方法入参
在UserService类中新增一个insertUser方法,含有User参数,对User参数进行校验,需要使用@Valid注解
public void insertUser(@Valid User user){
System.out.println("insertUser方法被调用");
}
在UserServiceTest类中新增对insertUser方法入参校验的测试方法
@Test
public void testParamValidation() throws NoSuchMethodException {
ExecutableValidator executableValidator = validator.forExecutables();
UserService userService = new UserService();
// 获取待验证的方法
Method method = userService.getClass().getMethod("insertUser", User.class);
// 构造方法的入参
Object[] paramObjects = new Object[]{new User()};
// 对参数进行校验, 支持填写校验分组,不填默认是Default分组
set = executableValidator.validateParameters(userService, method, paramObjects);
}
利用反射获取目标类中的method,通过构造User,来测试是否能够实现对入惨的校验
执行测试方法
给user的username属性和password属性赋值,再次执行测试
校验成功
校验方法返回值
在UserService类中新增一个方法getUserById,该方法返回一个User对象,对返回的User对象进行校验,同样也需要使用到@Valid注解
public @Valid User getUserById(Integer id){
System.out.println("getUserById方法被调用,userId为:" + id);
return new User();
}
在UserServiceTest中新增测试方法,对getUserById方法的返回值进行校验
@Test
public void testReturnValueValidation() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ExecutableValidator executableValidator = validator.forExecutables();
UserService userService = new UserService();
// 获取待验证的方法
Method method = userService.getClass().getMethod("getUserById", Integer.class);
// 调用方法获取返回值
Object returnVal = method.invoke(userService,1);
set = executableValidator.validateReturnValue(userService,method,returnVal);
}
利用反射获取method,并通过invoke调用目标方法获取返回值,从而对返回值进行校验
执行测试方法
目标方法被调用,同时抛出校验失败的信息,修改getUserById方法的返回值,给返回的User对象的password和username属性赋值,再次执行测试
校验成功,无错误提示输出
对构造函数入参进行校验
对构造函数的入参进行校验与对普通函数的入参校验的方式一致,都需要用到@Valid注解。在UserService类的有参构造方法的参数前加上@Valid注解
在UserServiceTest测试类中新增测试方法对构造函数的入参进行校验
@Test
public void testConstructorParamValidation() throws NoSuchMethodException {
ExecutableValidator executableValidator = validator.forExecutables();
UserService userService = new UserService();
// 获取待验证的方法
Constructor constructor = userService.getClass().getConstructor(User.class);
// 调用方法获取返回值
Object[] paramValue = new Object[]{new User()};
set = executableValidator.validateConstructorParameters(constructor,paramValue);
}
注意这里需要调用executableValidator的validateConstructorParameters方对构造函数的入参进行校验,执行该测试方法
不管是validateParameters方法还是validateReturnValue方法以及validateConstructorParameters方法都有一个groups属性,这个groups与上一篇你有没有使用过这些编程骚操作(三)- 验证框架(中)定义的groups是一样的,即可以将gourps方法入参中,定义分组校验或者定义校验的顺序。
可以使用Spring AOP对每个方法的切面进行校验,构造出入参出参切面,避免一个一个的进行校验 Spring MVC的Controller层的校验就是使用了这种方式。
完整验证步骤
- 约束注解的定义
- 约束验证规则
- 约束注解的声明
- 约束验证流程
自定义手机号约束注解
- 定义@interface Phone注解
- 实现约束验证器PhoneValidator
- 声明@Phone约束注解验证
- 执行手机号约束验证流程
验证规则
使用Optional处理value,如果value为空则赋值空字符串“”
使用自定义的@Phone注解
测试该注解