首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

忘记李刚,一步一步跟小弟我学Struts2 —— Result机制,让视图更丰富

2012-10-31 
忘记李刚,一步一步跟我学Struts2 —— Result机制,让视图更丰富专栏地址:http://www.iteye.com/wiki/struts2

忘记李刚,一步一步跟我学Struts2 —— Result机制,让视图更丰富
专栏地址:http://www.iteye.com/wiki/struts2/1462-result-in-struts2

Struts2将Result列为一个独立的层次,可以说是整个Struts2的Action层架构设计中的另外一个精华所在。Result之所以成为一个层次,其实是为了解决MVC框架中,如何从Control层转向View层这样一个问题而存在的。所以,接下来我们详细讨论一下Result的方方面面。

Result的职责

Result作为一个独立的层次存在,必然有其存在的价值,它也必须完成它所在的层次的职责。Result是为了解决如何从Control层转向View层这样一个问题而存在的,那么Result最大的职责,就是架起Action到View的桥梁。具体来说,我把这些职责大概分成以下几个方面:

封装跳转逻辑

Result的首要职责,是封装Action层到View层的跳转逻辑。之前我们已经反复提到,Struts2的Action是一个与Web容器无关的POJO。所以,在Action执行完毕之后,框架需要把代码的执行权重新交还给Web容器,并转向到相应的页面或者其他类型的View层。
而这个跳转逻辑,就由Result来完成。这样,好处也是显而易见的,对Action屏蔽任何Web容器的相关信息,使得每个层次更加清晰。

View层的显示类型非常多,有最常见的JSP、当下非常流行的Freemarker/Velocity模板、Redirect到一个新的地址、文本流、图片流、甚至是JSON对象等等。所以Result层的独立存在,就能够对这些显示类型进行区分,并封装合理的跳转逻辑。

以JSP转向为例,在Struts2自带的ServletDispatcherResult中就存在着核心的JSP跳转逻辑:



dispatcher主要用于返回JSP,HTML等以页面为基础View视图,这个也是Struts2默认的Result类型。

在使用dispatcher时,唯一需要指定的,是JSP或者HTML页面的位置,这个位置将被用于定位返回的页面:



从源码中,我们可以看到,createModel()方法真正为模板准备需要显示的数据。而之前,我们已经看到过这个方法的源码,这个方法所准备的数据不仅包含ValueStack中的数据,还包含了被封装过的HttpServletRequest,HttpSession等对象的数据。从而使得模板能够以它特定的语法输出这些数据。

Velocity的Result也是类似,有兴趣的读者可以顺着思路继续深究源码。

redirect



同时,Redirect的Result支持在配置文件中,读取并解析源Action中ValueStack的值,并成为参数传递到Redirect的地址中。上面给出的例子中,width和height就是ValueStack中的值。

chain



同时,StreamResult支持许多参数,对输出的Stream流进行参数控制。具体每个参数的作用,可以参考:http://struts.apache.org/2.0.14/docs/stream-result.html

其他

Struts2的高度可扩展性保证了许多自定义的Result可以通过插件的形式发布出来。比较著名的有JSONResult,JFreeChartResult等等。有兴趣的读者可以在Struts2的官方网站上找到它们,并选择合适的加入到你的项目中去。

关于Result配置简化的思考

Struts2的Result,解决了“如何从Control层转向View层”的问题。不过看了上面介绍的这些由框架本身实现的Result,我们可以发现Result所涉及到的,基本上还停留在为Control层到View层搭建桥梁。

传统的,我们需要通过配置文件,来指定Action执行完毕之后,到底执行什么样的Result。不过在这样一个到处呼吁简化配置的年代,存在着许多方式,可以省略配置:

1. 使用Annotation

Struts2的一些插件提供了@Result和@Results的Annotation,可以通过Annotation来省略XML配置。具体请参考相关的文档。

2. Codebehind插件

Struts2自带了一个Codebehind插件(Struts2.1以后被合并到了其他的插件中)。Codebehind的基本思想是通过CoC的方式,使用命名约定来确定JSP等资源文件的位置。它通过实现了XWork的UnknownHandler接口,来实现当Struts2框架无法找到相应的Result时,如何进行处理的逻辑。具体文档可以参考:

http://struts.apache.org/2.0.14/docs/codebehind-plugin.html

大家可以在上面这两种方式中任意选择,国内著名的开源倡导者Springside也是采用了上述2种方法。在多数情况下,使用Codebehind,针对其他的一些Result使用Annotation进行配置,这样可以在一定程度上简化配置。

不过我本人对使用Annotation简化配置的评价不高。因为实际上使用Annotation,只是将原本就非常简单的配置,从xml文件中移动到java代码中而已。就代码量而言,本身并没有减少。

在这里,我也在经常在思考,如何进行配置简化,可以不写Annotation,完全使用CoC的方式来指定Result。Codebehind在CoC方面已经做出了榜样,只是Codebehind无法判别Result的类型,所以它只能支持dispatcher / freemarker / velocity这三种Result。所以Result的类型的判别,成为了阻碍简化其配置CoC化的拦路虎。

前一段时间,曾经热播一部电视剧《暗算》,其中的《看风》篇中数学家黄依依的一段话给了我灵感:

return "success";


这样一个简单的success作为ResultCode,是无法识别成复杂的Result类型的,我们需要设计一套更加有效的ResultCode,同时,Struts2能够识别这些ResultCode,并得到相应的Result类型和Result实例。这样,我们就可以借用Codebehind的实现方式,实现XWork的UnknownHandler接口,从而达到我们的目的。例如,我们规定ResultCode的解析规则:

success —— 使用codebehind的规则进行JSP,Freemarker模板的寻址

r:/user/list  —— 返回一个redirect的Result,地址为/user/list

c:/user/list —— 返回一个chain的Result,地址为/user/list

j:user —— 返回一个JSON的Result,JSONResult的Root对象为user

s:inputStream-text/html —— 返回一个StreamResult,使用inputStream,并将contentType设置成text/html

以此类推,大家可以定义自己喜欢的ResultCode的格式,从而简化配置。有了这样的规则,也就有了后来的实现。具体解析这些ResultCode,并为他们构建Result实例的源码,大家可以参考我的一个插件项目LightURL。文档在:http://www.iteye.com/topic/242838 1 楼 langyu 2009-02-05   支持楼主,写的很多
读完明白很多 2 楼 fxzjdtk 2009-02-05   楼主说说freemarker和jsp的区别吧?
我只会jsp,不知道freemarker有什么好处,为什么这么流行,详细说说吧。 3 楼 shenzhw 2012-03-07   不曾记起,又何谈忘记!

热点排行