如果您查看链接到的答案,您会发现StreamResult https://docs.oracle.com/javase/7/docs/api/javax/xml/transform/stream/StreamResult.html用来。答案中,有一个StringWriter
被传递给构造函数,但是如果你查看 Javadoc,它有一个重载的构造函数,它也需要一个OutputStream
。所以如果你要返回一个StreamingOutput
,只需通过OutputStream
来自StreamingOutput#write(OutputStream)
方法到StreamResult
构造函数。答案中的其他内容应该是相同的。
return new StreamingOutput() {
@Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(out);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
};
Here's the complete resource class I used to test. Notice that I use @Produces(MediaType.APPLICATION_XML)
. There's no point in setting to application/octet-stream
if the data is XML1.
@Path("dom")
public class DomXmlResource {
@GET
@Produces(MediaType.APPLICATION_XML)
public StreamingOutput getXml() throws Exception {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("company");
doc.appendChild(rootElement);
Element staff = doc.createElement("Staff");
rootElement.appendChild(staff);
staff.setAttribute("id", "1");
Element firstname = doc.createElement("firstname");
firstname.appendChild(doc.createTextNode("yong"));
staff.appendChild(firstname);
return new StreamingOutput() {
@Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
try {
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(out);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
}
Update
要自动下载文件(而不是显示 XML 结果),我们实际上需要添加Content-Disposition
标头与attachment
价值。要做到这一点,而不是返回StreamingOutput
从该方法中,我们应该返回Response
,其中实体将是StreamingOutput
@Path("dom")
public class DomXmlResource {
@GET
@Produces(MediaType.APPLICATION_XML)
public Response getXml() throws Exception {
...
StreamingOutput entity = new StreamingOutput() {
@Override
public void write(OutputStream out)
throws IOException, WebApplicationException {
...
}
};
return Response.ok(entity)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=file.xml")
.build();
}
}
Update 2
如果您还不知道,您可以简单地返回 POJO(或它们的列表),它们将自动序列化为 XML。您不需要手动使用 DOM 类来创建 XML 结构。已经有实体提供商 https://jersey.github.io/documentation/latest/message-body-workers.html它将为我们处理从 POJO 到 XML 的转换。例如,如果我们有以下POJO(需要用注释@XmlRootElement
)
@XmlRootElement
public class User {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
然后我们可以返回它,它会自动序列化为
<user><name>footer</name></user>
这是一个例子
@Path("pojo")
public class PojoXmlResource {
@GET
@Produces("application/xml")
public Response getXml() {
User user = new User();
user.setName("Jane Doe");
return Response.ok(user)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=user.xml")
.build();
}
}
这样就不会那么混乱了,不是吗?如果您想返回用户列表,那么您需要将其包装在GenericEntity
List<User> users = Arrays.asList(user1, user2, user3);
GenericEntity<List<User>> entity = new GenericEntity<List<User>>(users){};
return Response.ok(entity)
...
.build();
1. See: Do I need Content-Type: application/octet-stream for file download? https://stackoverflow.com/q/20508788/2587435