通用轉(zhuǎn)換接口設(shè)計(jì)
目錄
- 轉(zhuǎn)換接口的定義
- 轉(zhuǎn)換接口的作用
- 轉(zhuǎn)換接口的使用
- 轉(zhuǎn)換接口的實(shí)現(xiàn)
1. 轉(zhuǎn)換接口的定義
接口是系統(tǒng)內(nèi)部與第三方系統(tǒng)協(xié)議數(shù)據(jù)的相互轉(zhuǎn)換處理過程,轉(zhuǎn)換接口以XML配置的形式把這種處理過程描述出來弃舒,方便接口的開發(fā)與維護(hù)乘凸;
2. 轉(zhuǎn)換接口的作用
- 增加開發(fā)效率椎扬,轉(zhuǎn)換接口抽象出通用的轉(zhuǎn)換處理馍管,開發(fā)只需組裝對應(yīng)轉(zhuǎn)換操作即可去团,減少了重復(fù)開發(fā)的工作寞秃,增加開發(fā)效率瑰枫;
- 降低出錯率踱葛,統(tǒng)一協(xié)議轉(zhuǎn)換之外的處理,接口開發(fā)只需配置相應(yīng)的轉(zhuǎn)換處理光坝,減少代碼量尸诽,降低出錯概率;
- 減少維護(hù)成本教馆,接口配置化后逊谋,對接口協(xié)議的調(diào)整,只需要針對接口配置修改即可土铺;
3. 轉(zhuǎn)換接口的使用
接口配置以XML文件描述胶滋,XSD文件定義節(jié)點(diǎn)結(jié)構(gòu),節(jié)點(diǎn)分為轉(zhuǎn)換接口和擴(kuò)展節(jié)點(diǎn)悲敷,轉(zhuǎn)換節(jié)點(diǎn)用于做數(shù)據(jù)轉(zhuǎn)換處理究恤,可擁有多個子節(jié)點(diǎn),一般先執(zhí)行父節(jié)點(diǎn)后德,后執(zhí)行子節(jié)點(diǎn)部宿,執(zhí)行方式有順序、選擇瓢湃、循環(huán)理张,子節(jié)點(diǎn)如果出現(xiàn)異常,父節(jié)點(diǎn)可捕獲做處理绵患;擴(kuò)展節(jié)點(diǎn)用于對接口配置或轉(zhuǎn)換節(jié)點(diǎn)擴(kuò)展使用雾叭;
3.1 接口配置說明
轉(zhuǎn)換定義文件:有XSD文件表示,定義具體轉(zhuǎn)換節(jié)點(diǎn)落蝙,需描述節(jié)點(diǎn)名稱织狐、參數(shù)名稱,參數(shù)類型和轉(zhuǎn)換處理類筏勒;
<!--MD5加密-->
<xsd:element name="md5">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="nestedConverterType">
<!--MD5處理類-->
<xsd:attribute name="clazz" type="xsd:string"
fixed="com.nnk.ecsys.interfaceConverter.converter.Md5Converter"/>
<!--加密字符串-->
<xsd:attribute name="value" type="paramType" use="required"/>
<!--編碼類型-->
<xsd:attribute name="charsetType" type="paramType" use="optional"/>
<!--大小寫類型-->
<xsd:attribute name="caseType" type="caseType" use="optional"
default="LowerCase"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
轉(zhuǎn)換節(jié)點(diǎn):由XML節(jié)點(diǎn)表示移迫,做具體的轉(zhuǎn)換處理,可有多個輸入?yún)?shù)和一個輸出參數(shù)管行,輸入?yún)?shù)由具體轉(zhuǎn)換節(jié)點(diǎn)定義厨埋,屬性name表示輸出參數(shù),轉(zhuǎn)換結(jié)果以name值作為名稱存入【上下文變量】捐顷;
輸入?yún)?shù):值可直接用字符串表示揽咕,如需引用【上下文變量】則使用${變量名}表示悲酷,還可以相互組合, 如:value="${參數(shù)2} AAA ${參數(shù)2}"亲善,如需要引用對象的參數(shù)设易,則使用${變量名.參數(shù)名}表示,基本用法和EL表達(dá)式類似蛹头;
擴(kuò)展節(jié)點(diǎn):可自定義擴(kuò)展節(jié)點(diǎn)顿肺,針對接口配置或轉(zhuǎn)換節(jié)點(diǎn)做處理,現(xiàn)有擴(kuò)展節(jié)點(diǎn)渣蜗,import可導(dǎo)入其他接口配置屠尊,loadProperty可加載properties文件變量;
示例:
interface-trade.xml
<?xml version="1.0" encoding="UTF-8"?>
<converter xmlns="http://www.007ka.com/schema/converter"
xmlns:extend="http://www.007ka.com/schema/converter/extend"
xmlns:interface="http://www.007ka.com/schema/converter/interface">
<!--導(dǎo)入配置文件-->
<extend:loadProperty location="properties/common.properties"/>
<!--定義請求對象-->
<getRequest name="request"/>
<!--組裝請求報文-->
<interface:tryException errorCode="CEC_FAILED" errorMsg="請求報文組裝異常">
<!--轉(zhuǎn)換參數(shù)-->
<set name="orderReq" value="${request.reqeustParam}" />
<interface:mapget name="cardType" key="${orderReq.providerId}" mappingName="providerMap"/>
<!--組裝協(xié)議-->
<set name="orderInfo"
value="${nnk_merId}|${orderReq.orderId}|${cardType}|${orderReq.unitCount}|"/>
<interface:md5 name="sign" value="${orderInfo}|${inter_channelKey}"
charsetType="${inter_charset}"/>
<interface:newInstance name="httpParam" value="java.util.HashMap">
<set name="httpParam.Orderinfo" value="${orderInfo}"/>
<set name="httpParam.Sign" value="${sign}"/>
</interface:newInstance>
</interface:tryException>
<!--調(diào)用http接口-->
<interface:tryException errorCode="CEC_UNKNOWN" errorMsg="網(wǎng)絡(luò)異常">
<interface:http name="httpResponse" url="${inter_interUrl}"
paramMap="${httpParam}" charsetType="${inter_charset}"/>
</interface:tryException>
<!--解析響應(yīng)報文-->
<interface:tryException errorCode="CEC_UNKNOWN" errorMsg="響應(yīng)報文解析異常">
<!--解析報文-->
<interface:xmlToMap name="mapRes" value="${httpResponse}" />
<set name="mapRes" value="${mapRes.root}"/>
<!--協(xié)議驗(yàn)簽-->
<interface:verifyMd5 charsetType="${inter_charset}" sign="${mapRes.Sign}"
value="${mapRes.MerID}|${mapRes.OrderID}|${mapRes.TranStat}|${inter_channelKey}"/>
<!--組裝響應(yīng)對象-->
<interface:newInstance name="orderRes"
value="com.nnk.ecsys.database.mapper.order.entity.ExternOrderOrderInfo">
<set name="orderRes.orderId" value="${mapRes.OrderID}"/>
<set name="orderRes.partnerOrderId" value="${mapRes.TranOrder}"/>
<set name="orderRes.partnerOrderReceiveErrorCode" value="${mapRes.TranStat}"/>
<set name="orderRes.partnerOrderReceiveErrorMsg" value="${mapRes.TranInfo}"/>
</interface:newInstance>
</interface:tryException>
<!--返回響應(yīng)結(jié)果-->
<setResponse value="${orderRes}"/>
</converter>
TestMain.java
//接口配置資源
Resource resource = ResourceUtils.getResource("interface-trade.xml");
//轉(zhuǎn)換構(gòu)建器
ConverterStackerBuilder converterStackerBuilder = new DefaultConverterStackerBuilder();
//創(chuàng)建轉(zhuǎn)換器
ConverterStacker converterStacker = converterStackerBuilder.buildConverterStacker(resource);
//執(zhí)行轉(zhuǎn)換
Order.ExternOrderInfo tradeRequest= Order.ExternOrderInfo.getDefaultInstance();
ExternOrderOrderInfo tradeResponse = (ExternOrderOrderInfo) converterStacker.invoke(tradeRequest);
4. 轉(zhuǎn)換接口的實(shí)現(xiàn)
4.1 配置文件的解析與擴(kuò)展
DefinitionReader // 配置讀取類耕拷,讀取解析接口配置文件
NamespaceHandler // 命名空間處理類讼昆,包含命名空間內(nèi)每個節(jié)點(diǎn)的解析對象
NamespaceHandlerResolver // 命名空間管理類,管理每個命名空間的XSD文件路徑和處理類
DefinitionParser // 節(jié)點(diǎn)解析類骚烧,解析具體的轉(zhuǎn)換節(jié)點(diǎn)或擴(kuò)展節(jié)點(diǎn)
ConverterDefinition // 轉(zhuǎn)換節(jié)點(diǎn)定義信息類浸赫,包含返回值名稱,參數(shù)列表赃绊,轉(zhuǎn)換執(zhí)行類名既峡,子節(jié)點(diǎn)列表等信息
ConverterDefinitionContext // 轉(zhuǎn)換定義上下文信息類,包含轉(zhuǎn)換節(jié)點(diǎn)結(jié)構(gòu)信息碧查,常量參數(shù)對象等信息
處理流程:
1.DefinitionReader讀取接口配置运敢,遞歸解析節(jié)點(diǎn)信息,
2.根據(jù)節(jié)點(diǎn)命名空間調(diào)用NamespaceHandlerResolver獲取指定NamespaceHandler處理
2.NamespaceHandler內(nèi)部根據(jù)節(jié)點(diǎn)名稱獲取對應(yīng)的DefinitionReader
3.DefinitionReader解析完成后把ConverterDefinition返回DefinitionReader忠售,并存入ConverterDefinitionContext中
4.遞歸解析完成后最后得到ConverterDefinitionContext對象
擴(kuò)展說明:
1.添加擴(kuò)展節(jié)點(diǎn)解析類DefinitionParser传惠,解析方法可獲取ConverterDefinitionContext對象,可自定義轉(zhuǎn)換節(jié)點(diǎn)稻扬,或?qū)涌谂渲没蜣D(zhuǎn)換節(jié)點(diǎn)做擴(kuò)展處理涉枫;
2.添加命名空間處理類NamespaceHandler,描述節(jié)點(diǎn)名稱與DefinitionParser解析類對應(yīng)關(guān)系
3.添加擴(kuò)展配置信息腐螟,在目錄META-INF.converter下添加擴(kuò)展配置:XSD文件、handlers.properties困后、schemas.properties乐纸,在NamespaceHandlerResolver對象初始化的時候,會讀取運(yùn)行環(huán)境下所有Jar下此目錄的擴(kuò)展文件摇予;
XSD文件:定義擴(kuò)展節(jié)點(diǎn)結(jié)構(gòu)信息汽绢,以及指明命名空間名稱
handlers.properties:描述命名空間與之對應(yīng)的NamespaceHandler類
schemas.properties:描述命名空間與之對應(yīng)的XSD文件路徑
4.2 轉(zhuǎn)換器的構(gòu)建
ConverterDefinitionContext // 轉(zhuǎn)換定義上下文信息類,包含轉(zhuǎn)換節(jié)點(diǎn)結(jié)構(gòu)信息侧戴,常量參數(shù)對象等信息
ConverterStacker // 轉(zhuǎn)換器宁昭,執(zhí)行具體的轉(zhuǎn)換操作
Converter // 轉(zhuǎn)換節(jié)點(diǎn)執(zhí)行類
ConverterStackerBuilder // 轉(zhuǎn)換器構(gòu)建類
處理流程:
1.通過DefinitionReader讀取接口配置跌宛,得到ConverterDefinitionContext;
2.ConverterStackerBuilder遞歸遍歷ConverterDefinition积仗,通過ConverterDefinition實(shí)例化Converter對象疆拘;
3.在Converter實(shí)例化過程,將會把Converter參數(shù)列表中存在的部分常量引用寂曹, 根據(jù)ConverterDefinitionContext常量列表設(shè)置為具體的值哎迄;
4.遍歷完成后,每個Converter對象會有一個父節(jié)點(diǎn)喝多個子節(jié)點(diǎn)隆圆,形成樹形架構(gòu)的Converter集合漱挚;
5.最后使用Converter集合構(gòu)建ConverterStacker對象;
4.3 轉(zhuǎn)換器執(zhí)行過程
ConverterStacker // 轉(zhuǎn)換器渺氧,執(zhí)行具體的轉(zhuǎn)換操作
Converter // 轉(zhuǎn)換節(jié)點(diǎn)執(zhí)行類
ConverterRequest // 轉(zhuǎn)換請求對象旨涝,作為執(zhí)行過程中變量存儲對象
處理流程:
1.接受轉(zhuǎn)換請求,組裝ConverterRequest侣背;
2.執(zhí)行開始白华,把根轉(zhuǎn)換節(jié)點(diǎn)倒序放入執(zhí)行棧中,然后循環(huán)出棧執(zhí)行Converter秃踩;
3.在執(zhí)行的過程中衬鱼,根據(jù)ConverterRequest變量集合,實(shí)例化Converter的參數(shù)列表憔杨,如過程中存在未實(shí)例化的參數(shù)鸟赫,將會拋出異常;
4.參數(shù)列表實(shí)例化完成后消别, 把變量列表傳給Converter執(zhí)行轉(zhuǎn)換方法抛蚤,完成后把結(jié)果以name為變量名把結(jié)果存入ConverterRequest;
5.轉(zhuǎn)換執(zhí)行完成后寻狂,獲取當(dāng)前Converter的后續(xù)節(jié)點(diǎn)倒序存入執(zhí)行棧中岁经,注意:獲取后續(xù)節(jié)點(diǎn)的邏輯將由Converter本身實(shí)現(xiàn),超類默認(rèn)實(shí)現(xiàn)是獲取子節(jié)點(diǎn)蛇券,但如果像選擇缀壤、循環(huán)之類的結(jié)構(gòu),此方法邏輯將會重寫纠亚;
6.如在Converter執(zhí)行過程中出現(xiàn)異常塘慕,則會進(jìn)入異常捕獲處理分支,詳情看代碼蒂胞;
7.循環(huán)執(zhí)行到執(zhí)行棧為空時图呢,返回結(jié)果對象
4.4 上下文變量管理
ConverterRequest // 轉(zhuǎn)換器請求對象
ConverterDefinitionContext // 轉(zhuǎn)換定義上下文信息類,包含轉(zhuǎn)換節(jié)點(diǎn)結(jié)構(gòu)信息,常量參數(shù)對象等信息
AssemblyParam // 裝配參數(shù)對象
處理流程:
詳情看代碼