这篇文章我是继看过帖子 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进行提制了.
分享到:
相关推荐
这个数据集提供了2010年至2021年间加拿大各省的家庭支出与收入数据,这些数据根据人口统计和地理指标进行了分类。每行代表了年份(REF_DATE)、省份(GEO)以及编码后的支出或收入类型的唯一组合(COORDINATE)。以下是该数据集的关键特点及包含的列信息: 关键特点: 支出数据:家庭支出按照收入五分位数和支出类别进行分类。 收入数据:家庭收入值根据家庭类型、较年长成年人的年龄组别和收入水平细分。 地理位置匿名化:为了保护隐私,原始的地理位置标识符被替换为如“Province 1”这样的标签。 时间序列:涵盖了超过十年的财务数据(2010–2021),适合用于纵向经济和社会趋势分析。 包含的列: REF_DATE:记录年份(2010–2021) GEO:省份标签(例如,“Province 1”) Statistic:度量类型(例如,平均家庭支出) Before-tax household income quintile:税前家庭收入水平分组 Household expenditures, summary-level categories:支出类别 UOM:计量单位 COORD
1.【锂电池剩余寿命预测】GRU门控循环单元锂电池剩余寿命预测(Matlab完整源码和数据) 2.数据集:NASA数据集,已经处理好,B0005电池训练、测试; 3.环境准备:Matlab2023b,可读性强; 4.模型描述:GRU门控循环单元在各种各样的问题上表现非常出色,现在被广泛使用。 5.领域描述:近年来,随着锂离子电池的能量密度、功率密度逐渐提升,其安全性能与剩余使用寿命预测变得愈发重要。本代码实现了GRU门控循环单元在该领域的应用。 6.作者介绍:机器学习之心,博客专家认证,机器学习领域创作者,2023博客之星TOP50,主做机器学习和深度学习时序、回归、分类、聚类和降维等程序设计和案例分析,文章底部有博主联系方式。从事Matlab、Python算法仿真工作8年,更多仿真源码、数据集定制私信。
2000-2024年各省专利侵权案件结案数数据 1、时间:2000-2024年 2、来源:国家知识产权J 3、指标:专利侵权案件结案数 4、范围:31省 5、用途:可用于衡量知识产权保护水平
- 使用`<div>` 容器组织游戏界面,包含得分显示、游戏画布和操作按钮 - 支持三种游戏模式选择(一般模式、困难模式、无敌模式) - 移动端和桌面端兼容,提供触摸和键盘两种控制方式 2. CSS样式 : - 采用Flex布局实现页面居中显示 - 使用Grid布局实现方向按钮的排列 - 定义了游戏容器的阴影、圆角等视觉效果 - 为按钮添加了hover效果和过渡动画 3. JavaScript逻辑 : - 使用Canvas API实现游戏渲染 - 实现了蛇的移动、食物生成、碰撞检测等核心游戏逻辑 - 支持三种游戏模式,不同模式对应不同的游戏速度和规则 - 使用localStorage保存最高分记录 - 实现随机颜色生成,使游戏更具趣味性 代码整体结构清晰,功能完整,具有良好的可扩展性和可维护性。
台区终端电科院送检文档
内容概要:本文详细介绍了一个基于强化学习(RL)的飞机升阻力特性预测模型的实现过程。首先,定义了飞机空气动力学环境,包括状态空间、动作空间以及目标——预测升力系数(Cl)和阻力系数(Cd)。接着,通过生成模拟数据并进行预处理,创建了用于训练的数据集。然后,构建了一个神经网络代理模型,用于联合编码状态和动作,并预测升阻力系数。最后,实现了PPO算法来训练强化学习代理,使其能够根据当前状态选择最优动作,并通过不断迭代提高预测精度。文中还提供了完整的代码实现和详细的注释。 适合人群:航空航天领域的研究人员、机器学习工程师、对强化学习感兴趣的开发者。 使用场景及目标:适用于需要预测飞机升阻力特性的应用场景,如飞行器设计优化、性能评估等。目标是通过强化学习方法提升预测模型的准确性,从而为实际工程提供可靠的理论支持和技术手段。 其他说明:本文不仅涵盖了模型的设计与实现,还包括了数据生成、预处理等多个环节,有助于读者全面理解整个建模过程。同时,提供的代码可以作为研究和开发的基础,方便进一步扩展和改进。
cmock ut aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
lsm6d datasheet
风力发电机传动机构的设计(增速器)
genesys-zu(5ev)配置petalinux(从安装到嵌入)
django自建博客app
Android项目原生java语言课程设计,包含LW+ppt
幼儿园预防肺结核教育培训课件资料
STM32F103RCT6单片机控制气泵和电磁阀的开关 1、气泵和电磁阀的开和关均为开关量,实现控制方法有多种,比如继电器,但是继电器动作有噪声且体积较大,更好的方法为使用mos管。 2、mos管的选型:mos管选择主要注意两个参数即可,一是导通的电流,二是耐压值,并且常用NMOS管,根据要求,气泵和电磁阀供电电压为12V,所以选择的mos管耐压值要大于12V,这里选用耐压值为30V的MOS管,并且导通电流为5.8A。
因文件较多,数据存放网盘,txt文件内包含下载链接及提取码,永久有效。失效会第一时间进行补充。样例数据及详细介绍参见文章:https://blog.csdn.net/T0620514/article/details/146916073
将 Windows 系统中 “C:\windows\fonts” 目录下的所有字体文件
智能量测终端最新标准
滑道式提升机及其控制电路的设计.zip
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
三拐曲轴模锻工艺及模具设计说明书参考.zip