写了一个POJO + Annotation来做validation的验证方案。思路就是在POJO里加入Annotation来标注验证条件,以取代validation.xml等验证方式。
先看一下最终的应用效果
public class UserBean {
private String userName;
private String password;
private String email;
@SRequired(messageKey = "Name is required.")
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@SRequired(messageKey = "Password is required.")
@SLength(min = 6, max = 20, messageKey = "Password is 6 - 20")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@SRegularEx(regex = RegPatterns.EMAIL, messageKey = "Please input a valid email.")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public class ValidateTest {
public static void main(String[] args) {
UserBean user = new UserBean();
List<String> messageList = ValidationUtils.validate(user);
for (String s : messageList) {
System.out.println(s);
}
}
}
这里只需要在POJO的get方法上加annotation说明验证条件,以及验证失败后的消息(或消息的i18n key)即可,ValidationUtils将收集验证失败的消息并返回。
推荐将annotation加在public getXXX方法上,而不是加在field上。主要原因是
- 这样不会破坏java的public, private等访问限制。
- 加在get方法上更加灵活,你可以验证由几个filed组合而成的一个String是否符合条件
再说一下实现,其实很简单, 像下面这样创建validation annotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface SLength {
String messageKey() default "";
int max() default 255;
int min() default 0;
}
这里SLength的默认范围是 0-255 基本符合大部分项目的需求。
在ValidationUtils中先找出POJO的所有method,然后遍历,取得一个method的返回值,再取出这个method上的所有annotation,遍历这些annotation并找出那些是我们定义的validation annotation,再根据不同的条件分别进行验证。
private static void validateMethods(Object bean, List<String> messageList) {
//get all of public methods
Method[] publicMethods = bean.getClass().getMethods();
for (Method method : publicMethods) {
//ignore if it is not getXXX method
if (!isGetterMethod(method)) {
continue;
}
Object value = null;
try {
value = method.invoke(bean, null);
} catch (Exception e) {
e.printStackTrace();
}
//Annotation[] annotations = method.getDeclaredAnnotations();
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
validateAnnotation(value, annotation, messageList);
}
}
}
private static void validateAnnotation(Object value, Annotation annotation, List<String> messageList) {
if (annotation instanceof SRequired) {
validateRequired(value, (SRequired) annotation, messageList);
} else if (annotation instanceof SLength) {
validateLength(value, (SLength) annotation, messageList);
} else if (annotation instanceof SRegularEx) {
validateRegularEx(value, (SRegularEx) annotation, messageList);
}
}
在这里大部分的验证都可以通过 SRegularEx annotation 来做,你只需要自行扩展 RegPatterns 类中定义的正则表达式就行了。有特殊需要的话,你可以创建自己的validation annotation,并扩展ValidationUtils.validateAnnotation()方法。
做这个的时候,只是为了验证web form提交,有什么不足的还请大家指点。