用vetr.x寫一個HTTP接口適配器, 對接各種形式接口

  業務說明

  在日常開發工作中,我們經常會遇到要和各種第三方調試接口的情況,如果是簡單的幾個接口還好,代碼寫起來很快就寫好了。但是如果在某一種業務情況下,比如支付,我們對接了很多家第三方的支付公司,每一家的支付接口都不一樣,這時就需要針對多家不同的接口文檔編寫不同的代碼。又或者我們作爲接口提供方提供一套標準的接口,但是某些客戶會比較強硬,要求你提供的接口需要按照對方的要求來做,這時就又需要苦哈哈的寫一個適配他們的代碼。這個過程就十分的難受了。

  我所在的項目就遇到了這種問題,我在的項目是做保險業務的,現在需要對接多家保險公司的接口,每家數據還是那些常見的數據,但是數據結構都不相同。有些是XML的,有些是JSON的。像性別,證件類型的枚舉值也都不大相同。

  所以根據現有的情況,我開發了一個HTTP接口適配工具。用於支持各種類型的HTTP接口轉發,轉換請求數據,轉換響應數據的需求。

  項目說明

  業務需求

  可配置,可配置,可配置(重要的說3邊)

  可以接受常見的HTTP請求, 比如POST+JSON,POST+XML,GET,POST+表單等

  數據轉換過程不需要寫java代碼。

  可以實現接口加密解密等功能

  數據落庫。

  開發思路

  因爲這個可配置是很重要的需求,但是我又不想寫頁面,所以定義一個配置文件是必不可少的,這裏配置文件我使用json格式。

  對於接口信息的描述,可以寫在配置文件中,比如定義一個接受請求的地址,再定義一個轉發請求的地址,另外加上他們的數據格式和請求類型的描述。

  數據轉換這裏,因爲涉及到xml和json格式的報文,每個報文的節點和層級深度都是不一樣的,另外還要做到能夠互相轉換。所以我的做法是將他們深度遍歷之後,做成Map這種的數據類型,其中Object 可以使另外一個Map, 也可以是一個List。總之就是一個樹狀結構。解析完數據之後,將數據放進freemarker模板文件中完成轉換。當然這個模板是需要自己編寫的。

  再能夠完成數據轉換之後需要考慮的是參數加密和簽名的步驟,這可以設計一個接口,做成插件的形式,然後自己實現簽名和驗籤的步驟。就類似jmeter的插件一樣,做成一個jar包放在項目裏就可以用了。

  數據落庫這裏很簡單,將接受到的原始數據和接口返回的原始數據保存入庫,並記錄調用開始時間和調用結束時間就好了。

  項目框架上我選擇的是vert.x,他是一個事件驅動和非阻塞的java框架,根據網上看到的測試結果,效率非常的高,很適合做這種類似中間件的工具。

  項目介紹

  因爲是一個已經開發完成的工具,在公司項目中使用良好。下面說一下如何使用。

  安裝

  git clone https://github.com/hjx601496320/transmit.git

  cd transmit/

  mvn package

  cd target/

  //解壓

  tar -zxvf transmit.tar.gz

  //啓動

  sh bin/start.sh

  這裏啓動用的是linux的腳本,因爲Windows腳本我不會寫,所以只有linux的。

  也可以在項目中直接啓動Main.java中的main方法。

  項目結構

  ├── bin 啓動腳本

  │ ├── restart.sh 重啓

  │ ├── start.sh 啓動

  │ └── stop.sh 停止

  ├── config 配置

  │ ├── config.json 啓動時加載的配置文件

  │ └── logback.xml 日誌配置,使用logback

  ├── lib

  │ ├── commons-cli-1.4.jar 依賴,自己添加的插件jar可以放在這裏

  ......

  │ ├── transmit-1.0-SNAPSHOT.jar

  │ ├── vertx-web-client-3.8.0.jar

  │ └── vertx-web-common-3.8.0.jar

  ├── log 日誌

  │ ├── debug

  │ │ └── debug.2019-09-17.log

  │ ├── error

  │ │ └── error.2019-09-17.log

  │ └── info

  │ └── info.2019-09-17.log

  └── sout.log 啓動時輸出的日誌

  配置說明

  {

  其他配置

  "config": {

  是否緩存模板文件,默認true. 關閉的話每次請求會重新加載模板,方便調試.

  "cache": true,

  系統端口號

  "port": 9090,

  引用其他的配置文件的文件路徑

  "import": [

  ],

  其他組件加載, 執行CLass.forName, 可以加載自己定義的一些插件, 完成類似數據入庫, 接口簽名之類的功能

  "ext": [

  "com.hebaibai.ctrt.Driver"

  ],

  數據庫配置, 用於保存接口請求日誌

  "db": {

  "host": "127.0.0.1",

  "database": "dbname",

  "port": 3306,

  "username": "root",

  "password": "root"

  }

  },

  配置示例

  "config-demo": {

  接受請求

  "request": {

  接受請求的地址 127.0.0.1:9090/download

  "path": "/download",

  請求的方式

  "method": "GET",

  請求參數類型: FORM(表單提交), JSON(json), QUERY(?key=value&key2=value), TEXT(文本), XML(xml),

  "request-type": "QUERY",

  返回參數類型

  "response-type": "TEXT"

  },

  轉發的接口配置

  "api": {

  接口請求地址

  "url": "http://127.0.0.1:9003/api/download",

  插件編號, 在ext中加載來的

  "extCode": "null",

  接口請求地址

  "method": "GET",

  請求參數類型

  "request-type": "QUERY",

  請求超時設置,默認3000 ms, 單位ms

  "timeout": 1,

  返回參數類型

  "response-type": "TEXT",

  請求參數轉換模板

  "request-ftl": "/home/hjx/work/transmit/file/download-req.ftl",

  響應參數轉換模板

  "response-ftl": "/home/hjx/work/transmit/file/download-res.ftl"

  }

  }

  }

  數據轉換流程

  

流程圖


  配置示例

  這裏說一下,比如需要根據一個第三方接口添加一個轉換, 第三方接口信息如下:

  請求地址:http://xxx.xxx.com/text/getOrder

  請求方式:POST

  參數類型:JSON

  參數示例:

  接口請求參數

  {

  "header": {

  "code": "123123123",

  "date": "2019-09-19 14:28:57"

  },

  "body": {

  "orderCode": "O1231231231231231"

  }

  }

  接口返回參數

  {

  "code":1

  "msg":"success"

  }

  而你能夠發送的數據是這樣的:

  請求方式:POST

  參數類型:XML

  參數示例:

  請求數據

  

  

  XXX-1

  d83a011a-958d-4310-a51b-0fb3a4228ef5

  2017-11-15 16:57:36

  

  

  0

  123123123

  asdasdasd

  1

  

  

  需要返回的數據

  

  

  1

  

  

  success

  

  

  這時你需要添加如下配置

  {

  "config":{

  "port":9527,

  "import":[

  ],

  "ext":[

  ],

  "db":{

  "host":"127.0.0.1",

  "database":"dbname",

  "port":3306,

  "username":"root",

  "password":"root"

  }

  },

  "getOrder":{

  "request":{

  "path":"/getOrder",

  "method":"POST",

  "request-type":"XML",

  "response-type":"XML"

  },

  "api":{

  "url":"http://xxx.xxx.com/text/getOrder",

  "method":"POST",

  "request-type":"JSON",

  "response-type":"JSON",

  "request-ftl":"/home/hjx/work/transmit/file/getOrder-req.json",

  "response-ftl":"/home/hjx/work/transmit/file/getOrder-res.xml"

  }

  }

  }

  請求轉換/home/hjx/work/transmit/file/getOrder-req.xml

  {

  "header": {

  "code": "${ROOT.Info.Code}",

  "date": "${ROOT.Info.Time}"

  },

  "body": {

  "orderCode": "${ROOT.Order.OrderCode}"

  }

  }

  響應轉換模板/home/hjx/work/transmit/file/getOrder-res.xml

  

  

  ${ROOT.code}

  

  

  ${ROOT.msg}

  

  

  配置完成後,啓動transmit,向http://127.0.0.1:9527/getOrder發送post請求,就可以轉換你的請求參數,並完成對http://xxx.xxx.com/text/getOrder接口的調用了。

  關於模板中原始數據的訪問

  原始數據:

  

  

  XXX-1

  d83a011a-958d-4310-a51b-0fb3a4228ef5

  2017-11-15 16:57:36

  

  

  0

  123123123

  asdasdasd

  1

  

  

  對應的節點

  ${ROOT.Info.Code}=XXX-1

  ${ROOT.Info.UUID}=d83a011a-958d-4310-a51b-0fb3a4228ef5

  ${ROOT.Info.Time}=2017-11-15 16:57:36

  ${ROOT.Order.SerialNo}=0

  ${ROOT.Order.OrderNo}=123123123

  ${ROOT.Order.OrderCode}=asdasdasd

  ${ROOT.Order.Result}=1

  插件編寫

  插件有兩種。

  一種

  是實現接口com.hebaibai.ctrt.transmit.util.ext。這個接口可以處理一些簽名之類的操作,其中有四個方法。

  /**

  * 用於判斷是否使用該插件,extCode爲配置文件中的配置

  * @param extCode

  * @return

  */

  boolean support(String extCode);

  /**

  * 獲取插件編號

  *

  * @return

  */

  String getCode();

  /**

  * 在api請求前前執行

  *

  * @param value 完整的數據

  * @param valueMap 放進freemarker的數據

  * @return 插件處理後的數據

  */

  String beforRequest(String value, MapvalueMap) throws Exception;

  /**

  * 在api響應後執行

  *

  * @param value 完整的數據

  * @param valueMap 放進freemarker的數據

  * @return

  */

  String afterResponse(String value, MapvalueMap) throws Exception;

  單獨新建項目,實現該接口,添加一個類:

  package com.hebaibai.ctrt;

  import com.hebaibai.ctrt.ext.sign.PICC_XM_testSign;

  import com.hebaibai.ctrt.transmit.util.CrtrUtils;

  /**

  * 驅動

  */

  public class Driver {

  /**

  * 將插件添加進項目

  */

  static {

  System.out.println("加載 簽名插件...");

  CrtrUtils.EXT_LIST.add(你編寫的插件實例對象);

  }

  }

  之後將這個項目單獨打成jar包,放進項目的lib文件夾中。之後修改配置:

  。。。

  "ext":[鄭州婦科:http://www.zztjfk.com/

  "com.hebaibai.ctrt.Driver"

  ],

  。。。

  就完成了。

  另一種

  添加freemarker自定義指令,操作和上面的插件差不多,需要實現freemarker.template.TemplateDirectiveModel接口,然後

  package com.hebaibai.ctrt;

  import com.hebaibai.ctrt.ext.sign.PICC_XM_testSign;

  import com.hebaibai.ctrt.transmit.util.CrtrUtils;

  /**

  * 驅動

  */

  public class Driver {

  /**

  * 將插件添加進項目

  */

  static {

  System.out.println("加載 簽名插件...");

  CrtrUtils.EXT_LIST.add(你編寫的插件實例對象);

  //freeMarker 自定義指令

  CrtrUtils.FREEMARKER_DIRECTIVE_MODEL.put("has", new Has());

  }

  }

  就完成了。

  沒了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章