前言
在当前数字化时代,数据的高效传输与处理已成为软件开发领域中至关重要的环节。UniHttp 作为一种高性能的 HTTP 客户端库,提供了便捷的网络通信解决方案。但在天地图驾车导航等场景中,返回数据格式为 XML,而 XML 的数据格式在应用中存在着较多的不便。将 XML 数据与 JavaBean 进行相互转换,可以提高代码的可读性和可维护性。在使用 UniHttp 进行网络请求时,如何高效地实现 XML 和 JavaBean 的序列化与反序列化,成为了开发者需要解决的关键问题。本文将详细探讨在 UniHttp 环境下,实现 XML 和 JavaBean 序列化的多种方式。
一、使用 JAXB 的数据转换
JAXB(Java Architecture for XML Binding)是 Java 平台的一部分,它提供了一种便捷的方式,用于在 Java 类和 XML 表示形式之间进行数据绑定。简单来说,JAXB 能够将 Java 对象(通常是 JavaBean)转换为 XML 数据(序列化),也可以将 XML 数据转换为 Java 对象(反序列化)。
1、Jaxb 特性
- 易用性:JAXB 提供了注解驱动的方式来定义 Java 类和 XML 之间的映射关系。开发者只需要在 Java 类上添加一些简单的注解,如
@XmlRootElement、@XmlElement 等,就可以清晰地指定类的属性如何映射到 XML 元素。
- 标准性:JAXB 是 Java EE 的一部分,它遵循 Java 社区的标准规范。这意味着它在不同 Java 开发环境中具有良好的兼容性和一致性。
- 性能:JAXB 在性能方面表现良好。它在序列化和反序列化过程中进行了优化,能够快速地将 Java 对象和 XML 数据进行转换。
2、实现原理
(一)序列化(Java 对象到 XML)
- 创建 JAXBContext:JAXBContext 是 JAXB API 的入口点,负责管理 Java 类和 XML 数据之间的映射信息。
- 创建 Marshaller:通过 JAXBContext 的
createMarshaller() 方法可以创建一个 Marshaller 实例。
- 序列化操作:使用 Marshaller 的
marshal() 方法将 Java 对象序列化为 XML 数据。
(二)反序列化(XML 到 Java 对象)
- 创建 JAXBContext:同样需要创建一个 JAXBContext 实例。
- 创建 Unmarshaller:通过 JAXBContext 的
createUnmarshaller() 方法可以创建一个 Unmarshaller 实例。
- 反序列化操作:使用 Unmarshaller 的
unmarshal() 方法将 XML 数据反序列化为 Java 对象。
3、Jaxb 注解简介
- @XmlRootElement:用于指定一个 Java 类作为 XML 文档的根元素。
- @XmlElement:用于指定 Java 类的属性或字段映射到 XML 元素。
- @XmlAttribute:用于将 Java 类的属性或字段映射为 XML 元素的属性。
- @XmlAccessorType:用于指定类成员的访问策略。
4、编码实现
首先我们看一下使用 Jaxb 的自助编码方式来进行 Xml 和 JavaBean 的定义实现 UniHttp 接口定义如下:
package com.yelang.project.thridinterface;
import com.burukeyou.uniapi.http.annotation.HttpApi;
import com.burukeyou.uniapi.http.annotation.param.QueryPar;
import com.burukeyou.uniapi.http.annotation.request.GetHttpInterface;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
@HttpApi(url = "http://api.tianditu.gov.cn/")
public interface TdtOptionService {
@GetHttpInterface("drive")
public HttpResponse<String> drivePlan(@QueryPar("postStr") String postStr,
@QueryPar("type") String type,
@QueryPar("tk") String tk);
}
请注意以上接口,驾车规划返回的对象值是:HttpResponse。在调用接口之后使用编码的形式来实现自定义的转换。来看一下手动的调用服务及转换方法如下:
package com.yelang.project.unihttp;
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
import com.google.gson.Gson;
import com.yelang.project.education.domain.tdt.TdtResult;
import com.yelang.project.thridinterface.TdtOptionService;
@SpringBootTest
public class TdtUniHttpCase {
private static final String TDT_SERVER_KEY = "tdt_key";
@Autowired
private TdtOptionService tdtOptService;
@Test
public void xml2JavaBean() {
String origInfo = "113.216171,28.190967";
String destInfo = "112.957124,28.198626";
String postStr = "%7B'orig':'" + origInfo + "','dest':'" + destInfo + "','style':'2'%7D";
HttpResponse<String> resp = tdtOptService.drivePlan(postStr, , TDT_SERVER_KEY);
{
System.out.println(resp.getBodyResult());
JAXBContext.newInstance(TdtResult.class);
context.createUnmarshaller();
(TdtResult) unmarshaller.unmarshal( (resp.getBodyResult()));
System.out.println( + result.getDistance());
System.out.println( + result.getDuration());
();
System.out.println(gson.toJson(result));
} (JAXBException e) {
e.printStackTrace();
}
}
}
可以看到可以正常的输出 xml 结果,也可以将 xml 转换成 javabean 后进行展示。
二、基于 XmlSerializeConverter 的数据转换
使用上述方法对 xml 对象转换为 JavaBean 之后,虽然功能上基本是达到了我们的期望,但是有完美主义的同学一定注意到,使用这种机制不太友好,对代码的有一定的侵入性,而且要编写的代码挺多的,是否有一种机制不仅能保证对象的顺利转换,同时也能保持代码优雅性呢?本节我们就来讲讲 unihttp 的 XmlSerializeConverter 模式。
1、XmlSerializeConverter
这里我们首先来看一下 UniHttp 这个工具,我们在其核心注解 HttpApi 中可以看到以下的代码定义:
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HttpApi {
Class<? extends XmlSerializeConverter> xmlConverter() default JaxbXmlSerializeConverter.class;
}
在代码的最后就有一个属性,是一定自定义的 xmlConverter,是一个 xml 的转换器,通过这个转换器就可以实现对象的高速映射。因此我们就可直接使用 UniHttp 自带的这个属性来进行实现。先来看看 XmlSerializeConverter 是什么?打开源码后发现:
public interface XmlSerializeConverter extends SerializeConverter {
String serialize(Object object);
Object deserialize(String xml, Type type);
}
你会发现这是一个 xml 转换的接口,核心方法就是两个,第一个是序列化节后,第二个是反序列化接口。
2、JaxbXmlSerializeConverter 的具体实现
在 HttpApi 这个类中,有一个关于 xml 转换器的默认实现,见如下代码:
Class<? extends XmlSerializeConverter> xmlConverter() default JaxbXmlSerializeConverter.class;;
这里明确指出了其具体的实现方式,下面结合代码来讲讲具体如何进行配置。
3、实现方法
为了在 httpAPI 中使用 xml 转换器,首先在声明接口时做如下定义:
@HttpApi(url = "http://api.tianditu.gov.cn/", xmlConverter = JaxbXmlSerializeConverter.class)
public interface TdtDriveService {
@GetHttpInterface("drive")
public TdtResult drivePlan(@QueryPar("postStr") String postStr,
@QueryPar("type") String type,
@QueryPar("tk") String tk);
}
请注意,这里的方法返回,我们就可以直接使用一个 JavaBean 来接收,而不是 HttpResponse 对象了。调用的逻辑简单:
@Test
public void testByJaxbXmlSerializeConverter() {
System.out.println("testByJaxbXmlSerializeConverter 进行 xml 转换");
String origInfo = "113.216171,28.190967";
String destInfo = "112.957124,28.198626";
String postStr = "%7B'orig':'" + origInfo + "','dest':'" + destInfo + "','style':'2'%7D";
TdtResult result = tdtDriveService.drivePlan(postStr, "search", TDT_SERVER_KEY);
System.out.println("距离:" + result.getDistance());
System.out.println("时长:" + result.getDuration());
System.out.println("起始点:" + result.getParameters().getOrig());
System.out.println(result);
}
说明我们的程序运行正常,输出正常。
三、其它第三方实现
当然会有朋友问,如何既不想使用硬编码的方式进行实现,也不想使用默认的转换器来实现,就想自己手动发明轮子,采用完全自定义的方式来实现又该如何实现呢?本节来介绍一下如何进行完全自定义的实现。
1、实现方法
在序列化请求体和反序列化响应体默认使用的是 jaxb. 如果想要修改其他序列化方式。可以实现 XmlSerializeConverter 接口,并配置到 @HttpApi 注解上。自定义 XML 序列化逻辑如下代码所示:
public class DiyXMLSerializeConverter implements XmlSerializeConverter {
@Override
public String serialize(Object object) {
return null;
}
@Override
public Object deserialize(String xml, Type type) {
return null;
}
}
通过这种方式自己定义相应的转换器,然后跟前面的使用的默认转换器一样,在创建 HttpAPI 类中进行定义和绑定,如下所示:
@HttpApi(xmlConverter = DiyXMLSerializeConverter.class)
interface UserAPI { }
其它的参数传递和设置跟前面的内容基本一致,在此不再进行赘述。
四、总结
本文探讨了在 UniHttp 环境下实现 XML 和 JavaBean 序列化的多种方式,包括使用原生 JAXB 库、UniHttp 自带的 XmlSerializeConverter 模式以及完全自定义的转换器。结合天地图路径规划功能展示了实际案例,帮助开发者根据需求选择合适的序列化策略,优化网络通信过程。