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

struts2 result-type门类详解

2012-09-02 
struts2 result-type类型详解在struts2-core.jar/struts-default.xml中,我们可以找到关于result-type的一

struts2 result-type类型详解
在struts2-core.jar/struts-default.xml中,我们可以找到关于result-type的一些配置信息,从中可以看出struts2组件默认为我们提供了这
些result-type
       <result-types>
            <result-type name="chain" default="true"/>
            <result-type name="freemarker" />
            <!-- Deprecated name form scheduled for removal in Struts 2.1.0. The camelCase versions are preferred. See ww-1707 -->
            <result-type name="redirect-action" />
        </result-types>


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

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

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

常用的Result
dispatcher
Xml代码

<result-type name="dispatcher" default="true"/>

  dispatcher主要用于返回JSP,HTML等以页面为基础View视图,这个也是Struts2默认的Result类型。在使用dispatcher时,唯一需要指定的,是JSP或者HTML页面的位置,这个位置将被用于定位返回的页面:

Xml代码

<result name="success">/index.jsp</result>

  而Struts2本身也没有对dispatcher做出什么特殊的处理,只是简单的使用Servlet API进行forward。

  freemarker / velocity

Xml代码
<result-type name="freemarker" + location;  
    }  

    // 得到模板  
    Template template = configuration.getTemplate(location, deduceLocale());  
    // 为模板准备数据  
    TemplateModel model = createModel();  

    // 根据模板和数据进行输出  
    // Give subclasses a chance to hook into preprocessing  
    if (preTemplateProcess(template, model)) {  
        try {  
            // Process the template  
            template.process(model, getWriter());  
        } finally {  
            // Give subclasses a chance to hook into postprocessing  
            postTemplateProcess(template, model);  
        }  
    }  
}

public void doExecute(String location, ActionInvocation invocation) throws IOException, TemplateException {
    this.location = location;
    this.invocation = invocation;
    this.configuration = getConfiguration();
    this.wrapper = getObjectWrapper();

    // 获取模板的位置
    if (!location.startsWith("/")) {
        ActionContext ctx = invocation.getInvocationContext();
        HttpServletRequest req = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
        String base = ResourceUtil.getResourceBase(req);
        location = base + "/" + location;
    }

    // 得到模板
    Template template = configuration.getTemplate(location, deduceLocale());
    // 为模板准备数据
    TemplateModel model = createModel();

    // 根据模板和数据进行输出
    // Give subclasses a chance to hook into preprocessing
    if (preTemplateProcess(template, model)) {
        try {
            // Process the template
            template.process(model, getWriter());
        } finally {
            // Give subclasses a chance to hook into postprocessing
            postTemplateProcess(template, model);
        }
    }
}

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

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

  redirect

Xml代码
<result-type name="chain" type="redirect">
         <param name="location">generateReport.jsp</param>
         <param name="namespace">/genReport</param>
         <param name="reportType">pie</param>
         <param name="width">${width}</param>
         <param name="height">${height}</param>
      </result>
   </action>

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

  chain

Xml代码
<result-type name="chain" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">filename="document.pdf"</param>
<param name="bufferSize">1024</param>
</result>

  同时,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化的拦路虎。

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

  黄依依写道:开启密锁钥匙的复杂化,是现代密码发展的趋势。但这种复杂化却受到无线通讯本身的限制,尤其是距离远、布点多的呈放射性的无线通讯,一般的密钥总是要藏在报文中。

  密钥既然可以藏在报文中,那么Result的类型当然也能够藏在ResultCode中。

Java代码
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。



redirect和redirectAction chain的区别

struts2中关于result的返回类型一般我们是转发到一个jsp页面或者是html页面等,但是struts2中的result的返回类型还有redirect,redirectAction,chain。对于这三种返回类型之间肯定是有区别的,下面我们来看看关于redirect redirectAction chain这三种struts2的返回类型之间的区别。

当使用type=“redirectAction” 或type=“redirect”提交到一个action并且需要传递一个参数时。这里是有区别的:
使用type=“redirectAction”时,结果就只能写Action的配置名,不能带有后缀:“.action”



使用type=“redirect”时,结果应是action配置名+后缀名
 

    redirect:action处理完后重定向到一个视图资源(如:jsp页面),请求参数全部丢失,action处理结果也全部丢失。 redirect-action:action处理完后重定向到一个action,请求参数全部丢失,action处理结果也全部丢失。 chain:action处理完后转发到一个action,请求参数全部丢失,action处理结果不会丢失。



热点排行