Struts2的Result Type

chain

    用来处理Action链

    com.opensymphony.xwork2.ActionChainResult

dispatcher

    用来转向页面,通常处理JSP

    org.apache.struts2.dispatcher.ServletDispatcherResult

freemaker

    处理FreeMarker模板

    org.apache.struts2.views.freemarker.FreemarkerResult

httpheader

    控制特殊HTTP行为的结果类型

    org.apache.struts2.dispatcher.HttpHeaderResult

redirect

    重定向到一个URL

    org.apache.struts2.dispatcher.ServletRedirectResult

redirectAction

    重定向到一个Action

    org.apache.struts2.dispatcher.ServletActionRedirectResult

stream

    向浏览器发送InputSream对象,通常用来处理文件下载,还可用于返回AJAX数据

    org.apache.struts2.dispatcher.StreamResult

velocity

    处理Velocity模板

    org.apache.struts2.dispatcher.VelocityResult

xslt

    处理XML/XLST模板

    org.apache.struts2.views.xslt.XSLTResult

plainText

    显示原始文件内容,例如文件源代码

    org.apache.struts2.dispatcher.PlainTextResult

redirect-action

    重定向到一个Action

    org.apache.struts2.dispatcher.ServletActionRedirectResult

plaintext

    显示原始文件内容,例如文件源代码

    org.apache.struts2.dispatcher.PlainTextResult

Struts2将Result列为一个独立的层次,可以说是整个Struts2的Action层架构设计中的另外一个精华所在。Result之所以成为一个层次,其实

是为了解决MVC框架中,如何从Control层转向View层这样一个问题而存在的

在struts2-core.jar/struts-default.xml中,我们可以找到关于result-type的一些配置信息,从中可以看出struts2组件默认为我们提供了这

些result-type

       <result-types>

            <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>

            <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>

            <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>

            <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>

            <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>

            <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>

            <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

            <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>

            <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>

            <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />

            <!-- Deprecated name form scheduled for removal in Struts 2.1.0. The camelCase versions are preferred. See ww-1707 -->

            <result-type name="redirect-action" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>

            <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult" />

        </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 

  接下来,大致介绍一下Struts2内部已经实现的Result,并看看他们是如何工作的。

  dispatcher

<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>

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

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

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

  freemarker / velocity

<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>  
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/> 
 

  随着模板技术的越来越流行,使用Freemarker或者Velocity模板进行View层展示的开发者越来越多。Struts2同样为模板作为Result做出了支持。由于模板的显示需要模板(Template)与数据(Model)的紧密配合,所以在Struts2中,这两个Result的主要工作是为模板准备数据。

  以Freemarker为例,我们来看看它是如何为模板准备数据的:

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);   
        }   
    }   
} 

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

<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>  
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>  
<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> 
 

  如果你在Action执行完毕后,希望执行另一个Action,有2种方式可供选择。一种是forward,另外一种是redirect。有关forward和redirect的区别,这里我就不再展开,这应该属于Java程序员的基本知识。在Struts2中,分别对应这两种方式的Result,就是chain和redirect。

  先来谈谈redirect,既然是重定向,那么源地址与目标地址之间是2个不同的HttpServletRequest。所以目标地址将无法通过ValueStack等Struts2的特性来获取源Action中的数据。如果你需要对目标地址传递参数,那么需要在目标地址url或者配置文件中指出:

Xml代码 

<!--   
   The redirect-action url generated will be :   
   /genReport/generateReport.jsp?reportType=pie&width=100&height=100  
   -->  
   <action name="gatherReportInfo" class="...">  
      <result name="showReportResult" 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中的值。

猜你喜欢

转载自862123204-qq-com.iteye.com/blog/1555324