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所示。