验证框架
java
it书童
2021-01-14 16:42:57
0赞
0踩
150阅读
0评论
验证模型
验证模型可分为:
- 分层验证模型
- Java Bean 验证模型
Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API
Hibernate Validator 是对 Bean Validation 规范的实现
Spring Validation 在 Hiberante Validator 的基础上,对其进行了二次封装,以满足在 Spring 环境中更简单、高效地对数据进行验证
完成验证的步骤
首先引入相关依赖:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.20.Final</version>
</dependency>
操作步骤可分解为:
-
约束注解的定义
-
约束验证规则
-
约束注解的声明
-
约束验证流程
前两步验证框架为我们做好了。如果我们要自定义约束注解,就需要完成整个步骤
如:自定义手机号约束注解
-
定义 @interface Phone 注解
-
实现约束验证器 PhoneValidator.java
-
声明 @Phone 约束验证
-
执行手机号约束验证流程
验证框架的综合使用
自定义手机号的约束注解,其他使用预定义的约束注解
自定义注解接口
package efficient.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 自定义手机号约束注解
*/
@Documented
// 注解的作用目标
@Target({ElementType.FIELD})
// 注解的保留策略
@Retention(RetentionPolicy.RUNTIME)
// 与普通注解的不同之处:与约束注解关联的验证器
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
// 约束注解验证时的输出信息
String message() default "手机号校验错误";
// 约束注解在验证时所属的组别
Class<?>[] groups() default {};
// 约束注解的有效负载
Class<? extends Payload>[] payload() default {};
}
自定义约束注解的校验逻辑
package efficient.validation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PhoneValidator implements ConstraintValidator<Phone, String> {
public void initialize(Phone constraint) {
}
/**
* 自定义校验逻辑方法
*
* @param value
* @param context
* @return
*/
public boolean isValid(String value, ConstraintValidatorContext context) {
// 手机号验证规则:158开头随便
String check = "158\\d{8}";
Pattern regex = Pattern.compile(check);
// 空值处理
String phone = Optional.ofNullable(value).orElse("");
Matcher matcher = regex.matcher(phone);
return matcher.matches();
}
}
实体类中使用约束注解:可以区分不同使用场景
package efficient.validation;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.GroupSequence;
import javax.validation.Valid;
import javax.validation.constraints.*;
import javax.validation.groups.Default;
import java.util.Date;
import java.util.List;
/**
* 待验证对象实体类
*/
@Data
public class UserInfo {
// 登录场景
public interface LoginGroup {}
// 注册场景
public interface RegisterGroup {}
// 组排序场景
@GroupSequence({
LoginGroup.class,
RegisterGroup.class,
Default.class
})
public interface Group {}
@NotNull(
message = "用户id不能为空",
groups = LoginGroup.class // 指定使用场景
)
private String userId;
@NotEmpty(message = "用户名称不能为空") // 不会自动去掉前后空格
private String userName;
@NotBlank(message = "用户密码不能为空") // 自动去掉字符串前后空格再验证是否为空
@Length(min = 6, max = 20, message = "密码长度不能少于6位,多于20位")
private String password;
@NotNull(
message = "邮箱不能为空",
groups = RegisterGroup.class
)
@Email(message = "邮箱必须为有效邮箱")
private String email;
@Phone(message = "手机号不是158开头的")
private String phone;
@Min(value = 18, message = "年龄不能小于18岁")
@Max(value = 60, message = "年龄不能大于60岁")
private Integer age;
@Past(message = "生日不能为未来或当前时间点")
private Date birthday;
@Size(min = 1, message = "不能少于1个好友")
private List<@Valid UserInfo> friends; // 对集合中的 UserInfo 也进行同样的验证
}
服务层中使用约束注解
package efficient.validation;
import javax.validation.Valid;
public class UserInfoService {
/**
* UserInfo 作为输入参数
* @param userInfo
*/
public void setUserInfo(@Valid UserInfo userInfo) {
}
/**
* UserInfo 作为输出参数
* @return
*/
public @Valid UserInfo getUserInfo() {
return new UserInfo();
}
public UserInfoService() {
}
public UserInfoService(@Valid UserInfo userInfo) {
}
}
测试调用结果
package efficient.validation;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Set;
/**
* 验证测试类
*/
public class ValidationTest {
// 验证器对象
private Validator validator;
// 待验证对象
private UserInfo userInfo;
// 验证结果集合
private Set<ConstraintViolation<UserInfo>> set;
// 验证结果集合
private Set<ConstraintViolation<UserInfoService>> otherSet;
@Before
public void init() {
// 初始化验证器
validator = Validation.buildDefaultValidatorFactory().getValidator();
// 初始化待验证对象
userInfo = new UserInfo();
userInfo.setUserId("001");
userInfo.setUserName("郭靖");
userInfo.setPassword("rootPwd");
userInfo.setEmail("123@qq.com");
userInfo.setAge(26);
userInfo.setPhone("13631439097");
Calendar calendar = Calendar.getInstance();
calendar.set(2012, 1, 1);
userInfo.setBirthday(calendar.getTime());
UserInfo friend = new UserInfo();
friend.setUserId("002");
friend.setUserName("黄蓉");
friend.setPassword("pwdRoot");
friend.setAge(24);
userInfo.setFriends(new ArrayList(){{add(friend);}});
}
@After
public void print() {
if (set != null) {
set.forEach(item -> {
// 输出验证
System.out.println(item.getMessage());
});
}
if (otherSet != null) {
otherSet.forEach(item -> {
// 输出验证
System.out.println(item.getMessage());
});
}
}
// 初级验证
@Test
public void primaryValidation() {
set = validator.validate(userInfo);
}
// 分组验证
@Test
public void groupValidation() {
set = validator.validate(userInfo, UserInfo.RegisterGroup.class);
}
// 组排序,当前面的组验证不通过时,中断执行
@Test
public void groupSequenceValidation() {
set = validator.validate(userInfo, UserInfo.Group.class);
}
// 对方法输入参数进行约束注解校验
@Test
public void paramValidation() throws NoSuchMethodException {
// 获取校验执行器
ExecutableValidator executableValidator = validator.forExecutables();
// 待验证对象
UserInfoService service = new UserInfoService();
// 待验证方法
Method method = service.getClass().getMethod("setUserInfo", UserInfo.class);
// 方法输入参数
Object[] paramObjects = new Object[]{new UserInfo()};
// 对方法的输入参数进行校验
otherSet = executableValidator.validateParameters(service, method, paramObjects);
}
// 对方法返回值进行约束注解校验
@Test
public void returnValueValidation() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 获取校验执行器
ExecutableValidator executableValidator = validator.forExecutables();
// 待验证对象
UserInfoService service = new UserInfoService();
// 待验证方法
Method method = service.getClass().getMethod("getUserInfo");
// 调用方法得到返回值
Object returnValue = method.invoke(service);
// 校验方法返回值是否符合约束
otherSet = executableValidator.validateReturnValue(service, method, returnValue);
}
// 对构造函数输入参数进行校验
@Test
public void constructorValidation() throws NoSuchMethodException {
// 获取校验执行器
ExecutableValidator executableValidator = validator.forExecutables();
// 获取构造函数
Constructor<UserInfoService> constructor = UserInfoService.class.getConstructor(UserInfo.class);
Object[] paramObjects = new Object[]{new UserInfo()};
// 校验构造函数
otherSet = executableValidator.validateConstructorParameters(constructor, paramObjects);
}
}
- 上一篇: Google Guava 工具集
- 下一篇: idea 好用的插件

关于我
一个文科出身的程序员,追求做个有趣的人,传播有价值的知识,微信公众号主要分享读书思考心得,不会有代码类文章,非程序员的同学请放心订阅
转载须注明出处:https://www.itshutong.com/articles/1030
精品付费
这一次,真正掌握composer
1597
0
个人开发者通过payjs接入微信支付
2814
0
相关推荐
Java super 关键字使用
291
0
Java 面向对象的多态特征介绍
239
0
Java 可变参数
172
0
Java 网络编程入门
226
0
Mybatis 一级缓存
188
0
Spring 基于注解的声明式事务控制
170
0
什么是Hystrix
225
0
java 改变线程优先级
198
0
java线程通信
164
0
java使用finally回收资源
202
0
java的IO流
210
0
VisualVM工具的使用
181
0
开闭原则
151
0
简单工厂
184
0