探索 UniHttp:解锁 Xml 及 JavaBean 序列化的多种方式

探索 UniHttp:解锁 Xml 及 JavaBean 序列化的多种方式

目录

前言

一、使用JAXB的数据转换

1、Jaxb特性

2、实现原理

(一)序列化(Java 对象到 XML)

(二)反序列化(XML 到 Java 对象)

3、Jaxb注解简介

4、编码实现

二、基于XmlSerializeConverter的数据转换

1、XmlSerializeConverter

2、JaxbXmlSerializeConverter的具体实现

3、实现方法

三、其它第三方实现

1、实现方法

四、总结


前言

        在当今数字化时代,数据的高效传输与处理已成为软件开发领域中至关重要的环节。在之前内容中介绍了天地图的行车规划接口,基于GeoTools和SpringBoot的省域驾车最快路线生成实践,也介绍了UniHttp这个工具。UniHttp,作为一种高性能的 HTTP 客户端库,凭借其强大的功能和灵活的配置,为广大开发者提供了便捷的网络通信解决方案。但是在天地图驾车导航中,其返回的数据格式是Xml的,而Xml的数据格式在应用中存在着较多的不便。

        在与天地图进行交互时,路径规划请求与响应数据通常以 Xml 格式进行传输。这就需要开发者能够熟练掌握 Xml 的序列化与反序列化技术,以便准确地构建请求并解析响应数据。而 JavaBean 则以其简洁明了的结构和易于操作的特性,在 Java 开发中被广泛用于封装数据。将 Xml 数据与 JavaBean 进行相互转换,不仅可以提高代码的可读性和可维护性,还能更好地利用 Java 的面向对象特性进行数据处理。

        在使用 UniHttp 进行网络请求时,如何高效地实现 Xml 和 JavaBean 的序列化与反序列化,成为了开发者需要解决的关键问题。目前,存在多种方式可以实现这一目标,每种方式都有其独特的优缺点和适用场景。通过对这些方式的深入探索与研究,我们可以更好地根据实际需求选择合适的序列化策略,从而优化网络通信过程,提高系统的整体性能。

        在接下来的内容中,我们将详细探讨在 UniHttp 环境下,实现 Xml 和 JavaBean 序列化的多种方式。我们将从基础的序列化原理入手,逐步深入到各种具体实现方法,包括但不限于使用原生的 Java 库、第三方序列化工具以及自定义序列化器等。同时,结合天地图的路径规划功能,我们将通过实际案例展示如何在实际开发中应用这些序列化方式,以实现高效、准确的数据交互。通过对这些内容的深入剖析,希望能够为使用 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 元素。例如,使用@XmlRootElement注解可以指定一个 Java 类作为 XML 文档的根元素。这种方式使得代码更加直观易懂,减少了编写繁琐的 XML 处理代码的工作量。

        标准性

  • JAXB 是 Java EE(Java Platform, Enterprise Edition)的一部分,它遵循 Java 社区的标准规范。这意味着它在不同 Java 开发环境中具有良好的兼容性和一致性。开发者可以利用 JAXB 在各种 Java 应用程序中进行 XML 数据的处理,无论是 Web 应用、企业级应用还是桌面应用等。

        性能

  • JAXB 在性能方面表现良好。它在序列化和反序列化过程中进行了优化,能够快速地将 Java 对象和 XML 数据进行转换。这对于处理大量数据或者对性能要求较高的应用程序来说是非常重要的。例如,在一些需要频繁与外部系统进行 XML 数据交互的企业级应用中,JAXB 能够高效地完成数据转换任务。

2、实现原理

(一)序列化(Java 对象到 XML)

  1. 创建 JAXBContext
    • JAXBContext 是 JAXB API 的入口点,它负责管理 Java 类和 XML 数据之间的映射信息。要进行序列化操作,首先需要创建一个 JAXBContext 实例。这通常是通过指定包含要序列化对象的 Java 类的类名来实现的。例如,JAXBContext jaxbContext = JAXBContext.newInstance(MyJavaBeanClass.class);,这里的MyJavaBeanClass就是需要序列化的 Java 类。
  2. 创建 Marshaller
    • Marshaller 是用于将 Java 对象序列化为 XML 数据的类。通过 JAXBContext 的createMarshaller()方法可以创建一个 Marshaller 实例。然后可以设置 Marshaller 的一些属性,比如是否格式化输出 XML 数据(marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);),这可以让生成的 XML 数据更易于阅读。
  3. 序列化操作
    • 最后,使用 Marshaller 的marshal()方法将 Java 对象序列化为 XML 数据。这个方法可以将 Java 对象写入到多种输出目标,如OutputStreamWriterFile等。例如,marshaller.marshal(myJavaBeanObject, System.out);将 Java 对象myJavaBeanObject序列化为 XML 数据并输出到控制台。

(二)反序列化(XML 到 Java 对象)

  1. 创建 JAXBContext(与序列化相同)
    • 同样地,需要创建一个 JAXBContext 实例,指定包含目标 Java 类的类名。
  2. 创建 Unmarshaller
    • Unmarshaller 是用于将 XML 数据反序列化为 Java 对象的类。通过 JAXBContext 的createUnmarshaller()方法可以创建一个 Unmarshaller 实例。
  3. 反序列化操作
    • 使用 Unmarshaller 的unmarshal()方法将 XML 数据反序列化为 Java 对象。这个方法可以从多种输入源读取 XML 数据,如InputStreamReaderFile等。例如,MyJavaBeanClass myJavaBeanObject = (MyJavaBeanClass) unmarshaller.unmarshal(new File("data.xml"));将文件data.xml中的 XML 数据反序列化为MyJavaBeanClass类型的 Java 对象。

3、Jaxb注解简介

        @XmlRootElement

  • 用于指定一个 Java 类作为 XML 文档的根元素。例如,在@XmlRootElement(name = "Person")注解的 Java 类Person中,当序列化为 XML 时,XML 文档的根元素为<Person>……</Person>

        @XmlElement

  • 用于指定 Java 类的属性或字段映射到 XML 元素。例如,@XmlElement(name = "Name")注解的name字段,在序列化时会生成<Name>……</Name>这样的 XML 元素。

        @XmlAttribute

  • 用于将 Java 类的属性或字段映射为 XML 元素的属性。例如,@XmlAttribute(name = "id")注解的id字段,在序列化时会生成类似<Person>……</Person>的 XML 元素属性。

        @XmlAccessorType

  • 用于指定类成员的访问策略,决定了哪些成员(字段、属性等)会被 JAXB 处理。常见的取值有XmlAccessType.FIELD(处理字段)、XmlAccessType.PROPERTY(处理属性)等。例如,@XmlAccessorType(XmlAccessType.FIELD)表示 JAXB 会处理类的字段。

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<String>。在调用接口之后使用编码的形式来实现自定义的转换。来看一下手动的调用服务及转换方法如下:

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.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import com.burukeyou.uniapi.annotation.UniAPIScan; import com.burukeyou.uniapi.http.core.response.HttpResponse; import com.google.gson.Gson; import com.yelang.common.utils.StringUtils; import com.yelang.project.education.domain.TdtSearchVo; import com.yelang.project.education.domain.tdt.TdtResult; import com.yelang.project.thridinterface.TdtDriveService; import com.yelang.project.thridinterface.TdtOptionService; @SpringBootTest @RunWith(SpringRunner.class) @UniAPIScan("com.yelang.project.thridinterface") // 指定@HttpApi接口所在的包路径 public class TdtUniHttpCase { private static final String TDT_SERVER_KEY = "tdt_key"; private static final String QUERY = "query"; @Autowired private TdtOptionService tdtOptService; @Test public void xml2JavaBean() { String origInfo = "113.216171,28.190967";//黄花国际机场 String destInfo = "112.957124,28.198626";//橘子洲景区 // style 默认0 (0:最快路线,1:最短路线,2:避开高速,3:步行) // 这里选择避开高速 String postStr = "%7B'orig':'" + origInfo + "','dest':'" + destInfo + "','style':'2'%7D" ; HttpResponse<String> resp = tdtOptService.drivePlan(postStr,"search",TDT_SERVER_KEY); try { System.out.println(resp.getBodyResult()); JAXBContext context = JAXBContext.newInstance(TdtResult.class); Unmarshaller unmarshaller = context.createUnmarshaller(); TdtResult result = (TdtResult) unmarshaller.unmarshal(new StringReader(resp.getBodyResult())); System.out.println("距离: " + result.getDistance()); System.out.println("时长: " + result.getDuration()); System.out.println("起始点: " + result.getParameters().getOrig()); // 输出其他需要的数据... Gson gson = new Gson(); System.out.println("json格式化如下:"); System.out.println(gson.toJson(result)); System.out.println(result); } catch (JAXBException e) { e.printStackTrace(); } } }

        按照上面介绍的内容,我们自定义实现转换。执行完毕后可以在控制台中看到如下输出:

        可以看到可以正常的输出xml结果,也可以将xml转换成javabean后进行展示。

二、基于XmlSerializeConverter的数据转换

        使用上述方法对xml对象转换为JavaBean之后,虽然功能上基本是达到了我们的期望,但是有完美主义的同学一定注意到,使用这种机制不太友好,对代码的有一定的侵入性,而且要编写的代码挺多的,是否有一种机制不仅能保证对象的顺利转换,同时也能保持代码优雅性呢?本节我们就来讲讲unihttp的XmlSerializeConverter模式。

1、XmlSerializeConverter

        这里我们首先来看一下UniHttp这个工具,我们在其核心注解HttpApi中可以看到以下的代码定义:

package com.burukeyou.uniapi.http.annotation; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.burukeyou.uniapi.http.core.serialize.json.FastJson2SerializeConverter; import com.burukeyou.uniapi.http.core.serialize.json.JsonSerializeConverter; import com.burukeyou.uniapi.http.core.serialize.xml.JaxbXmlSerializeConverter; import com.burukeyou.uniapi.http.core.serialize.xml.XmlSerializeConverter; import com.burukeyou.uniapi.http.extension.client.OkHttpClientFactory; import com.burukeyou.uniapi.http.extension.processor.HttpApiProcessor; /** * HTTP API configuration * suggest config channel-related parameters * The HTTP API annotation of UniAPI can be marked on a class or interface, * indicating that the proxy logic of HTTP API can be applied to the methods of that class or interface, * helping us quickly send and deserialize an HTTP request * @author caizhihao */ @Inherited @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface HttpApi { /** * Configure global HTTP request URL * Support taking values from environmental variables, such as ${xx.url} */ String url() default ""; /** * Specify extension points for custom HTTP requests during execution * please see {@link HttpApiProcessor} */ Class<? extends HttpApiProcessor<? extends Annotation>> processor()[] default {}; /** * Config custom http client, if not config will use default http client */ Class<? extends OkHttpClientFactory> httpClient()[] default {}; /** * Config custom json converter, to serialize and deserialize http body in json */ Class<? extends JsonSerializeConverter> jsonConverter() default FastJson2SerializeConverter.class; /** * Config custom xml converter, to serialize and deserialize http body in xml */ Class<? extends XmlSerializeConverter> xmlConverter() default JaxbXmlSerializeConverter.class;; }

        在代码的最后就有一个属性,是一定自定义的xmlConverter,是一个xml的转换器,通过这个转换器就可以实现对象的高速映射。因此我们就可直接使用UniHttp自带的这个属性来进行实现。先来看看XmlSerializeConverter是什么?打开源码后发现:

package com.burukeyou.uniapi.http.core.serialize.xml; import java.lang.reflect.Type; import com.burukeyou.uniapi.http.core.serialize.SerializeConverter; /** * xml * * @author caizhihao */ public interface XmlSerializeConverter extends SerializeConverter { /** * Convert the object to an XML string * @param object wait to be converted * @return XML string */ String serialize(Object object); /** * Convert the XML string to an object * @param xml wait to be converted * @param type the type of the object * @return the object */ Object deserialize(String xml, Type type); }

        你会发现这是一个xml转换的接口,核心方法就是两个,第一个是序列化节后,第二个是反序列化接口。请记住这个接口,后面在将自定义实现的时候,还会涉及这个接口。

2、JaxbXmlSerializeConverter的具体实现

在HttpApi这个类中,有一个关于xml转换器的默认实现,见如下代码:

/** * Config custom xml converter, to serialize and deserialize http body in xml */ Class<? extends XmlSerializeConverter> xmlConverter() default JaxbXmlSerializeConverter.class;;

        这里明确指出了其具体的实现方式,下面结合代码来讲讲具体如何进行配置。

3、实现方法

        为了在httpAPI中使用xml转换器,首先在声明接口时做如下定义:

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.serialize.xml.JaxbXmlSerializeConverter; import com.yelang.project.education.domain.tdt.TdtResult; @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对象了。调用的逻辑简单:

/** * - testByJaxbXmlSerializeConverter 默认xml序列化实战 */ @Test public void testByJaxbXmlSerializeConverter() { System.out.println("testByJaxbXmlSerializeConverter进行xml转换"); String origInfo = "113.216171,28.190967";//黄花国际机场 String destInfo = "112.957124,28.198626";//橘子洲景区 // style 默认0 (0:最快路线,1:最短路线,2:避开高速,3:步行) // 这里选择避开高速 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序列化逻辑如下代码所示:

package com.yelang.project.thridinterface.converter; import java.lang.reflect.Type; import com.burukeyou.uniapi.http.core.serialize.xml.XmlSerializeConverter; 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 序列化的多种方式。我们将从基础的序列化原理入手,逐步深入到各种具体实现方法,包括但不限于使用原生的 Java 库、第三方序列化工具以及自定义序列化器等。同时,结合天地图的路径规划功能,我们将通过实际案例展示如何在实际开发中应用这些序列化方式,以实现高效、准确的数据交互。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

Read more

OPC转Web API服务器框架源码:集成IoT的C#高性能高并发服务器服务带手机app测试d...

OPC转Web API服务器框架源码:集成IoT的C#高性能高并发服务器服务带手机app测试d...

OPC转web API服务器框架源码。 集成iot,web api服务,这套带码是通过C#编写集成IOCP高性能高并发优势服务器服务源码。 带手机app测试demo源码 具体具备功能如下: 1、具备EF6+mssql数据库功能,可更改为MYSQL或SQLITe. 2、自带WEB API服务,抛弃IIS支持。 用户可以通过WEB前端直接读取远程设备数据以及下发控制指令。 WEB API功能有服务器日志查询、WEB API接口认证用户管理、远端设备注册管理、服务器轮询读取任务启停、服务器参数设置、查询历史数据记录、下发指令到终端设备。 3、系统目前支持modbus 、modbus rtu协议,可定制开发集成Modbus TCp、西门子PLC S7协议、OPC协议、三菱PLC协议以及集成MQTT服务(以上协议在框架中没有集成,可以定制集成)。 4、系统自带MVC服务,开发API像平常使用的一样方便。 另外它自带硬件协议驱动。 5、与传统协议方法不同,比如Modbus设备,需要PC端主动去连接设备,而这套框架只需要监听端口,服务器就能自动去轮询终端所有设备。 6、

By Ne0inhk
vkedit:专业级 Vue3 Web 图形编辑器 npm 包,标签/票据/二维码设计一键搞定

vkedit:专业级 Vue3 Web 图形编辑器 npm 包,标签/票据/二维码设计一键搞定

vkedit:专业级 Vue3 Web 图形编辑器 npm 包,标签/票据/二维码设计一键搞定 📊 为什么选择 vkedit? 🌐 专为 Web 开发打造的 Vue3 npm 包 vkedit 是一个完全基于 Web 技术栈的图形编辑器解决方案,专为 Vue3 项目设计: * 纯前端实现:无需后端服务,完全在浏览器中运行 * Vue3 原生支持:基于 Vue 3 Composition API 开发,完美融入 Vue 项目 * npm 包管理:通过 npm/pnpm/yarn 一键安装,版本管理方便 * TypeScript 支持:完整的类型定义,

By Ne0inhk

Clawdbot+Qwen3-32B保姆级教程:从环境准备到Web Chat可用的完整链路

Clawdbot+Qwen3-32B保姆级教程:从环境准备到Web Chat可用的完整链路 1. 为什么需要这个组合:一句话说清价值 你是不是也遇到过这些问题:想本地跑一个真正能用的大模型,但Qwen3-32B这种大块头动辄需要2×A100显卡,部署门槛高;想快速搭个聊天界面,又不想从零写前端、配后端、接API;好不容易调通了Ollama,却发现网页访问不了,跨域报错、端口不通、代理转发一头雾水? Clawdbot+Qwen3-32B这套组合,就是为解决这些“卡脖子”环节而生的——它不碰CUDA编译、不改模型权重、不手写WebSocket服务,而是用极简配置把私有大模型能力,稳稳地托举到浏览器里。你只需要一台带NVIDIA GPU的机器(RTX 4090/3090/A6000均可),15分钟内就能拥有一个专属、离线、可对话的AI聊天页。 这不是概念演示,也不是Demo玩具。它已经稳定运行在多个内部知识助手、技术文档问答和代码辅助场景中,支持连续多轮对话、上下文记忆、流式输出,且全程不依赖任何公网API。 下面我们就从零开始,一步步带你走通这条“

By Ne0inhk
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典

【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典

半桔:个人主页  🔥 个人专栏: 《前端扫盲》《手撕面试算法》《C++从入门到入土》 🔖阻止了我的脚步的,并不是我所看见的东西,而是我所无法看见的那些东西。 《海上钢琴师》 文章目录 * 前言 * 一. CSS是什么 * 1.1 概念 * 1.2 基本语法 * 二. CSS如何引入HTML * 2.1 内部样式表 * 2.2 行内选择器 * 2.3 外部引入 * 三. CSS选择器 * 3.1 基础选择器 * 3.1.1 标签选择器 * 3.1.2 类选择器 * 3.1.3 id选择器 * 3.

By Ne0inhk