浏览 10740 次
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2006-03-10
Webwork是标准的请求风格Web MVC,类似的有Struts、Spring MVC。这这种风格的MVC中都使用了前端控制器模式(企业架构模式),也就是说一个URL会被解析然后派发到对应的Action解析,而View调用的是Action处理后的Form对象或者Command对象(Rod的Without EJB)。 上面引用了一些经典的言论,而它们和“页面控制器风格Action复用”有什么关系呢? 嘿嘿,页面控制器在这里指到了View的Page里面依然可以调用控制器(在Webwork中就是Action)。如果是以前肯定有人会说,如果用JSP我随时可以在Page里面写scriptlet,什么东西都能调用…… 可是,现在不一样了。我们希望让View单纯一点,不要有杂乱无章的逻辑参与其中。 可是,如果要是如上面所说那么Action在它的一个请求生命周期就要做所有的事……这样一是使Action逻辑变得复杂,二是会变得难以复用。 所以,说到这里就引出了这个主题: 1、在页面调用控制器 2、复用控制器逻辑 在Webwork中我们可以使用<ww:action/>标签实现这个目的。 —————————————————————————————————————— 不要着急,我们先介绍一下ww:action的两种主要用法,而说用法之前先说语法: 语法: <ww:action/>有5个属性: 1、id:给Action返回的ValueStack命名,如果不写则默认为调用的Action的名字。(详细使用参照后面) 2、name:调用的Action的name。 3、namespace:调用的Action的namespace。 4、executeResult:true或false,是否渲染Action的View。这个决定了ww:action的用法。(后面会做说明) 5、ignoreContextParams:Boolean值,request参数是否在Action被调用时所包括。 好了,语法很简单,我们说ww:action的两种主要用法。 1、代替<jsp:include>: include有两种方式@ include和jsp:include,它们一个是编译前一个是运行时include。webwork是不能使用<jsp:include>的。 但其实ww有ww:include标签,但是根据Webwork in Action中的推荐,ww:include标签适合调用一般servlet,而对于action则推荐使用强大的ww:action。所以我们这里就略过ww:include。 说强大是什么意思呢?ww:action充当这个角色时,可以选择是否将valueStack的东西复制过来。 当ww:action代替jsp:include的时候我们需要executeResult="true",这个时候调用的action返回的view会被include到调用的位置。<ww:action><param name="xxx" value="yyy"/></ww:action>则可以给action传递参数。其它的用法就与jsp:include或者ww:include用法差别不大了。 2、页面控制器风格Action复用: 我们经常遇到这样的场景,比如用户注册的时候需要选择单位列表。那么我们reg.action运行之前就需要先把单位列表unitsList取出来。而它们本身与User注册逻辑上没什么关系。 所以有的人把这个取出unitsList单独写在prepare()方法里面,然后用prepare Inteceptor……或者把读取unitsList的逻辑写在execute方法里面。 但是这显然难以复用! 其实如果有单位unit这样的domain,我们可能就有对应的CRUD的Action。其中可能就有UnitsListAction这样的Action。 我们完全可以在用户注册的时候就复用这个Action,而不是把同样的逻辑写到用户注册的Action里面。这就是页面控制器风格要解决的问题。 说那么多大帽子其实没有意义,我们看看怎么实现: UnitsListAction片断(我们要复用它): UnitService unitService = null;//注入,商业逻辑 List<Unit> unitsList = null;//设置对应getter、setter Public String execute(); { unitsList = unitDao.listAll();; return SUCCESS; } UserRegAction假设在注册前只是doDefault()直接返回SUCCESS,只有在Post数据时在调用execute(),我们就不写空的代码了。或者不通过任何Action调用注册页面,直接调用注册的jsp文件直接访问也可以。 到了UserRegAction显示的View,我这里是Jsp片断: <ww:action id="listUnits" executeResult="false" namespace="/" name="unitsListAction" /> <ww:select name="unitId" list="#attr.listUnits.unitsList" listKey="id" listValue="name" required="true"/> 注意,executeResult="false",也就是说我们不渲染unitsListAction返回的view,只用它的值。 而访问它的值的时候要使用#attr.listUnits.unitsList这样的引用,因为这时unitsListAction返回的VlueStack不是页面的ognl的rootStack,我们需要访问#attr这个Stack,这部分可以参考一下Webwork的wiki。 上面我给unitsListAction规定了一个id,这样调用比较灵活,你可以多次调用同一个Action并且将值放在#attr下的不同地方。 我们引用unitsListAction返回的unitsList这个list的时候需要用#attr加上我们给unitsListAction设定的id(如果不指定id,则默认unitsListAction)再加上你要访问的变量名访问。 其实很简单,而这种方式就是开始说的页面控制器风格的action复用。虽然和真正的叶面控制器的Tapestry和JSF相差甚远,但是也算有点那个意思了。 扩展点想,如果我们在Action实现了一个counter,也可以通过这种方式调用,连返回的值都可以忽略,呵呵,这种逻辑复用还是挺有用的。 抛砖引玉,我这个人说话啰嗦,见谅,就到这里。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-03-21
我原来以为有个这个东西,就可以不用把得到的list放到Session中用来出错返回这个页面时能够正常显示。但是试了一下,好像在输入检查没通过返回来时这个action不会执行。这样页面还是不能正常显示,下拉列表中的值没有了。
|
|
返回顶楼 | |
发表时间:2006-05-29
zjumty 写道 我原来以为有个这个东西,就可以不用把得到的list放到Session中用来出错返回这个页面时能够正常显示。但是试了一下,好像在输入检查没通过返回来时这个action不会执行。这样页面还是不能正常显示,下拉列表中的值没有了。
同问这个, 有没有比较好的方法. |
|
返回顶楼 | |
发表时间:2006-05-29
按照文档和自己以前做过的实验,需要在被调用的Action里显式语句将值放到valueStatck的Request里。
public class ActionTagAction extends ActionSupport { public String execute() throws Exception { return "done"; } public String doDefault() throws Exception { ServletActionContext.getRequest().setAttribute("stringByAction", "This is a String put in by the action's doDefault()"); return "done"; } } webwork的文档: http://www.opensymphony.com/webwork/wikidocs/action.html |
|
返回顶楼 | |
发表时间:2006-06-05
zjumty 写道 我原来以为有个这个东西,就可以不用把得到的list放到Session中用来出错返回这个页面时能够正常显示。但是试了一下,好像在输入检查没通过返回来时这个action不会执行。这样页面还是不能正常显示,下拉列表中的值没有了。
奇怪呀,我一直是这样用的呀,没有问题呀。就是单独使用jsp访问也工作正常呀。在使用dispather和redirect两种result的时候和单独访问jsp的生命周期非常类似呀。为了出错返回使用session,我可不喜欢。 |
|
返回顶楼 | |
发表时间:2006-06-06
Why not use Preparable?
|
|
返回顶楼 | |
发表时间:2006-06-06
dwangel 写道 Why not use Preparable?
这个可以自己写个interceptor 在 DefaultWorkflowInterceptor 前 ValidationInterceptor 后 执行, 负责检查当前的action是否有错误,如果有错误就尝试调用 methodNameOnError() 方法, 一样可以增加一个 PreResultListener 在action执行结束后 判断是否有错误, 没有就执行methodNameOnSuccess()方法. 如果单纯是用preparable 可能有效率问题, 应为prepare不关心我action执行是否有错误都执行. |
|
返回顶楼 | |
发表时间:2006-06-06
嗯,同意,最好继承MethodFilterInterceptor
这样可以在配置中设置忽略的方法。 |
|
返回顶楼 | |