通用轉換接口設計

通用轉換接口設計


目錄

  • 轉換接口的定義
  • 轉換接口的作用
  • 轉換接口的使用
  • 轉換接口的實現

1. 轉換接口的定義

接口是系統內部與第三方系統協議數據的相互轉換處理過程,轉換接口以XML配置的形式把這種處理過程描述出來,方便接口的開發與維護;


2. 轉換接口的作用

  • 增加開發效率,轉換接口抽象出通用的轉換處理,開發只需組裝對應轉換操作即可,減少了重復開發的工作,增加開發效率;
  • 降低出錯率,統一協議轉換之外的處理,接口開發只需配置相應的轉換處理,減少代碼量,降低出錯概率;
  • 減少維護成本,接口配置化后,對接口協議的調整,只需要針對接口配置修改即可;

3. 轉換接口的使用

接口配置以XML文件描述,XSD文件定義節點結構,節點分為轉換接口和擴展節點,轉換節點用于做數據轉換處理,可擁有多個子節點,一般先執行父節點,后執行子節點,執行方式有順序、選擇、循環,子節點如果出現異常,父節點可捕獲做處理;擴展節點用于對接口配置或轉換節點擴展使用;

3.1 接口配置說明

轉換定義文件:有XSD文件表示,定義具體轉換節點,需描述節點名稱、參數名稱,參數類型和轉換處理類;

<!--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>

轉換節點:由XML節點表示,做具體的轉換處理,可有多個輸入參數和一個輸出參數,輸入參數由具體轉換節點定義,屬性name表示輸出參數,轉換結果以name值作為名稱存入【上下文變量】;

輸入參數:值可直接用字符串表示,如需引用【上下文變量】則使用${變量名}表示,還可以相互組合, 如:value="${參數2} AAA ${參數2}",如需要引用對象的參數,則使用${變量名.參數名}表示,基本用法和EL表達式類似;

擴展節點:可自定義擴展節點,針對接口配置或轉換節點做處理,現有擴展節點,import可導入其他接口配置,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">
    <!--導入配置文件-->
    <extend:loadProperty location="properties/common.properties"/>
    <!--定義請求對象-->
    <getRequest name="request"/>
    <!--組裝請求報文-->
    <interface:tryException errorCode="CEC_FAILED" errorMsg="請求報文組裝異常">
        <!--轉換參數-->
        <set name="orderReq" value="${request.reqeustParam}" />
        <interface:mapget name="cardType" key="${orderReq.providerId}" mappingName="providerMap"/>
        <!--組裝協議-->
        <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>
    <!--調用http接口-->
    <interface:tryException errorCode="CEC_UNKNOWN" errorMsg="網絡異常">
        <interface:http name="httpResponse" url="${inter_interUrl}" 
            paramMap="${httpParam}" charsetType="${inter_charset}"/>
    </interface:tryException>
    <!--解析響應報文-->
    <interface:tryException errorCode="CEC_UNKNOWN" errorMsg="響應報文解析異常">
        <!--解析報文-->
        <interface:xmlToMap name="mapRes" value="${httpResponse}" />
        <set name="mapRes" value="${mapRes.root}"/>
        <!--協議驗簽-->
        <interface:verifyMd5 charsetType="${inter_charset}" sign="${mapRes.Sign}" 
            value="${mapRes.MerID}|${mapRes.OrderID}|${mapRes.TranStat}|${inter_channelKey}"/>
        <!--組裝響應對象-->
        <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>
    <!--返回響應結果-->
    <setResponse value="${orderRes}"/>
</converter>

TestMain.java

//接口配置資源
Resource resource = ResourceUtils.getResource("interface-trade.xml");
//轉換構建器
ConverterStackerBuilder converterStackerBuilder = new DefaultConverterStackerBuilder();
//創建轉換器
ConverterStacker converterStacker = converterStackerBuilder.buildConverterStacker(resource);
//執行轉換
Order.ExternOrderInfo tradeRequest= Order.ExternOrderInfo.getDefaultInstance();
ExternOrderOrderInfo tradeResponse = (ExternOrderOrderInfo) converterStacker.invoke(tradeRequest);

4. 轉換接口的實現

4.1 配置文件的解析與擴展

DefinitionReader            // 配置讀取類,讀取解析接口配置文件
NamespaceHandler            // 命名空間處理類,包含命名空間內每個節點的解析對象
NamespaceHandlerResolver    // 命名空間管理類,管理每個命名空間的XSD文件路徑和處理類
DefinitionParser            // 節點解析類,解析具體的轉換節點或擴展節點
ConverterDefinition         // 轉換節點定義信息類,包含返回值名稱,參數列表,轉換執行類名,子節點列表等信息
ConverterDefinitionContext  // 轉換定義上下文信息類,包含轉換節點結構信息,常量參數對象等信息

處理流程:

1.DefinitionReader讀取接口配置,遞歸解析節點信息,

2.根據節點命名空間調用NamespaceHandlerResolver獲取指定NamespaceHandler處理

2.NamespaceHandler內部根據節點名稱獲取對應的DefinitionReader

3.DefinitionReader解析完成后把ConverterDefinition返回DefinitionReader,并存入ConverterDefinitionContext中

4.遞歸解析完成后最后得到ConverterDefinitionContext對象

擴展說明:

1.添加擴展節點解析類DefinitionParser,解析方法可獲取ConverterDefinitionContext對象,可自定義轉換節點,或對接口配置或轉換節點做擴展處理;

2.添加命名空間處理類NamespaceHandler,描述節點名稱與DefinitionParser解析類對應關系

3.添加擴展配置信息,在目錄META-INF.converter下添加擴展配置:XSD文件、handlers.properties、schemas.properties,在NamespaceHandlerResolver對象初始化的時候,會讀取運行環境下所有Jar下此目錄的擴展文件;

            XSD文件:定義擴展節點結構信息,以及指明命名空間名稱
handlers.properties:描述命名空間與之對應的NamespaceHandler類
 schemas.properties:描述命名空間與之對應的XSD文件路徑

4.2 轉換器的構建

ConverterDefinitionContext  // 轉換定義上下文信息類,包含轉換節點結構信息,常量參數對象等信息
ConverterStacker            // 轉換器,執行具體的轉換操作
Converter                   // 轉換節點執行類
ConverterStackerBuilder     // 轉換器構建類

處理流程:

1.通過DefinitionReader讀取接口配置,得到ConverterDefinitionContext;

2.ConverterStackerBuilder遞歸遍歷ConverterDefinition,通過ConverterDefinition實例化Converter對象;

3.在Converter實例化過程,將會把Converter參數列表中存在的部分常量引用, 根據ConverterDefinitionContext常量列表設置為具體的值;

4.遍歷完成后,每個Converter對象會有一個父節點喝多個子節點,形成樹形架構的Converter集合;

5.最后使用Converter集合構建ConverterStacker對象;

4.3 轉換器執行過程

ConverterStacker            // 轉換器,執行具體的轉換操作
Converter                   // 轉換節點執行類
ConverterRequest            // 轉換請求對象,作為執行過程中變量存儲對象

處理流程:

1.接受轉換請求,組裝ConverterRequest;

2.執行開始,把根轉換節點倒序放入執行棧中,然后循環出棧執行Converter;

3.在執行的過程中,根據ConverterRequest變量集合,實例化Converter的參數列表,如過程中存在未實例化的參數,將會拋出異常;

4.參數列表實例化完成后, 把變量列表傳給Converter執行轉換方法,完成后把結果以name為變量名把結果存入ConverterRequest;

5.轉換執行完成后,獲取當前Converter的后續節點倒序存入執行棧中,注意:獲取后續節點的邏輯將由Converter本身實現,超類默認實現是獲取子節點,但如果像選擇、循環之類的結構,此方法邏輯將會重寫;

6.如在Converter執行過程中出現異常,則會進入異常捕獲處理分支,詳情看代碼;

7.循環執行到執行棧為空時,返回結果對象

4.4 上下文變量管理

ConverterRequest            // 轉換器請求對象
ConverterDefinitionContext  // 轉換定義上下文信息類,包含轉換節點結構信息,常量參數對象等信息
AssemblyParam               // 裝配參數對象

處理流程:

詳情看代碼
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容