`
Fly_m
  • 浏览: 257942 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

使用struts2的annotation验证

阅读更多

      这篇文章我是继看过帖子 http://www.iteye.com/topic/173295 之后写下的一些经过和学习经验,尽管以前也简单看过一些关于webwork验证的东西,但都因为没有进行深入研究而作罢,直到看了论坛帖子之后,才想专心去看一下相应的解决办法.(注:写本文的目的只是让自己能有一个记性,同时也将相关的东西统一起来,让大家也都能够了解一些,如果有人也解决过这个问题,不妨一起说说经历).

       很早以前就利用struts2(其实就是webwork核心)的验证框架,写各个方法的验证文件了.如我有一个名叫ArticleAction的类,其中需要调用一个叫做showArticle方法,那么我的action配置可能是这样写的:

 

<action name="sa2" class="articleAction" method="showArticle">  	<result name="input">/WEB-INF/news/error.jsp</result>  	<result name="ARTICLEACTION_SHOWARTICLE_SUCCESS">/WEB-INF/news/articleShow.jsp</result>  	<result name="ARTICLEACTION_SHOWARTICLE_FAIL">/WEB-INF/news/error.jsp</result>  </action>

  这样,在我的源代码中,就有一个名叫Article-sa2-validation.xml的校验文件.这里注明一下,如果配置文件里面已经注明了方法,如上文所示,那么相应的校验文件中的方法应该是action的配置别名,而不是showArticle.我以前写Article-showArticel-validation,它死活都不解析,最后去找英文论坛好不容易看到这么一条配置,终于解析了.

验证文件就不用写了,那么我们继续帖子上的内容,在看了webwork中文wiki上的java5注解配置,同时受帖子启发,把相关的验证都搬到Action源代码中,并删除了xml验证文件.

     这里要注明一下,帖子中作者的注明其实只有一个是需要被验证的,而我自己的action中,是有很多方法被验证,同时每个访求所验证的对象还可能不一样.由以下这个action配置文件来说:

 

<action name="sa1" class="articleAction" method="saveArticle">  			<interceptor-ref name="defaultStack"/>  			<interceptor-ref name="token"/>  			<result name="invalid.token">/WEB-INF/news/success.jsp</result>  			<result name="ARTICLEACTION_SAVEARTICLE_FAIL">/WEB-INF/news/articleCreate.jsp</result>  			<result name="ARTICLEACTION_SAVEARTICLE_SUCCESS">/WEB-INF/news/success.jsp</result>  			<result name="input">/WEB-INF/news/articleCreate.jsp</result>  		</action>  		<action name="sa2" class="articleAction" method="showArticle">  			<result name="input">/WEB-INF/news/error.jsp</result>  			<result name="ARTICLEACTION_SHOWARTICLE_SUCCESS">/WEB-INF/news/articleShow.jsp</result>  			<result name="ARTICLEACTION_SHOWARTICLE_FAIL">/WEB-INF/news/error.jsp</result>  		</action>

这里就有两个验证一个是sa1,一个是sa2,而对sa1所验证的主要是article这个对象的相关属性(具体属性就不用由贴出来了,主要就是些标题啊,内容啊什么的),而sa2所验证的是一个article.id这个对象是否为空就完了,因为它必须要求这个属性不能为空才能调用相关的方法逻辑.相应的annotation我贴出来,看下验证的内容:

 

@Validations(requiredStrings = {  	@RequiredStringValidator(fieldName = "article.title", key = "article.title.requiredstring", message = "null"),  	@RequiredStringValidator(fieldName = "article.content", message = "null", key = "article.content.requiredstring"),  	@RequiredStringValidator(fieldName = "article.titleColor", key = "article.titleColor.requiredstring", message = "null"),  	@RequiredStringValidator(fieldName = "article.tags", key = "article.tags.requiredstring", message = "null")})  	public String saveArticle() throws Exception {}
  
@Validations(requiredFields = @RequiredFieldValidator(fieldName = "article.id", key = "article.id.required", message = "null"),  			conversionErrorFields = @ConversionErrorFieldValidator(fieldName = "article.id", message = "null", key = "article.id.int"))  	public String showArticle() throws Exception {}

 从上面可以看出,两者进行验证的内容是完全不一样的.好了,改写完毕,进行tomcat运行了.先运行一下第一个方法,恩一切正常,验证也是正常的.然后运行第二个方法,结果出错了,页面上一堆验证失败信息,而令人奇怪的是,除了对于第二个方法的验证错误之外,所有每一个方法的验证错误都出来了.刚开始还以为是配制出错的原因,检查了几次都还是有错.我尝试将第一个的验证改成@SkipValidation,结果出来了,第二个验证开始起作用了,也就是说第一个的验证没有出现了.但是这很正常的呀,把第一个禁用了(SkipValidation)了,当然不会出现第一个的验证了.我觉得好像虽然是写在方法级别上的验证,而实际的作用范围却是每一个方法,于最初的要求还是有那么一大段区别.我认为可能是源代码中哪儿逻辑错了或者说配置错了.于是,先是去google,不过查了很久,都没有查到跟这个问题相关的地方,很多页面都说了struts2(webwork)的annotation验证,却没有说碰到这种情况,因为相应的验证都是放在field上或者说是单独的一个方法之上(如中文webwork wiki中写的),还是自己动手吧.

 说干就做,下载 了struts2的源代码,在用于验证的拦截器AnnotationValidationInterceptor 这个方法的doIntercept(ActionInvocation actionInvocation)是这样写的:

 

protected String doIntercept(ActionInvocation invocation) throws Exception {         Object action = invocation.getAction();         if (action != null) {             Method method = getActionMethod(action.getClass(), invocation.getProxy().getMethod());             SkipValidation skip = (SkipValidation) method.getAnnotation(SkipValidation.class);             if (skip != null) {                 return invocation.invoke();             }         }         return super.doIntercept(invocation);     }
  看了一下,主要是先找方法上有没有SkipValidation这个Annotation,如果有,就不用验证了,直接通过.原来这个SkipValidation是struts2单独提供的,原来的webwork并没有提供这个验证,我想它主要是为了提供不被验证的方法一个好的注解吧.再往下看,进入父类的dointercept方法中,也就是由webwork提供的验证中了.进入webwork(xwork2.04)中,
protected void doBeforeInvocation(ActionInvocation invocation) throws Exception {         Object action = invocation.getAction();         String context = invocation.getProxy().getActionName();         String method = invocation.getProxy().getMethod();         if (validateAnnotatedMethodOnly) {             ActionValidatorManagerFactory.getInstance().validate(action, context, method);         } else {             ActionValidatorManagerFactory.getInstance().validate(action, context);         }     }     protected String doIntercept(ActionInvocation invocation) throws Exception {         doBeforeInvocation(invocation);                return invocation.invoke();     }

 由上文可以看到,有一个判断,判断validateAnnotationMethodOnly这个标志,如果为false,进行第二个验证,而第二个验证的代码可以看到是这样写的

 

public void validate(Object object, String context) throws ValidationException {          validate(object, context, (String) null);  }

  也就是说,第二个验证调用的是第一个方法,只不过方法参数为null.现在来看,既然,带了方法这个参数,那么应该就是对访求进行单独设置的才对呀,那为什么会那样呢,接下去看.

 

public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {          List<Validator> validators = getValidators(object.getClass(), context, method);          ......//中间省略若干                  validator.validate(object);              } finally {                  validator.setValidatorContext( null );              }          }      }
 
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {          List<Validator> validators = getValidators(object.getClass(), context, method);          ......//中间省略若干                  validator.validate(object);              } finally {                  validator.setValidatorContext( null );              }          }      }

  看样子就是得到该方法的验证器,再验证此对象了.而对于上面的几个方法来说,validator.validate(object)是最终的验证手段,而第一步才是最关键的,得到该对象,方法的所有验证.进入方法:

 

public synchronized List<Validator> getValidators(Class clazz, String context, String method) {          final String validatorKey = buildValidatorKey(clazz, context);           if (validatorCache.containsKey(validatorKey)) {              if (FileManager.isReloadingConfigs()) {                  validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));              }          } else {              validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));          }           // get the set of validator configs          List<ValidatorConfig> cfgs = validatorCache.get(validatorKey);           // create clean instances of the validators for the caller's use          ArrayList<Validator> validators = new ArrayList<Validator>(cfgs.size());          for (ValidatorConfig cfg : cfgs) {              if (method == null || method.equals(cfg.getParams().get("methodName"))) {                  // Remove methodName temporary                  Object methodName = cfg.getParams().remove("methodName");                  Validator validator = ValidatorFactory.getValidator(cfg, ObjectFactory.getObjectFactory());                  // Readd methodName temporary                  cfg.getParams().put("methodName", methodName);                  validator.setValidatorType(cfg.getType());                  validators.add(validator);              }          }           return validators;      }

  这个流程也很简单,好像就是得到类上的验证,字段上的验证,还有就是方法级别上的验证.而在我们的程序中,类级别上的验证没有,字段上的验证也没有,所以就只有方法级别上的验证了.最后几句最为关键,它好像是进行了方法判断,并将难过的验证放在list中,并返回.其中它的判断很特别:

 

if (method == null || method.equals(cfg.getParams().get("methodName"))) {}

  前面有一个对方法的空判断,而后面有一个方法名的判断.这时我想到了,如果一路上将方法带上的话,那么这里如果没有出错的话应该是只会加上特定方法上的验证的,而如果方法本身就是空的,那么这里就会把所有配置上的验证加在验证列表中,也就是说,本身上属于第一个方法的验证也会被加上.为了验证这种想法,我对原文件进行验证性输出,结果果不其然,method是空,而且同时输出的各个加进来的验证中,果然就本来属于第一个方法的requiredstring等验证.

那么为什么方法是空的呢,如果xwork是正确的,那么结论就肯定出现在当初最先进入验证的源头,validate(...)上.一开始以为是方法没有得到,重新打印输出一下,结果发现这里方法是被得到的.那么,问题肯定出现在接下来的

 

if (validateAnnotatedMethodOnly) {

  上了,一查果然这个参数是空的,那么它肯定进入无方法的验证了,也就是说所有的验证都是进入验证列表了.
为了解决这个问题,看了下这个拦截器的写法,发现它是一个经典的webwork的写法,它提供了对validateAnnotatedMethodOnl这个参数的可配置性,那么如果将这个参数配置成true的话,那么肯定就只进行方法级别的验证了.再看了一个struts2的默认配置,终于发现原来可以在struts2的配置中,对这个值进行依赖注入,参加它本身的写法:

 

<interceptor-ref name="validation">  					<param name="excludeMethods">input,back,cancel,browse</param>  				</interceptor-ref>

  它配置默认对几个方法名不拦截,那么我们再加上以下一条:

 

<interceptor-ref name="validation">  					<param name="excludeMethods">input,back,cancel,browse</param>  					<param name="validateAnnotatedMethodOnly">true</param>  				</interceptor-ref>

  这样就可以调用有方法的验证了.结果实验了一下,果然程序依照自己的思路正确的运行了.

根据这次收获,发现原来自己解决问题也是很高兴的,不知道struts2里面怎么把这个默认给关了, 难道是希望用xml的方式进行验证,而且几乎没有文档提供这个参数的作用,还得靠自己来才行.

突然想到一点,如果我靠这个判断,那么如果是没有验证Annotation的方法,那么它就没有validation了,那么是不是就不会进行验证了?试验了一把,果然没有进行验证(或者说方法上没有可验证的validation).帖子中提到的加SkipValidation的方法,这是在struts2的层次上进行验证的提前结束,不过如果不验证的方法很多的话,那不是要写很多的@SkipValition了.如果不写这个,利用xwork本身的验证就会根本上通过这个方法,且xwork的验证是通过cache进行了,也就是说,它的validator都是存储在cache中的,对系统的影响了不会有很大吧.不知道struts2电门弄这个@SkipValidator是什么意思,且这个好像是专门为AnnotationValidatorInterceptor服务的,难道是没有想到本身就是不需要的吗,不解.所以看到帖子说很多地方要加@SkipValidator这个东西,本身也觉得很矛盾的,看来是多心了.根本不用加,因为它本身就没有validator所以,不需要进行验证.直接就通过了.:)

Fly_m 2008-3-21

附件中为一个验证Action和一个struts.xml配置文件.

我晕,看了一下,用Editplus复制的代码这么多<br>,而在编辑器中看到挺好的啊,哎,下次不用editplus进行提制了.
14
9
分享到:
评论
3 楼 Mr_sqw 2017-05-02  
非常感谢
2 楼 xb8911 2008-07-28  
很好的东西,Thanks!
1 楼 wanderain 2008-03-31  
不错.

相关推荐

    Struts2入门教程(全新完整版)

    10.为什么要使用struts2代替struts1.x 7 二、struts.xml配置及例程 7 1.配置文件的优先级 7 2.配置形式 8 3.package配置相关 8 4.分工合作include:指定多个配置文件 10 5.tomcat认证访问 10 6.初识拦截器 11 7....

    深入浅出struts2

    为了达成这一目标,Struts2中提供了很多新特性,比如智能的默认设置、annotation的使用以及“惯例重于配置”原则的应用,而这一切都大大减少了XML配置。Struts2中的Action都是POJO,这一方面增强了Action本身的可...

    基于spring,struts(struts2),hibernate的web项目脚手架

    generator,极易进行二次开发 struts1,struts2的零配置 spring集成及加强,自动搜索hibernate的entity annotation class 集成动态构造sql的工具:rapid-xsqlbuilder 集成javascript表单验证:rapid-validation 集成...

    低清版 大型门户网站是这样炼成的.pdf

    (Struts 2+Spring 2+Hibernate 3).pdf(完整版) 网上有高清版350M的。可以去下 http://115.com/file/be5gwid8 请于下载后 24H 内及时删除!请抱着学习的态度下载此资料。 总共900多页!!!!!!! 第1篇 ...

    Struts2注解

    配置web.xml,加入注解,验证注解,Convention的Annotation ,、与Result配置相关的Annotation

    Spring2.5+Struts2.0+hibernate3.0+Dwr+jquery+displayTag

    2 利用struts2 的LoginAction-validation.xml 3 在bean里把service包;暴露DWR,写了一个验证用户名的流程 4 采用jpa作为POJO,还是减少配置 5 加入display的分页,并且是物理分页 打开后自已建表sql.txt jdbc....

    java web 开发详解

    Java 的 Web框架虽然各不相同,但基本也都是遵循特定的路数的:使用Servlet或者Filter拦截请求,使用MVC的思想设计架构,使用约定,XML或 Annotation实现配置,运用Java面向对象的特点,面向抽象实现请求和响应的...

    经典JAVA.EE企业应用实战.基于WEBLOGIC_JBOSS的JSF_EJB3_JPA整合开发.pdf

     国内知名的高端IT技术作家,已出版《Spring 2.0宝典》、《基于J2EE的Ajax宝典》、《轻量级J2EE企业应用实战》、《Struts 2权威指南》、《Ruby On Rails敏捷开发最佳实践》等著作。 目录: 第0章 学习Java...

    java命名规范 开发规范

    6. 验证代码质量的约定,如JUnit、EMMA、FindBugs、CheckStyle、PMD的使用;Hudson持续集成需注意的; 7. 压力测试、防内存泄漏测试; 基础CSS:标签的各种状态的样式;表格单双行的样式; 开发一个Action请求的...

    iuhyiuhkjh908u0980

    Ebean的特性如下: ============== l 使用标准的JPA annotation,即:@Entity, @OneToMany等。 l 提供Sessionless API,也就是说没有merge,flush等方法。(这也是Ebean与Hibernatet等ORM的重要区别之一) l 支持...

    java开源包2

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包8

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    JAVA上百实例源码以及开源项目源代码

    2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户...

    java开源包1

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包11

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包3

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包6

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

Global site tag (gtag.js) - Google Analytics