在Struts2框架里,Action执行完毕后默认会转向一个JSP或HTML视图,但在提供数据接口时,我们往往希望直接把XML字符串返回给调用方。这就涉及到结果类型(Result Type)的切换。Struts2通过struts.xml中的result元素来定义跳转方式,只要把type指定为合适的值,就能改变响应形态。

一、使用stream结果类型手动返回XML
stream是Struts2内置的结果类型,它的作用是把Action中的一个InputStream直接写入HTTP响应体。由于XML本质就是一段文本,我们可以先把XML拼成字符串,再用字节流输出,从而完全控制内容和头部。
在Action类中,定义一个InputStream类型的字段,并提供getter。通常我们用ByteArrayInputStream包装XML字符串的字节数组,同时记得指定字符集,避免中文乱码。下面给出一个最小可运行示例:
package com.demo.action;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.opensymphony.xwork2.ActionSupport;
public class XmlAction extends ActionSupport {
private InputStream xmlStream;
public InputStream getXmlStream() {
return xmlStream;
}
public String execute() throws Exception {
String xml = "<?xml version="1.0" encoding="UTF-8"?>"
+ "<user><name>张三</name><age>28</age></user>";
xmlStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
return SUCCESS;
}
}
对应的struts.xml配置需要把result的type设为stream,并通过param子元素指定输入流属性名与内容类型。contentType必须写成text/xml或者application/xml,这样浏览器和接口调用工具才能正确解析。
<package name="default" extends="struts-default">
<action name="xmlTest" class="com.demo.action.XmlAction">
<result name="success" type="stream">
<param name="inputName">xmlStream</param>
<param name="contentType">text/xml;charset=UTF-8</param>
</result>
</action>
</package>
这种写法的优点是逻辑直观,适合动态拼装复杂报文;缺点是要自己处理XML转义与格式,代码略显冗长。如果XML结构固定,更推荐后面介绍的xslt方式。
二、使用xslt结果类型自动转换JavaBean
xslt结果类型允许Struts2把一个暴露给OGNL的对象树,按照XSL样式表转换成XML输出。它底层依赖JDK的Transformer,适合把已有POJO直接序列化为标准XML,而不必手写字符串。
先在Action里准备一个数据对象,比如一个List或单个实体,并在struts.xml中把result的type配置为xslt,同时通过param指定样式表位置与输出属性。XSL文件需放在类路径或Web目录下,负责定义节点名称与层级。
package com.demo.action;
import java.util.ArrayList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class UserListAction extends ActionSupport {
private List<String> users = new ArrayList<String>();
public List<String> getUsers() {
return users;
}
public String execute() {
users.add("张三");
users.add("李四");
return SUCCESS;
}
}
struts.xml中的配置片段如下,location指向Web根目录下的xsl文件,让框架自动完成转换:
<action name="userXml" class="com.demo.action.UserListAction">
<result name="success" type="xslt">
<param name="location">/user.xsl</param>
<param name="mimeType">text/xml</param>
</result>
</action>
对应的user.xsl可用标准XSLT语法遍历users集合。该方式减少了Java端的字符串拼接,但要求开发者懂一点XSL,且调试不如直接写流直观。
三、常见配置误区与排查
很多接口异常并不是代码错,而是result参数没配对。比如忘记写inputName,框架就不知道读哪个字段;或者contentType只写了text/xml却没带charset,某些旧客户端会按系统默认编码解读,导致汉字变问号。
另一个坑是extends的包必须是struts-default,否则stream和xslt这些内置类型没有注册,启动时会报找不到结果类型。如果用了自定义拦截器栈,也要确认没有把响应体提前提交,否则流写不进去。排查时可以先在浏览器访问Action,用开发者工具看响应头里的Content-Type,再对照配置逐项核实。
| 结果类型 | 适用场景 | 主要参数 |
|---|---|---|
| stream | 手动控制XML内容 | inputName, contentType |
| xslt | POJO自动转XML | location, mimeType |
掌握这两种配置办法后,Struts2返回XML就不再依赖页面模板,能够轻松支撑外部系统对接。实际项目中建议把字符集统一成UTF-8,并在Action外层加一层异常拦截,保证出错时也返回合法XML而非HTML错误页。