项目地址:https://github.com/hjx601496320/transmitjava
在平常开发工做中,咱们常常会遇到要和各类第三方调试接口的状况,若是是简单的几个接口还好,代码写起来很快就写好了。可是若是在某一种业务状况下,好比支付,咱们对接了不少家第三方的支付公司,每一家的支付接口都不同,这时就须要针对多家不一样的接口文档编写不一样的代码。又或者咱们做为接口提供方提供一套标准的接口,可是某些客户会比较强硬,要求你提供的接口须要按照对方的要求来作,这时就又须要苦哈哈的写一个适配他们的代码。这个过程就十分的难受了。linux
我所在的项目就遇到了这种问题,我在的项目是作保险业务的,如今须要对接多家保险公司的接口,每家数据仍是那些常见的数据,可是数据结构都不相同。有些是XML的,有些是JSON的。像性别,证件类型的枚举值也都不大相同。git
因此根据现有的状况,我开发了一个HTTP接口适配工具。用于支持各类类型的HTTP接口转发,转换请求数据,转换响应数据的需求。github
由于是一个已经开发完成的工具,在公司项目中使用良好。下面说一下如何使用。web
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方法。json
├── 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" } } }
这里说一下,好比须要根据一个第三方接口添加一个转换, 第三方接口信息以下:api
请求地址: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
参数示例:
请求数据 <Demo> <Info> <Code>XXX-1</Code> <UUID>d83a011a-958d-4310-a51b-0fb3a4228ef5</UUID> <Time>2017-11-15 16:57:36</Time> </Info> <Order> <SerialNo>0</SerialNo> <OrderNo>123123123</OrderNo> <OrderCode>asdasdasd</OrderCode> <Result>1</Result> </Order> </Demo> 须要返回的数据 <Demo> <Info> <Code>1</Code> </Info> <Order> <Msg>success</Msg> </Order> </Demo>
这时你须要添加以下配置
{ "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" } } }
{ "header": { "code": "${ROOT.Info.Code}", "date": "${ROOT.Info.Time}" }, "body": { "orderCode": "${ROOT.Order.OrderCode}" } }
<Demo> <Info> <Code>${ROOT.code}</Code> </Info> <Order> <Msg>${ROOT.msg}</Msg> </Order> </Demo>
配置完成后,启动transmit,向http://127.0.0.1:9527/getOrder发送post请求,就能够转换你的请求参数,并完成对http://xxx.xxx.com/text/getOrder接口的调用了。
原始数据:
<Demo> <Info> <Code>XXX-1</Code> <UUID>d83a011a-958d-4310-a51b-0fb3a4228ef5</UUID> <Time>2017-11-15 16:57:36</Time> </Info> <Order> <SerialNo>0</SerialNo> <OrderNo>123123123</OrderNo> <OrderCode>asdasdasd</OrderCode> <Result>1</Result> </Order> </Demo>
对应的节点
${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, Map<String, Object> valueMap) throws Exception; /** * 在api响应后执行 * * @param value 完整的数据 * @param valueMap 放进freemarker的数据 * @return */ String afterResponse(String value, Map<String, Object> valueMap) 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":[ "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()); } }
就完成了。