前言
1.网上看了很多资料,都是说JavaBean与XML的互转,但实际上感觉还是叫做DTO与XML互转好一些。毕竟JavaBean的概念比较大。
2.本文主要讲述:以XML为基础,由其定制产生的Bean与对应XML之间的互转分析与实现;
3.看到第2条,有人也许会问为什么不使用主流的XStream等第三方工具。为:目前的三方工具均不支持数组(实际上Java反射难以实现数组型)
这些第三方工具应对简单情况还可以,而真正的交互报文格式相当复杂,会有类似数组类型节点的出现,而这些工具不支持数组,决定了面对复杂格式XML时,只能走上定制实现之路。
4.为什么说是笨拙的?
实现的时候,有了让人烦的环节(下文详述),说明实现的还不太清爽...
并没有对所有情况进行可定制。
鉴于以上几点,故为笨拙说:)
一、Why?
今年3月份,接到开发交强险平台报文交互的任务。
交互报文是XML格式,客户要求交互可根据报文变化进行配置(后未实现),有日志记录。
经讨论,大家产生了将报文交互独立出一个服务层的想法。
二、What?
这个服务层要做什么?
1.提供XML与定制Bean互转的统一的、透明的技术封装
先看一下以前是如何实现报文拼写与解析的:
有人直接使用拼串实现拼写报文,你会看到这样的代码:XML += "<node>"+nodeValue+"</node>";
有人使用JDOM、有人使用DOM4j......当我们发现一种方式有缺陷时(比如JDOM对10M以上XML解析有问题),代码调整量会相当大。
封装就解决了这一问题。
2.提供报文交互的统一的、透明的技术封装
理由同上,之前报文的发送与接收都是使用HttpURLConnection,这东西没有提供超时断开的功能,会导致网络异常时连接耗尽。
现使用Apache的httpclient。
3.添加其它功能
比如客户提出交互日志、定时发送等功能。均可以在此层实现或提供接口。
三、How?
此层的技术核心便是1.如何形成XML定制Bean(规则分析) 2.XML与定制Bean互转(实现)
1.如何形成XML定制Bean(规则分析)
以一个示例XML来说明吧,顺便介绍一些XML、DOM基础知识
<!-- XML命名规则
XML名以下划线或字母开始;
XML名可包含字母、数字、句点、下划线和冒号;
XML名不能包含空格;
XML名不能以数字开始,但可包含数字;
XML名区分大小写。
-->
<!-- XML声明 -->
<?xml version="1.0" encoding="GB2312" standalone="yes" ?>
<!-- Root是XML根结点,唯一 -->
<Root>
<!-- String型
特征:XML Bean中最基本元素(叶子)
转换规则:使用Java中的String表达
-->
<StringType>abcd</StringType>
<!-- List型
特征:其子节点全为相同对象
转换规则:使用Java中的List表达
-->
<ListType>
<ObjectTypeB>
<StringType1>111</StringType1>
<StringType2>222</StringType2>
</ObjectTypeB>
<ObjectTypeB>
<StringType1>111</StringType1>
<StringType2>222</StringType2>
</ObjectTypeB>
</ListType>
<!-- Array型
特征:兄弟节点中即含相同对象,也含其它不相同对象
转换规则:使用Java中的List表达,但变量名采用array$开头
-->
<ObjectArrayType>
<StringType1>111</StringType1>
<StringType2>222</StringType2>
</ObjectArrayType>
<ObjectArrayType>
<StringType1>111</StringType1>
<StringType2>222</StringType2>
</ObjectArrayType>
<OthElement/>
<!-- StringList型
特征:子节点中全部为同名String
转换规则:JDK找不到一个合适的类型,故为其单独建立一个StringList类
属性1:String stringName
属性2:String[] stringValues
-->
<StringListType>
<StringType>111</StringType>
<StringType>222</StringType>
<StringType>333</StringType>
<StringType>444</StringType>
</StringListType>
<!-- Object型
特征:非以上情况
另:Attribute的表达
使用'$'做为分隔符并以attr开头,下面的attr1在类ObjectTypeA中会表示为String attr$attr1
-->
<ObjectTypeA attr1="abc">123</ObjectTypeA>
</Root>
OK,一般XML的拆分不会超出以上几种情况,有了这些拆分规则,我们可以写一个解析器,将XML按规则生成定制Bean了。
附加规则:由于采用反射实现,为了便于调用,所有的Bean必须在一个包内(否则在调用其它Bean时需要知晓它的位置)。
2.XML与Bean互转(实现)
做好定制Bean,只需要同样按照拆分规则使用反射便不难实现XML与定制Bean之间的互转了。一些相关信息可参见以下两篇: