背景
Starring V6平台作为金融业前置系统和ESB实施的行业标杆,但是在实际应用过程中,可能会遇到一些非标准化的第三方系统,平台原有的标准化处理无法适配特殊情况,这个时候需要自行做个性化处理。本文主要说一些常见的需要个性化处理的问题。
常见问题
A、如何判断使用平台接出点还是CLI端连接第三方?
平台接出点仅适用于对方请求返回报文均为HTTP标准JSON报文,标准JSON报文的检验可以去百度搜索JSON格式化、或者使用本地JSON格式化工具HiJSON来检验,一旦对方返回报文JSON里面的某个字段类型不确定,尽量使用Cli端处理,避免后期改造起来有重复工作量。
B、如何处理对方返回非标准报文成标准格式?适用于任何报文改造,想怎么玩就怎么玩
根据平台定义的数据对象和报文格式,对方返回的报文经常会改变某一个字段的类型,比如当某字段为空时,第三方系统返回该字段为空字符串,当该字段有内容时,对方又返回了数组。
在平台中,我们定义的这个字段是数组,此时需要我们对返回报文进行转换处理,将对方返回的该字段为空时的空字符串替换成空数组格式。
1、在平台引入的Bean对象里面加上如下方法。
public void formatFMT() { String logFile = SUtil.getLogFile(); TrcLog.info(logFile, "解析接收字符串开始"); DtaInfo dtaInfo = DtaInfo.getInstance(); byte[] bytes = (byte[]) EPOper.get(dtaInfo.getTpId(), SysDef.GDTA_FORMAT + 0 + SysDef.FORMAT_ITEMDATA); String recData = null; try { recData = new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } TrcLog.info(logFile, "接收原始数据:" + recData); TrcLog.info(logFile, "对原始数据进行处理"); //TODO 此处可以添加对String字符串的自定义处理,比如原始数据验签、解密、字符替换、内容完善、格式调整等等操作TrcLog.info(logFile, "原始数据处理后:" + recData); EPOper.put(dtaInfo.getTpId(), SysDef.GDTA_FORMAT + 0 + SysDef.FORMAT_ITEMDATA, recData); EPOper.put(dtaInfo.getTpId(), SysDef.GDTA_FORMAT + 0 + SysDef.FORMAT_LENGTH, recData.getBytes().length); TrcLog.info(logFile, "打印数据池:" + EPOper.epToJSON(DtaInfo.getInstance().getTpId(), "UTF-8")); TrcLog.info(logFile, "解析接收字符串结束"); }2、此时代码已经备好了,该在何处享用呢?
如果是Cli端的返回,是在CLI端的 解析交易报文前事件,如下图:
如果是在接出点,则是在接出点的 报文接收前事件 调用上面的代码即可,调用方法相同。
以上情况适用于对方系统所有交易返回报文的共性问题,都需要统一处理,如果只有部分交易报文需要特殊处理,可以将处理方法加在具体交易的事件上,避免造成对其他交易的影响。
如下:
C、查看平台内部对象的值,以及在内部流转过程中数据赋值情况。
平台默认只输出了部分日志,一旦自己开发过程中步骤出错,导致交易内部报错,无法查看详细内部赋值过程,经常出现接入点接收报文有值,经过ALA调用接出点/CLI端出去就没值了。
一般是数据映射问题,此时需要看平台内部对象是否赋值成功,通过日志无法查看,可以自定义平台方法,打印交易数据池,会将请求对象、响应对象、平台对象全部输出到日志,方便排查问题。
1、在平台引入的Bean对象里面加上如下方法。代码如下:
public void printPool() { String logFile = SUtil.getLogFile(); TrcLog.log(logFile, EPOper.epToJSON(DtaInfo.getInstance().getTpId(), SysDef.FILE_ENCODING)); }同样,在平台引入的Bean对象里面加上方法,在DTA或者ALA或者交易的事件上调用该方法即可输出平台交易过程中全部对象内容。
D、平台请求报文头赋值处理。
最近几年随着互联网模式的兴起,很多银行也上了云平台,部分系统都是采用互联网交互模式。特别是对第三方外部系统的交互,互联网模式下需要对交易的请求头Header进行处理和校验。
平台默认只对通讯协议的请求头做了处理,比如 Content-Type、Connection、accept、host 等等通用请求头赋值,如果第三方需要使用特殊的请求头字段,则需要个性化处理。
比如第三方需要在请求头里面加上X_ACCOUNT_KEY、X_NONCE、X_CREATED、X_SIGN等内容。
1、在平台引入的Bean对象里面加上如下方法。处理代码如下:
public void tx() { String logFile = SUtil.getLogFile(); String x_account_key = "just for test"; String accountSecret = "just for test"; long created = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString(); String sign = OpenSDKKC.signCredential(x_account_key, accountSecret, nonce, created); TrcLog.log(logFile, "计算sign:" + sign); Map<String, String> heads = new HashMap<>(); heads.put(OpenSDKKC.X_ACCOUNT_KEY, x_account_key); heads.put(OpenSDKKC.X_NONCE, nonce); heads.put(OpenSDKKC.X_CREATED, String.valueOf(created)); heads.put(OpenSDKKC.X_SIGN, sign); heads.put("accept", "application/json"); heads.put("Content-Type", "application/json"); heads.put("Connection", "keep-alive"); DtaInfo dtaInfo = DtaInfo.getInstance(); int i = 0; for (Map.Entry<String, String> entry : heads.entrySet()) { EPOper.put(dtaInfo.getTpId(), "__HTTP_HEADER[0].__KEY[" + i + "]", entry.getKey()); EPOper.put(dtaInfo.getTpId(), "__HTTP_HEADER[0].__VALUE[" + i + "]", entry.getValue()); i++; TrcLog.log(logFile, "key:" + entry.getKey() + " value:" + entry.getValue()); } }以上是对请求头的赋值处理,只需要替换 heads.put(“”,””)里面的内容即可完成请求Header头的处理,固定请求头直接写死,需要计算的头处理则自定义计算后赋值。
2、在定制的接出点,调用该方法即可完成对请求头的Header赋值。
3、输出结果示例如下:
4、很多时候内部系统调用时,带了它自身的请求头,比如上图中的c-business-id、c-app-id,这种第三方根本不care的请求头信息,如果对方不报错,则可以不用理会,偶尔对方会因为多出一些Header头信息导致调用交易出错。
我们则需要去掉内部系统请求时带的Header头信息,只赋值第三方系统需要的Header头,则需要增加一行删除Header头信息的代码,上述代码修改如下:
public void tx() { String logFile = SUtil.getLogFile(); String x_account_key = "just for test"; String accountSecret = "just for test"; long created = System.currentTimeMillis(); String nonce = UUID.randomUUID().toString(); String sign = OpenSDKKC.signCredential(x_account_key, accountSecret, nonce, created); TrcLog.log(logFile, "计算sign:" + sign);// 此代码为清除请求Header头信息,如不需要则屏蔽com.adtec.starring.datapool.HttpHeaderOper.deleteAll(); Map<String, String> heads = new HashMap<>(); heads.put(OpenSDKKC.X_ACCOUNT_KEY, x_account_key); heads.put(OpenSDKKC.X_NONCE, nonce); heads.put(OpenSDKKC.X_CREATED, String.valueOf(created)); heads.put(OpenSDKKC.X_SIGN, sign); heads.put("accept", "application/json"); heads.put("Content-Type", "application/json"); heads.put("Connection", "keep-alive"); DtaInfo dtaInfo = DtaInfo.getInstance(); int i = 0; for (Map.Entry<String, String> entry : heads.entrySet()) { EPOper.put(dtaInfo.getTpId(), "__HTTP_HEADER[0].__KEY[" + i + "]", entry.getKey()); EPOper.put(dtaInfo.getTpId(), "__HTTP_HEADER[0].__VALUE[" + i + "]", entry.getValue()); i++; TrcLog.log(logFile, "key:" + entry.getKey() + " value:" + entry.getValue()); } }
E、将JSON字符串转换成平台对象处理。
1、在一些特殊情况下,和第三方的通讯这一端,并没有使用平台的接出点或者调用CLI端组报文,比如form-data形式的文件上传,平台的支持性不是很好,需在交易的ALA逻辑处理里自定义代码来完成交易,或者第三方平台使用的是自己的SDK包,并不是以接口的形式来交互,这种第三方代码调用后,返回报文会以JSON字符串形式接收,收到后需要映射到平台定制的对象上去,不做映射处理,平台的对象是没有值的。
2、在接收到返回JSON字符串之后,需要自定义代码来处理返回信息。
比如交易 IWS0006006 的响应对象是:UPLOADONETHINGFILE_RES
对象里面的字段和第三方返回结构字段一致:
代码调用第三方交易后成功收到返回JSON字符串内容:
{ "fpath": "", "message": "", "success": "true" }我们则要把第三方返回JSON字符串赋值到平台对象UPLOADONETHINGFILE_RES,代码如下:
String result = "第三方返回JSON字符串内容,如上图所示"; result = "{"UPLOADONETHINGFILE_RES":" + result + "}"; TrcLog.info(logFile, "响应数据 = " + result); EPOper.jsonToEP(dtaInfo.getTpId(), result); //平台此处代码赋值// 此处就可以从平台对象取值 CompSDO sdo = EPOper.getCompSDO(dtaInfo.getTpId(), "UPLOADONETHINGFILE_RES"); String success = (String) sdo.getValue("success"); String message = (String) sdo.getValue("message"); String fpath = (String) sdo.getValue("fpath");
F、
G、
H、
J、
K、
L、为什么需要自定义平台通讯类
随着公司不断拓展业务范畴,对接互联网模式的概率越来越普遍,外部互联网公司开发的系统接口模式繁多,一家系统的接口可能就包含有GET(拼接URL、restful风格、restful风格key=value传参等)/POST(拼接URL、表单提交、JSON报文格式)/文件流传输/文件流带报文体模式form-data等各种乱七八糟的情况,可能部分公司对于接口标准没有明确定义,而且多为前后端未分离的系统,对接的第三方系统一般都已上线,临时让人修改接口显然也是不合适的,如果碰到配合的公司你说改,对方就改了,那算你运气好。不然的话你想想平台应该怎么定架构,一个第三方系统,对于我们来说一般统一走一个CLI端或者接出点,因为平台默认一个CLI端和接出点只能用一种协议。
第三方调用示例如下:
常规GET http://www.xxx.xxxx.com/pzInter/edu?PARAMS=MDEyMzExNzg5MjE3MzYyOQ==&FLAG=1常规GET https://www.xxx.xxxx.com/pzInter/edu?PARAMS=MDEyMzExNzg5MjE3MzYyOQ==&FLAG=1 异常restf风格GET http://www.xxx.xxxx.com/eduInterface/edu/v1/xkcj/kshId=MTkwMTAyMDAxMDE=/pwdId=MTIwMDEz/23123/yzm=232323 标准restful风格GET http://www.xxx.xxxx.com/instancecode/reqcode/2994 拼接URL风格POST http://www.xxx.xxxx.com/search/crjqueryn?sfzh=43018123233902265519&ywbh=4301442234101005747 表单提交POSTJSON报文POST看完这些,你敢信这是一家平台做出来的东西 ?互联网公司这么好混的吗 ?哪里有事少钱多离家近代码随便敲敲的工作请介绍给我!
总之看完这个接口整个人都不好了,非要强行使用平台要应对这个东西也不是不行,只是非常非常的麻烦,相信懂的人应该能明白,就为了这几只接口,咱们至少得建几个CLI端,还不能完全满足这个请求URL和报文格式。
唯一的办法只能自定义平台通讯类来处理该问题。
后面会单独起一篇介绍如何自定义平台通讯类的文,待续。
未完,有时间就完善完善 。。。