XML类型是使用最广泛的数据类型,Jersey 对XML类型的数据处理,支持Java领域的两大标准,即JAXP(Java API for XML Processing,JSR-206)和JAXB(Java Architecture for XML Binding,JSR-222),JAXP标准包含了DOM、SAX和StAX 三种解析技术标准。
- DOM是面向文档解析的技术,要求将XML数据全部加载到内存,映射为树和结点模型以实现解析
- SAX是事件驱动的流解析技术,通过监听注册事件,触发回调方法以实现解析
- StAX是拉式流解析技术,拉式解析使得读取过程可以主动推进当前XML位置的指针而不是被动的获得解析中的XML数据。
JAXP定义了三种标准类型的输入接口Source(DOMSource、SAXSource、StreamSource)和输出接口Result(DOMResult、SAXResult和StreamResult),示例代码如下:
/**
* 使用 StAX 拉式流解析技术
*
* @param streamSource
* @return
*/
@POST
@Path("stream")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public StreamSource getStreamSource(StreamSource streamSource) {
return streamSource;
}
/**
* 使用 SAX 事件驱动的流解析技术
*
* @param saxSource
* @return
*/
@POST
@Path("saxsource")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public SAXSource getSAXSource(SAXSource saxSource) {
return saxSource;
}
/**
* 使用DOM面向文档解析技术
*
* @param domSource
* @return
*/
@POST
@Path("domsource")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public DOMSource getSAXSource(DOMSource domSource) {
return domSource;
}
/**
* 使用DOM面向文档解析技术
*
* @param document
* @return
*/
@POST
@Path("doc")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public Document getSAXSource(Document document) {
return document;
}
JAXP 的缺点是需要编码解析XML,则增加了开发成本,但对业务逻辑的实现并没有实质的贡献,JAXB只需要在POJO定义相关的注解,使其和XML的schema对应,无须对XML进行程序式解析,弥补了JAXP的这个缺点,JAXB通过序列化和反序列化实现了XML数据和POJO对象的自动转换过程,JAXB的注解位于javax.xml.bind.annotation 包,从性能来说 JAXB低于JAXP,但使用JAXB的开发效率很高,示例代码如下:
-
POJO代码
@XmlRootElement
public class CreateParam implements Serializable {
private String name;
private String sex;
private TestEnum testEnum;
@XmlAttribute(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute(name = "sex")
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@XmlAttribute(name = "testEnum")
public TestEnum getTestEnum() {
return testEnum;
}
public void setTestEnum(TestEnum testEnum) {
this.testEnum = testEnum;
}
}
@XmlRootElement
public class DemoResult implements Serializable {
private boolean hasError;
private int returnCode;
private String message;
@XmlAttribute(name = "hasError")
public boolean isHasError() {
return hasError;
}
public void setHasError(boolean hasError) {
this.hasError = hasError;
}
@XmlAttribute(name = "returnCode")
public int getReturnCode() {
return returnCode;
}
public void setReturnCode(int returnCode) {
this.returnCode = returnCode;
}
@XmlAttribute(name = "message")
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
-
REST服务代码
@POST
@Path("jaxb")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public DemoResult getEntity(CreateParam createParam) {
DemoResult result = new DemoResult();
result.setHasError(false);
result.setMessage("创建 name=" + createParam.getName() + "\tsex=" + createParam.getSex()
+ "\tenum value=" + createParam.getTestEnum().getEnumValue()
+ "\tenum desc=" + createParam.getTestEnum().getEnumDesc());
System.out.println(createParam.getTestEnum() == TestEnum.Error);
return result;
}
-
单元测试代码
@Test
public void PostJaxbXMLTest() {
CreateParam createParam = new CreateParam();
createParam.setName("jaxbXml");
createParam.setSex("man男人");
createParam.setTestEnum(TestEnum.Error);
Invocation.Builder builder = target.path("demos").path("jaxb").request();
Response response = builder.post(Entity.entity(createParam, MediaType.APPLICATION_XML));
if (response.getStatus() == 200) {
DemoResult result = response.readEntity(DemoResult.class);
System.out.println("result hasError=" + result.isHasError() + "\tmessage=" + result.getMessage());
} else {
System.out.println("response status=" + response.getStatus() + "\tmessage=" + response.getStatusInfo());
}
}
示例中的POJO类,都定义为XML的属性(property)来组织的,POJO的字段也可以作为元素(element)组织,如果REST请求的传输数据量很大,并且无须和外系统对接的场景,建议使用属性来组织XML,这样可以极大的减少XML格式的数据包大小。
注意:Jersey默认设置了XMLConstants.FEATURE_SECURE_PROCESSING属性,当属性和元素过多是,会报"well-formedness error"的警告信息,可以通过设置 MessageProperties.XML_SECURITY_DISABLE 参数值来屏蔽,设置示例如下:
-
REST服务设置
// 继承ResouceConfig类,并增加属性设置
public class RESTfulResourceConfig extends ResourceConfig {
public RESTfulResourceConfig() {
property(MessageProperties.XML_SECURITY_DISABLE, Boolean.TRUE);
}
}
-
客户端设置
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(MessageProperties.XML_SECURITY_DISABLE, Boolean.TRUE);
Client c = ClientBuilder.newClient(clientConfig);