注解验证

http://www.opensymphony.com/webwork/wikidocs/J2SE%205%20Support.html
http://www.opensymphony.com/webwork/wikidocs/Validation%20Annotation.html
WEBWORK中需要加入包xwork-tiger

一般有两种注解法

1.直接注在get方法上面,像这种

@RequiredStringValidator(message="Supply password")

public String getPassword() {
       
return password;
    }

2.注在方法上面,like

@Validations(
requiredStrings={
@RequiredStringValidator(fieldName="username",message="用户名不能为空!" key="i18n,國際化功能"),
@RequiredStringValidator(fieldName="telNum",message="电话号码不能为空!")
},
regexFields={@RegexFieldValidator(fieldName="telNum",expression="^(\\+86|0|1)\\d{10,11}$",
message="电话号码格式不正确!")}
)


package com.gumtreenet.company.action;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.util.List;

import com.gumtreenet.company.base.Page;
import com.gumtreenet.company.service.IDdSubService;
import com.gumtreenet.company.service.IDownloadlibraryService;
import com.gumtreenet.company.vo.Downloadlibrary;
import com.gumtreenet.company.vo.Resume;
import com.opensymphony.webwork.dispatcher.json.JSONObject;
import com.opensymphony.xwork.ActionSupport;
import com.opensymphony.xwork.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork.validator.annotations.Validations;

/**
* 附件action
*
* @author 李义星
* @version 0.1
* @datetime 2011-03-22
*/
public class DownloadlibraryAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private final static String DDMAINNAME = "下载类型";

private Downloadlibrary downlib;
private IDownloadlibraryService downService;
private IDdSubService ddSubService;
private FileInputStream downIn;
private File down;
private String downFileName;
private String downContentType;
private Page page;
private JSONObject jsonObject;
private Timestamp start;
private Timestamp end;
private List<Resume> findDowns;

public Downloadlibrary getDownlib() {
return downlib;
}

public void setDownlib(Downloadlibrary downlib) {
this.downlib = downlib;
}

public IDownloadlibraryService getDownService() {
return downService;
}

public void setDownService(IDownloadlibraryService downService) {
this.downService = downService;
}

public IDdSubService getDdSubService() {
return ddSubService;
}

public void setDdSubService(IDdSubService ddSubService) {
this.ddSubService = ddSubService;
}

public FileInputStream getDownIn() {
return downIn;
}

public void setDownIn(FileInputStream downIn) {
this.downIn = downIn;
}

public File getDown() {
return down;
}

public void setDown(File down) {
this.down = down;
}

public String getDownFileName() {
return downFileName;
}

public void setDownFileName(String downFileName) {
this.downFileName = downFileName;
}

public String getDownContentType() {
return downContentType;
}

public void setDownContentType(String downContentType) {
this.downContentType = downContentType;
}

public Page getPage() {
return page;
}

public void setPage(Page page) {
this.page = page;
}

public JSONObject getJsonObject() {
return jsonObject;
}

public void setJsonObject(JSONObject jsonObject) {
this.jsonObject = jsonObject;
}

public Timestamp getStart() {
return start;
}

public void setStart(Timestamp start) {
this.start = start;
}

public Timestamp getEnd() {
return end;
}

public void setEnd(Timestamp end) {
this.end = end;
}

public List<Resume> getFindDowns() {
return findDowns;
}

public void setFindDowns(List<Resume> findDowns) {
this.findDowns = findDowns;
}

@Validations(requiredStrings = {
@RequiredStringValidator(fieldName = "downFileName", message = "请输入附件标题"),
@RequiredStringValidator(fieldName = "downFileName", message = "请输入附件") })
public String addDown() {
return SUCCESS;
}

@Validations(requiredStrings = {
@RequiredStringValidator(fieldName = "downFileName", message = "请1"),
@RequiredStringValidator(fieldName = "downFileName", message = "") })
public String deleteDown() {
return SUCCESS;
}
}



但无论是哪种注解,默认情况下都是对这个action的所有方法进行验证。

如上面的图,我虽然给deleteDown和addDown两个方法都写了对应的验证注解,但是结果是访问delete的时候,add的验证也起作用了。

在struts2中好解决
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
struts2中这个验证器是支持按方法进行区分注解的。
只要在
<!--开启方法级别的验证-->
validation的配置上加入validateAnnotatedMethodOnly,值是true
  <interceptor-ref name="validation">
      <param name="excludeMethods">input,back,cancel,browse</param>
      <param name="validateAnnotatedMethodOnly">true</param>
  </interceptor-ref>
但是webwork是不支持的。
webwork默认是使用xwork1的。而xwork1的注解验证需要xwork-tiger.jar的支持。
我对其进行的跟踪。发现它构建注解验证配置的是在类com.opensymphony.xwork.validator.AnnotationValidationConfigurationBuilder的静态方法
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) 从参数中可以看出来,它是不支持方法级别的验证的。
因此必须对这个类进行改进。
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) {

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();

        List<ValidatorConfig> temp = processAnnotations(aClass);
        if (temp != null) {
            result.addAll(temp);
        }

        Method[] methods = aClass.getDeclaredMethods();

        if ( methods != null ) {
            for (Method method : methods) {
                temp = processAnnotations(method);
                if (temp != null) {
                    result.addAll(temp);
                }
            }
        }

        return result;

    }

它的上级调用代码(堆栈)是:
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {

        String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>(loadFile(fileName, aClass, checkFile));

        List<ValidatorConfig> annotationResult = new ArrayList<ValidatorConfig>(AnnotationValidationConfigurationBuilder.buildAnnotationClassValidatorConfigs(aClass));

        result.addAll(annotationResult);

        return result;

    }
两部分都可以看出,它并没有把调用的实际方法传进来,因此可以知道它不支持方法级别的注解。

再往上一级调用堆栈是
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set checked) {
        List<ValidatorConfig> validatorConfigs = new ArrayList<ValidatorConfig>();

        if (checked == null) {
            checked = new TreeSet<String>();
        } else if (checked.contains(clazz.getName())) {
            return validatorConfigs;
        }

        if (clazz.isInterface()) {
            Class[] interfaces = clazz.getInterfaces();

            for (Class anInterface : interfaces) {
                validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
            }
        } else {
            if (!clazz.equals(Object.class)) {
                validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
            }
        }

        // look for validators for implemented interfaces
        Class[] interfaces = clazz.getInterfaces();

        for (Class anInterface1 : interfaces) {
            if (checked.contains(anInterface1.getName())) {
                continue;
            }

            validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));

            if (context != null) {
                validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
            }

            checked.add(anInterface1.getName());
        }

        validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));

        if (context != null) {
            validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
        }

        checked.add(clazz.getName());

        return validatorConfigs;
    }

这里的参数context就是方法名。
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));
这个方法是针对全局的验证配置加载
validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));这个是针对方法级别的配置加载,但是不支持注解。
由于http://www.opensymphony.com/webwork/wikidocs/J2SE%205%20Support.html
http://www.opensymphony.com/webwork/wikidocs/Validation%20Annotation.html
WEBWORK中需要加入包xwork-tiger

一般有两种注解法

1.直接注在get方法上面,像这种

@RequiredStringValidator(message="Supply password")

public String getPassword() {
       
return password;
    }

2.注在方法上面,like

@Validations(
requiredStrings={
@RequiredStringValidator(fieldName="username",message="用户名不能为空!" key="i18n,國際化功能"),
@RequiredStringValidator(fieldName="telNum",message="电话号码不能为空!")
},
regexFields={@RegexFieldValidator(fieldName="telNum",expression="^(\\+86|0|1)\\d{10,11}$",
message="电话号码格式不正确!")}
)


package com.gumtreenet.company.action;

import java.io.File;
import java.io.FileInputStream;
import java.sql.Timestamp;
import java.util.List;

import com.gumtreenet.company.base.Page;
import com.gumtreenet.company.service.IDdSubService;
import com.gumtreenet.company.service.IDownloadlibraryService;
import com.gumtreenet.company.vo.Downloadlibrary;
import com.gumtreenet.company.vo.Resume;
import com.opensymphony.webwork.dispatcher.json.JSONObject;
import com.opensymphony.xwork.ActionSupport;
import com.opensymphony.xwork.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork.validator.annotations.Validations;

/**
* 附件action
*
* @author 李义星
* @version 0.1
* @datetime 2011-03-22
*/
public class DownloadlibraryAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private final static String DDMAINNAME = "下载类型";

private Downloadlibrary downlib;
private IDownloadlibraryService downService;
private IDdSubService ddSubService;
private FileInputStream downIn;
private File down;
private String downFileName;
private String downContentType;
private Page page;
private JSONObject jsonObject;
private Timestamp start;
private Timestamp end;
private List<Resume> findDowns;

public Downloadlibrary getDownlib() {
return downlib;
}

public void setDownlib(Downloadlibrary downlib) {
this.downlib = downlib;
}

public IDownloadlibraryService getDownService() {
return downService;
}

public void setDownService(IDownloadlibraryService downService) {
this.downService = downService;
}

public IDdSubService getDdSubService() {
return ddSubService;
}

public void setDdSubService(IDdSubService ddSubService) {
this.ddSubService = ddSubService;
}

public FileInputStream getDownIn() {
return downIn;
}

public void setDownIn(FileInputStream downIn) {
this.downIn = downIn;
}

public File getDown() {
return down;
}

public void setDown(File down) {
this.down = down;
}

public String getDownFileName() {
return downFileName;
}

public void setDownFileName(String downFileName) {
this.downFileName = downFileName;
}

public String getDownContentType() {
return downContentType;
}

public void setDownContentType(String downContentType) {
this.downContentType = downContentType;
}

public Page getPage() {
return page;
}

public void setPage(Page page) {
this.page = page;
}

public JSONObject getJsonObject() {
return jsonObject;
}

public void setJsonObject(JSONObject jsonObject) {
this.jsonObject = jsonObject;
}

public Timestamp getStart() {
return start;
}

public void setStart(Timestamp start) {
this.start = start;
}

public Timestamp getEnd() {
return end;
}

public void setEnd(Timestamp end) {
this.end = end;
}

public List<Resume> getFindDowns() {
return findDowns;
}

public void setFindDowns(List<Resume> findDowns) {
this.findDowns = findDowns;
}

@Validations(requiredStrings = {
@RequiredStringValidator(fieldName = "downFileName", message = "请输入附件标题"),
@RequiredStringValidator(fieldName = "downFileName", message = "请输入附件") })
public String addDown() {
return SUCCESS;
}

@Validations(requiredStrings = {
@RequiredStringValidator(fieldName = "downFileName", message = "请1"),
@RequiredStringValidator(fieldName = "downFileName", message = "") })
public String deleteDown() {
return SUCCESS;
}
}



但无论是哪种注解,默认情况下都是对这个action的所有方法进行验证。

如上面的图,我虽然给deleteDown和addDown两个方法都写了对应的验证注解,但是结果是访问delete的时候,add的验证也起作用了。

在struts2中好解决
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
struts2中这个验证器是支持按方法进行区分注解的。
只要在
<!--开启方法级别的验证-->
validation的配置上加入validateAnnotatedMethodOnly,值是true
  <interceptor-ref name="validation">
      <param name="excludeMethods">input,back,cancel,browse</param>
      <param name="validateAnnotatedMethodOnly">true</param>
  </interceptor-ref>
但是webwork是不支持的。
webwork默认是使用xwork1的。而xwork1的注解验证需要xwork-tiger.jar的支持。
我对其进行的跟踪。发现它构建注解验证配置的是在类com.opensymphony.xwork.validator.AnnotationValidationConfigurationBuilder的静态方法
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) 从参数中可以看出来,它是不支持方法级别的验证的。
因此必须对这个类进行改进。
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(Class aClass) {

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();

        List<ValidatorConfig> temp = processAnnotations(aClass);
        if (temp != null) {
            result.addAll(temp);
        }

        Method[] methods = aClass.getDeclaredMethods();

        if ( methods != null ) {
            for (Method method : methods) {
                temp = processAnnotations(method);
                if (temp != null) {
                    result.addAll(temp);
                }
            }
        }

        return result;

    }

它的上级调用代码(堆栈)是:
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {

        String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;

        List<ValidatorConfig> result = new ArrayList<ValidatorConfig>(loadFile(fileName, aClass, checkFile));

        List<ValidatorConfig> annotationResult = new ArrayList<ValidatorConfig>(AnnotationValidationConfigurationBuilder.buildAnnotationClassValidatorConfigs(aClass));

        result.addAll(annotationResult);

        return result;

    }
两部分都可以看出,它并没有把调用的实际方法传进来,因此可以知道它不支持方法级别的注解。

再往上一级调用堆栈是
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set checked) {
        List<ValidatorConfig> validatorConfigs = new ArrayList<ValidatorConfig>();

        if (checked == null) {
            checked = new TreeSet<String>();
        } else if (checked.contains(clazz.getName())) {
            return validatorConfigs;
        }

        if (clazz.isInterface()) {
            Class[] interfaces = clazz.getInterfaces();

            for (Class anInterface : interfaces) {
                validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
            }
        } else {
            if (!clazz.equals(Object.class)) {
                validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
            }
        }

        // look for validators for implemented interfaces
        Class[] interfaces = clazz.getInterfaces();

        for (Class anInterface1 : interfaces) {
            if (checked.contains(anInterface1.getName())) {
                continue;
            }

            validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));

            if (context != null) {
                validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
            }

            checked.add(anInterface1.getName());
        }

        validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));

        if (context != null) {
            validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
        }

        checked.add(clazz.getName());

        return validatorConfigs;
    }

这里的参数context就是方法名。
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));这部会把整个类的方法的注解也加入配置集合中。基本上没找到可以入手的地方。

注解,既然它是针对注解的,那我就再写一个注解。
解压出xwork-tiger.jar包的源码。
添加注解类
package com.opensymphony.xwork.validator.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 定义方法级别的注解配置
*
* @author ANSHU87
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodValidation {

}
这个注解类只能写在class上面。

添加类

package com.opensymphony.xwork.validator;

import java.lang.annotation.Annotation;

public class ConfigState {
private boolean methodValidation = false;  //是否开启方法注解
private Annotation[] annotations;  //类的注解信息

public boolean isMethodValidation() {
return methodValidation;
}

public void setMethodValidation(boolean methodValidation) {
this.methodValidation = methodValidation;
}

public Annotation[] getAnnotations() {
return annotations;
}

public void setAnnotations(Annotation[] annotations) {
this.annotations = annotations;
}
}

用于保存获取到的class注解配置信息。
修改源码包的类
AnnotationValidationConfigurationBuilder
private static List<ValidatorConfig> processAnnotations(Object o) 方法修改如下

@SuppressWarnings("unchecked")
private static List<ValidatorConfig> processAnnotations(Object o,
String context, ConfigState configState) {

List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();

String fieldName = null;

Annotation[] annotations = null;

if (o instanceof Class) {
Class clazz = (Class) o;

annotations = clazz.getAnnotations();
configState.setAnnotations(annotations);
}

if (o instanceof Method) {
Method method = (Method) o;

// 开启了方法级别验证
if (configState.isMethodValidation()) {
if(context != null && !context.equals("")){
if (!context.equals(method.getName())) {
return result;
}
}
}

fieldName = resolvePropertyName(method);

annotations = method.getAnnotations();
}

if (annotations != null) {
for (Annotation a : annotations) {

// Process collection of custom validations
if (a instanceof Validations) {
processValidationAnnotation(a, fieldName, result);

}

// Process single custom validator
if (a instanceof Validation) {
Validation v = (Validation) a;
if (v.validations() != null) {
for (Validations val : v.validations()) {
processValidationAnnotation(val, fieldName, result);
}
}

}
// Process single custom validator
else if (a instanceof ExpressionValidator) {
ExpressionValidator v = (ExpressionValidator) a;
ValidatorConfig temp = processExpressionValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process single custom validator
else if (a instanceof CustomValidator) {
CustomValidator v = (CustomValidator) a;
ValidatorConfig temp = processCustomValidatorAnnotation(v,
fieldName);
if (temp != null) {
result.add(temp);
}

}

// Process ConversionErrorFieldValidator
else if (a instanceof ConversionErrorFieldValidator) {
ConversionErrorFieldValidator v = (ConversionErrorFieldValidator) a;
ValidatorConfig temp = processConversionErrorFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process DateRangeFieldValidator
else if (a instanceof DateRangeFieldValidator) {
DateRangeFieldValidator v = (DateRangeFieldValidator) a;
ValidatorConfig temp = processDateRangeFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process EmailValidator
else if (a instanceof EmailValidator) {
EmailValidator v = (EmailValidator) a;
ValidatorConfig temp = processEmailValidatorAnnotation(v,
fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process FieldExpressionValidator
else if (a instanceof FieldExpressionValidator) {
FieldExpressionValidator v = (FieldExpressionValidator) a;
ValidatorConfig temp = processFieldExpressionValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process IntRangeFieldValidator
else if (a instanceof IntRangeFieldValidator) {
IntRangeFieldValidator v = (IntRangeFieldValidator) a;
ValidatorConfig temp = processIntRangeFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process DoubleRangeFieldValidator
else if (a instanceof DoubleRangeFieldValidator) {
DoubleRangeFieldValidator v = (DoubleRangeFieldValidator) a;
ValidatorConfig temp = processDoubleRangeFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process RequiredFieldValidator
else if (a instanceof RequiredFieldValidator) {
RequiredFieldValidator v = (RequiredFieldValidator) a;
ValidatorConfig temp = processRequiredFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process RequiredStringValidator
else if (a instanceof RequiredStringValidator) {
RequiredStringValidator v = (RequiredStringValidator) a;
ValidatorConfig temp = processRequiredStringValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process StringLengthFieldValidator
else if (a instanceof StringLengthFieldValidator) {
StringLengthFieldValidator v = (StringLengthFieldValidator) a;
ValidatorConfig temp = processStringLengthFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}
}
// Process UrlValidator
else if (a instanceof UrlValidator) {
UrlValidator v = (UrlValidator) a;
ValidatorConfig temp = processUrlValidatorAnnotation(v,
fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process VisitorFieldValidator
else if (a instanceof VisitorFieldValidator) {
VisitorFieldValidator v = (VisitorFieldValidator) a;
ValidatorConfig temp = processVisitorFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process RegexFieldValidator
else if (a instanceof RegexFieldValidator) {
RegexFieldValidator v = (RegexFieldValidator) a;
ValidatorConfig temp = processRegexFieldValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// Process StringRegexValidator
else if (a instanceof StringRegexValidator) {
StringRegexValidator v = (StringRegexValidator) a;
ValidatorConfig temp = processStringRegexValidatorAnnotation(
v, fieldName);
if (temp != null) {
result.add(temp);
}

}
// 判断是否开启了方法级别
else if (a instanceof MethodValidation) {
configState.setMethodValidation(true);
}
}
}
return result;
}
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(
Class aClass)方法修改如下
@SuppressWarnings("unchecked")
//添加context方法,存放调用的上下文
public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(
Class aClass, String context) {

List<ValidatorConfig> result = new ArrayList<ValidatorConfig>();
ConfigState configState = new ConfigState();  //保存配置信息
List<ValidatorConfig> temp = processAnnotations(aClass, context,
configState);
if (temp != null) {
result.addAll(temp);
}

Method[] methods = aClass.getDeclaredMethods();

if (methods != null) {
for (Method method : methods) {
temp = processAnnotations(method, context, configState);
if (temp != null) {
result.addAll(temp);
}
}
}

return result;
}

修改源码包的
AnnotationActionValidatorManager类,把所有调用public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(
Class aClass)方法的代码,改成调用新的方法,public static List<ValidatorConfig> buildAnnotationClassValidatorConfigs(
Class aClass, String context)。

测试
刚才的action 在class前面添加注解
@MethodValidation
public class DownloadlibraryAction extends ActionSupport





4个文件代码
http://dl.iteye.com/topics/download/4142f2ff-2d36-3c9e-a004-ba35d3d0e275

猜你喜欢

转载自liyixing1.iteye.com/blog/1020314