JavaWeb从入门到精通(视频实战版)
上QQ阅读APP看书,第一时间看更新

5.6 Result类型介绍

Result是在Action执行完,一个结果返回后决定执行何种操作的类。开发者可以自由地根据他们的应用和环境的需要创建自己的Result类型。例如在Struts2中Servlet和Velocity结果类型已经被创建用来显示Web应用程序的画面。本节将介绍Struts2内置的几种Result类型和如何自定义开发Result。

5.6.1 内置Result类型

所有的Result类型都实现了com.opensymphony.xwork.Result接口。这个接口是所有action执行结果的通用接口,不管这个结果是用来显示一个网页还是产生一个E-mail,发送一个JMS消息还是别的。

在struts-default.xml中定义了系统提供的默认Result类型,把它们映射为action配置中可以引用的名字,在action配置中就不用再使用长类名,直接使用这些别名就可以了。如实例5-27所示,这些result的作用如表5.3所示。

【实例5-27】result-type的定义:struts-default.xml片段

01     <result-types>
02        <result-type name="dispatcher"
03          class="com.opensymphony.webwork.dispatcher.ServletDispatcherResult"
04     default="true"/>
05        <result-type name="redirect"
06          class="com.opensymphony.webwork.dispatcher.ServletRedirectResult"/>
07        <result-type name="velocity"
08          class="com.opensymphony.webwork.dispatcher.VelocityResult"/>
09        <result-type name="chain"
10          class="com.opensymphony.xwork.ActionChainResult"/>
11        <result-type name="xslt"
12          class="com.opensymphony.webwork.views.xslt.XSLTResult"/>
13        <result-type name="jasper"
14          class="com.opensymphony.webwork.views.jasperreports.JasperReportsResult"/>
15        <result-type name="freemarker"
16          class="com.opensymphony.webwork.views.freemarker.FreemarkerResult"/>
17        <result-type name="httpheader"
18          class="com.opensymphony.webwork.dispatcher.HttpHeaderResult"/>
19        <result-type name="stream"
20          class="com.opensymphony.webwork.dispatcher.StreamResult"/>
21        <result-type name="plaintext"
22          class="com.opensymphony.webwork.dispatcher.PlainTextResult" />
23     </result-types>

表5.3 result type作用说明表

5.6.2 默认Result

Dispatcher Result是最常用的一种result,它也是Struts2默认的result,又称为通用result。action执行完后,请求会导向对应的View,相当于<jsp:forword>标签实现的跳转功能。将同一个HTTP请求中的内容分发至某一个页面(dispatcher类型的result的使用),只要配置文件包含了struts-default.xml,而且package继承了struts-default,那么使用dispatcher result并不需要其他设置。示例:

<result name="success" type="dispatcher">
  <param name="location">foo.jsp</param>
</result>

在跳转时,可对跳转路径中包含的变量替换成具体的参数值;例:/a.jsp?id=${id}替换成 /a.jsp?id=1。Dispatcher result执行时会遍历location变量对应的字符串,获得符合${...}样式的子串,接着将大括号内的OGNL表达式取出来,然后根据值栈计算表达式的值,最后根据计算的结果替换整个${...}子串。

图5.10所示为Dispatcher Result跳转流程图。

图5.10 Dispatcher Result流程图

5.6.3 页面跳转 Result

Redirect Result与Dispatcher Result作用类似,也是实现页面跳转。对上次的响应将重定向到指定的位置,可以理解为在客户端跳转用户又重新请求了一个新的URL。redirect是重新产生一个新的request,因此原来request保存的东西将不再有效,比如不能再通过request.getAttribute()取得对象,也不能取得action的实例、errors、field errors等。

Redirect Result与Dispatcher Result的区别源于JSP篇中<jsp:forward>标签与response.redirect()的区别。

如图5.11所示,用Redirect Result跳转指向另一个URL,这个URL是一个新的action。

图5.11 Redirect Result流程图

5.6.4 创建Action链

Chain Result是一种Result类型,它基于自己的拦截器stack(堆栈)和Result调用一个Action,这样允许一个Action附带着原来的状态将请求转到目标Action。

Struts2提供把多个Action按照预先定义好的顺序或者流程链接起来的能力。这个特性通过给指定的Action设置一个Chain Result,然后通过一个ChainingInterceptor拦截目标Action来实现,如实例5-28所示。

Action链的流程如图5.12所示。

【实例5-28】Chain Result:struts.xml片段

01     <package name="public" extends=" struts -default">
02          <!--action链, 使用缺省参数r-->
03          <action name="createAccount" class="...">
04                <result type="chain">login</result>
05          </action>
06
07          <action name="login" class="...">
08               <!--链接到另一个命名空间-->
09                <result type="chain">
10                     <param name="actionName">dashboard</param>
11                     <param name="namespace">/secure</param>
12                </result>
13          </action>
14     </package>
15
16     <package name="secure" extends=" struts -default" namespace="/secure">
17          <action name="dashboard" class="...">
18                <result>dashboard.jsp</result>
19          </action>
20     </package>

图5.12 Action链流程图

如果需要把Action链中早先的Actions的属性复制到当前的Action中,应该采用ChainingInterceptor。这个拦截器会从request和ValueStack中复制所有的原始参数传给目标action。ValueStack会记录action源的信息,这样目标action就可以通过ValueStack访问早先的action的属性,这些属性也能被action链中最后的result访问,例如JSP或者Velocity页面。

Action链通常用来提供查找列表(例如状态的下拉列表等)。既然这些action已经放入了ValueStack,它们的属性在表现层就是可用的。这个功能也可以使用action标签(ActionTag)在显示页面执行一个action来做到,也可以利用Redirect Action Result来完成这样的功能。

5.6.5 整合各种View技术

Velocity、Freemarker、JasperReports、XSLT这4种result都是为了整合不同的视图技术而设计的。

1. Velocity Result

Velocity是一个基于Java的模板引擎(template engine)。它允许任何人仅仅简单地使用模板语言(template language)来引用由Java代码定义的对象。第6章会有详细叙述。

Velocity Result用Servlet容器中的JspFactory模拟JSP执行环境来显示Velocity模板,然后以流的形式输出到Servlet Output。

模板语言是强大的、直观的,其不必像JSP一样先被编译为JavaServlet再执行,而是被直接解析,因此其编译器速度快,输出速度接近静态HTML页面的速度。

2. Freemarker Result

Freemarker也是一个模板引擎,允许JavaServlet保持图形设计同应用程序逻辑的分离,这是通过在模板中密封HTML完成的。模板用Servlet提供的数据动态地生成HTML。

Freemarker Result一切使用与之前其他result一样,只需将type换为Freemarker。Freemarker类型result的默认变量和dispatcher是一样的,此外还支持contentType类型参数,输出如CSV、纯文本或者XML的格式形式,参数如表5.4所示。

表5.4 Freemarker Result配置参数

3. JasperReports Result

JasperReports是一个基于Java的开源报表工具,它可以在Java环境下像其他IDE报表工具一样来制作报表。JasperReports支持PDF、HTML、XLS、CSV和XML文件输出格式。JasperReports是当前Java开发者最常用的报表工具。

JasperReports Result一切使用与之前其他result一样,只需将type换为jasper。参数和Dispatcher是一样的,如表5.5所示。

4. XSLT Result

XSLT Result用XSLT来转换action对象到XML。

XSLT是eXtensible Stylesheet Language Transformation,是用于XML文档转换的一种标准,借助XSLT可以将XML数据以不同的表现方式表现。XSLT Result的参数如表5.6所示。

表5.5 JasperReports Result配置参数

表5.6 XSLT Result配置参数

注意

在struts2.properties文件中有一项配置与XSLT Result相关。struts.xslt.nocache默认为false,如果设置为true,则禁止样式表缓存。

5.6.6 自定义Result

Struts2也允许用户自定义自己的Result类型,只要实现com.opensymphony.xwork2.Result接口就可以了。实例5-29模拟了一种Result,作用是根据处理结果给指定用户发送一份E-mail。这个Result需要4个参数to、from、subject和body。

【实例5-29】自定义result:SendmailResult.java

package register;
01     import com.opensymphony.xwork2.ActionInvocation;
02     import com.opensymphony.xwork2.Result;
03     //自定义Result类型
04     public class SendmailResult implements Result {
05          //简单属性
06          private String to;
07          private String from;
08          private String subject;
09          private String body;
10          //重写execute()方法
11          public void execute(ActionInvocation invocation) throws Exception {
12               // 实现Email发送部分
13               System.out.println("sending mail....");
14               System.out.println("      To:" + to);
15               System.out.println("    From:" + from);
16               System.out.println("Subject:" + subject);
17          }
18          //以下是属性的setter/getter方法
19          public String getBody() {                     //关于body属性的getter和setter方法
20                return body;
21          }
22          public void setBody(String body) {
23                this.body = body;
24          }
25          public String getFrom() {                     //关于from属性的getter和setter方法
26                return from;
27          }
28          public void setFrom(String from) {
29                this.from = from;
30          }
31          public String getSubject() {                  //关于subject属性的getter和setter方法
32                return subject;
33          }
34          public void setSubject(String subject) {
35                this.subject = subject;
36          }
37          public String getTo() {                     //关于to属性的getter和setter方法
38                return to;
39          }
40          public void setTo(String to) {
41                this.to = to;
42          }
43     }

【代码剖析】上述代码首先创建了关于E-mail的各种属性,分别为to、from、subject和body,然后为每个属性设置setter和getter方法,最后在execute()方法中实现逻辑功能。

在struts.xml中定义如实例5-30,这里用到了一个空action,没有定义action的class属性,Struts2将默认调用ActionSupport,直接返回SUCCESS。

【实例5-30】自定义result:struts.xml片段

01     <result-types>
02          <result-type name="sendmail"
03                class="register.SendmailResult" />
04          </result-types>
05     <!--action定义:-->
06     <action name="testSendmail">
07          <result name="success" type="sendmail">
08                <param name="from">root@sina.com</param>
09                <param name="to">user@sina.com</param>
10                <param name="subject">hello, webwork!</param>
11          </result>
12     </action>

图5.13 运行结构

【代码剖析】上述代码实现对Action类的配置。

测试这个action可以直接访问http://127.0.0.1:8080/struts2/testSendmail.action,可以在控制台中看到打印结果,如图5.13所示。