table

对struts2的底层源码的解读

此问题网上很多人在讨论,至今还是没有很好的解决方案,在我对源码进行解读后,现在已经有个很好的解决方案,业务是用户注册(含复选框),用户注册验证出错后,错误信息的要显示在相应控件的后面,同时要让请求选中的复选框处于选中状态。希望您往下看,说不定会小有收获哦!!

步骤:

1)开发工具设置

   a)工程编码utf-8

   b)文件代码样式javaxml

   c)文件编码格式utf-8jsphtmljs

2)创建目录结构

3) 搭建struts2的环境,

a)    导入jar

参考struts2.1.8下的app下的struts2-blank-2.1.8项目,拷入基本的jar

==========================================================

struts2-core-2.x.x.jar :Struts 2框架的核心类库

       xwork-2.x.x.jar :XWork类库,Struts 2在其上构建

ognl-2.6.x.jar :对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性

       freemarker-2.3.x.jar :Struts 2UI标签的模板使用FreeMarker编写

       commons-fileupload-1.2.1.jarcommons-io-1.3.2.jar这两个jar是用于文件上传

===========================================================

       b)修改web.xml配置文件、添加struts.xml文件

       c)启动项目测试index.jsp界面输出

3)注册页面

页面的源码如下:粗心了点没有实现纯国际化


相信您已经推断出我的项目大致部署,我这里就简要描述下:

配置文件:struts.xmlstrus-user.xml基于模块化配置,UserAction-registerUser-validation.xml在执行UserActionregisterUser方法时进行校验

属性文件:有全局的国际化文件和user模块的国际化文件

类:UserActionUserBeanHobby

工程目录


Struts.xml文件


UserAction




工程目录
Struts.xml文件
UserAction类
第一个问题出现了,如下图:
说明
很多人都是对此很烦恼,struts2使用的默认主题是xhtml,查看html页面的源码发现,它给我们生成了表格布局,所以界面比较整齐,但在提供便利的同时,也带来些烦恼,就是错误提示出现的位置。
解决方案
1)把主题设为theme=simple,自己去控制布局,
2)struts使用freemarker模版技术,为我们标签生成了html代码,所以我们通过修改模版设置错误信息提示的位置。
解读源码了:
 
a: <s:textfield/>这是strus2给我们提供标签,所以我们查看官方文档得知struts-tags.tld在struts-core.jar文件里,每个标签都是一个java类,只是该类extends TagSupport,我们查看TextFieldTag类,其实有经验的人都能猜的八九不离十,您肯定是的。
查看TextFieldTag类
发现它没有doStartTag()方法,所以猜肯定在父类里定义了,查看AbstractUITag,这个类里也没有doStartTag()方法,这个类是所有UI标签的父类,里面定义了标签的属性
继续查看父类,
该类有doStartTag()方法,
我们查看得知,container容器注入了component组件,组件会话出html文本,所有我们需要查看着个组件的具体实现类,在TextFieldTag里面发现
查看Component具体类TextField,
查看注释得知该类构建html文本,但为什么TextField没有继承Component类呢?一猜就是UIBean继承了,查看
果然是继承了Component,学框架思想最重要的是看别人的注释,因为注释是别人思想的表达,这个类负责通过模版构建html文本,所以我们最重要的是找到模版的位置,这个我也是大概看懂,毕竟还没达到水平,相信您已经达到,大致意思是找这些属性值,从而定位到ftl模版文件
struts.ui.theme=xhtml
 
struts.ui.templateDir=template
struts.ui.templateSuffix=ftl

如:<s:checkbox/> 找/template/xhtml/checkbox.ftl模版文件,类推<s:textfield/>,在strus2-core.jar下找textfield.ftl,发现是text.ftl,打开我们查看:

 
包含三个模版,controlheader.ftl又包含controlheader-core.ftl文件,该文件才是核心,
现在我们要修改controlheader-core.ftl、controlfooter.ftl文件,把错误信息放到controlfooter.ftl里面,我们可以有两种方式修改:
1) 拷贝出两个文件,修改后再压缩进去(严重不建议!)
2) 既然有这样的需求,strus2团队肯定考虑到了,这让我实在太佩服他们了,每个细节考虑的都是那么周到,看官方文档
Strus2团队提出了模版的加载、选择模版目录、选择主题、扩展主题。我们想让框架加载我们的模版文件,所以我们点击Template Loading链接查看,
 
意思大概是,首先加载应用程序路径下模版文件,然后去加载classpath下的模版文件,如果需要覆盖某模版,拷贝修改后放置应用程序下,那样将首先加载。本人英语不是太好,如有出处,请见谅!
现在我们需要把两个ftl文件放置application下,有什么格式要求吗?
本章里strus2团队还给我们提供很多建议,建议我们不要随便更换模版引擎,如要修改ftl文件最好把源文件拷贝出来加以修改,不要自己手工重写,以防止出错。
相信也不用解释了,格式为:/template/$theme/$template.ftl.
所以我们只要在Web-Root下创建/template/xhtml文件夹,拷贝controlheader-core.ftl、controlfooter.ftl文件再加以修改。
本人对于freemarker语言不是很了解,但掌握了思想,这种增增删删的操作还是可以应付的,经过几轮修改,总于搞定了。
----------------------------------------------------------------------------------------------------
第二个问题:
先对strus2的默认拦截器原理说下
官方文档这两行最能表达我的意思,excludeMethods参数是设置该拦截器忽略哪些方法,下面反之。这简单原理相信您非常了解了,来看下我们这里出现的情况吧!
这是最普遍的业务逻辑,
这是strus-user.xml配置文件里的registerUser*.action配置:
情况一:
我们按此配置运行,我们不填用户名注册,结果出现如下情况:
说明:
为什么出现无法显示网页呢?我们注册首先被validate拦截器拦截后,UserAction-registerUser-validation.xml验证用户名不能为空,经过workflow拦截器,发现验证出错了,所以跳转input试图,我们input没有配置type,默认是dispatcher,我们这样转发的话,则不再被strus2的拦截器拦截,相当于浏览器访问registerUserUI静态资源,因为压根没有,所有tomcat容器无法访问,则出现无法显示网页
情况二:
好的我们现在修改input结果的type属性为redirect,
我们选中两个爱好,提交返回界面如下:
开始选中的被取消了,并且没有“用户名不能为空”的错误信息。
说明:
为什么会错误信息没了呢?同样经过validate、workflow拦截器后,跳转input试图,一但我们重定向,则strus2框架会为我们创建一个新的UserAction对象,则fieldErrors、UserBeanhobby数组都为null了,所以错误信息、开始选中的都显示不出来了。
情况三:
相信您已经有解决方案了,把input试图的type设为chain类型,chain类型的作用是,让该请求重新被拦截器拦截,好我们来修改:
我们同样不填用户名,选中两个爱好,点击注册后,发现如下结果:
意思大概是:发现一个无限递归调用。
说明:
怎么会出现这样无限递归呢?哪里在递归调用?我们来分析一下流程,当经过validate、workflow拦截器后,跳转input试图,此时type=chain,所以我们看下设置为chain类型后,struts2到底都干了些什么?在官方文档Action Chaining一章里讲解到,
大概意思是如果你要拷贝当前的action属性到当前chain上的action,你需要应用Chaining拦截器,该拦截器会拷贝请求上的parametersvalue stack传递到目标action,原始的action会保存valueStack,允许目标action访问前面所有action的valueStack作用域上的属性,同样对于chain的result结果试图如jsp、velocity界面同样可以访问这些属性。
=====================================================
所以当我们以chain方式访问registerUserUI.action,原先action的valueStack上的fieldErrors同样被拷贝到当前UserAction对象fieldErrors字段里,在经过workflow拦截器后,又发现有错误,同样调用input试图,进而又去调用registerUserUI.action,经过workflow拦截器后,又发现有错误,又去调用input试图,进而递归调用。
现在该怎样解决呢?我们要做的就是,让他调用registerUserUI.action时被workflow拦截器拦截后,不再验证是否有错误,前面说到过excludeMethods参数,我们查看workflow拦截器
发现他忽略input方法,所以我们加上这样的配置:
修改UserAction的registerUserUI方法为input,ok了!我们运行同样不填用户名、选中两个爱好提交,运行结果为:
注意:
虽然chain方式对于完成这种业务很方便,官方提示我们谨慎使用,过度使用会造成程序的代码混乱,到时还是根据业务来决定。

posted on 2009-12-24 15:42 小卓 阅读(2090) 评论(2)  编辑  收藏 所属分类: otherstruts

Feedback

# re: 对struts2的底层源码的解读 2011-05-27 17:41 easy518网址导航

http://www.easy518.com  回复  更多评论   

# re: 对struts2的底层源码的解读 2012-08-13 16:50 wew

fsdf  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: