应用系统如何与外部渠道进行对接?java代码实现篇
一个应用系统要与支付对接,要与短信平台对接,要与其他业务系统对接,甚至于qq、微博、微信等平台对接。与每一个系统对接,我们就得根据相应平台提供的SDK进行开发。相信大家都明白,如果这么搞,那么后期维护起来是非常的困难。大家肯定会问:为何不做一个统一通讯网关?相信下图大家应该多多少少都见过,这也是我认为目前比较合适的解决方案。
实现效果Demo:
实现思路
要实现这个过程应该有两步,第一步统一通讯网关的实现,第二步应用系统如何与统一通讯网关对接,文中重点介绍如何与统一通讯网关对接。
假设一种场景:目前要与支付平台对接【unionPay】,unionpay SDK已具备。传统做法是按照unionnay提供的demo进行改造,以完成系统对接,如果按照demo去实现,会导致很多冗余代码。其次感觉应用系统比较繁琐,不专一。
具体demo大家可自行前往下载。
文中实现时,将接口进行xml配置,保证重用性高。
XMl配置
<?xml version="1.0" encoding="UTF-8"?> <transactions> <!-- 公共请求报文头 --> <requestHeadCommon> <head> <field desc="交易代码" isOptional="false" ocrmFieldName="headTranCode">TranCode</field> <field desc="交易柜员" isOptional="false" ocrmFieldName="headTlrNo">TlrNo</field> <field desc="操作员号" isOptional="false" ocrmFieldName="headAccountCode">AccountCode</field> <field desc="交易版本号" isOptional="false" ocrmFieldName="headVersion">Version</field> <field desc="渠道流水号" isOptional="false" ocrmFieldName="headTermJourNo">TermJourNo</field> <field desc="渠道开始代理日期" isOptional="false" ocrmFieldName="headChannelSendDate">ChannelSendDate</field> <field desc="渠道开始代理时间" isOptional="false" ocrmFieldName="headChannelSendTime">ChannelSendTime</field> <field desc="渠道编码" isOptional="false" ocrmFieldName="headChannelNo">ChannelNo</field> <field desc="渠道子编码" isOptional="false" ocrmFieldName="headChanlSubNo">ChannelSubNo</field> <field desc="ServiceID" isOptional="false" ocrmFieldName="headServiceId">ServiceID</field> <field desc="功能编码" isOptional="false" ocrmFieldName="headPermissionCode">PermissionId</field> <field desc="交易地域" isOptional="false" ocrmFieldName="headTrunkId">TransArea</field> <field desc="客户姓名" isOptional="false" ocrmFieldName="headCustName">HeadCustName</field> <field desc="证件号" isOptional="false" ocrmFieldName="headPaperId">HeadPaperId</field> <field desc="证件类型" isOptional="false" ocrmFieldName="headPaperType">HeadPaperType</field> <field desc="凭证号码" isOptional="false" ocrmFieldName="headHolderNo">HeadHolderNo</field> <field desc="凭证类型" isOptional="false" ocrmFieldName="headHolderType">HeadHolderTp</field> </head> </requestHeadCommon> <!-- 公共响应报文头 --> <responseHeadCommon> <head> <field desc="交易柜员" isOptional="false" ocrmFieldName="headTlrNo">TlrNo</field> <field desc="渠道流水号" isOptional="false" ocrmFieldName="headTermJourNo">TermJourNo</field> <field desc="JT接收渠道日期" isOptional="false" ocrmFieldName="headJTRecChannelDate">JTRecChannelDate</field> <field desc="JT接收渠道时间" isOptional="false" ocrmFieldName="headJTRecChannelTime">JTRecChannelTime</field> <field desc="JT请求前置日期" isOptional="false" ocrmFieldName="headJTSendProxyDate">JTSendProxyDate</field> <field desc="JT请求前置时间" isOptional="false" ocrmFieldName="headJTSendProxyTime">JTSendProxyTime</field> <field desc="JT接收前置日期" isOptional="false" ocrmFieldName="headJTRecProxyDate">JTRecProxyDate</field> <field desc="JT接收前置时间" isOptional="false" ocrmFieldName="headJTRecProxyTime">JTRecProxyTime</field> <field desc="JT发送渠道日期" isOptional="false" ocrmFieldName="headJTSendChannelDate">JTSendChannelDate</field> <field desc="JT发送渠道时间" isOptional="false" ocrmFieldName="headJTSendChannelTime">JTSendChannelTime</field> <field desc="交易地域" isOptional="false" ocrmFieldName="headTrunkId">TransArea</field> <field desc="返回交易代码" isOptional="false" ocrmFieldName="headAnsTranCode">AnsTranCode</field> <field desc="联动交易码" isOptional="false" ocrmFieldName="headLnkTranCode">LnkTranCode</field> <field desc="交易日期" isOptional="false" ocrmFieldName="headAnsTranDate">AnsTranDate</field> <field desc="出错交易序号" isOptional="false" ocrmFieldName="headErrTranSeq">ErrTranSeq</field> <field desc="交易响应代码" isOptional="false" ocrmFieldName="headRespCode">ReqCode</field> <field desc="交易响应描述" isOptional="false" ocrmFieldName="headRespMsg">ReqMsg</field> </head> </responseHeadCommon> <!-- Test 简单测试一下而已 --> <transaction transactionID="E1000"> <message type="request"> <body> <field desc="商品名称" isOptional="false" ocrmFieldName="goodsName">Name</field> </body> </message> <message type="response"> <body> <field desc="查询总笔数" isOptional="false" ocrmFieldName="totalCount">TotalCount</field> <field desc="当前页返回笔数" isOptional="false" ocrmFieldName="returnCount">ReturnCount</field> <field-list isOptional="true" ocrmFieldName="detailList" name="RECORD" class="com.jsup.service.trans.test.model.GoodsSub"> <field-list isOptional="true" ocrmFieldName="0" name="0"> <field desc="商品ID" isOptional="false" ocrmFieldName="id">ID</field> <field desc="商品名称" isOptional="false" ocrmFieldName="goodsName">GOODS_NAME</field> <field desc="商品描述" isOptional="false" ocrmFieldName="goodsDetail">GOODS_DETAIL</field> </field-list> </field-list> </body> </message> </transaction> </transactions>
XML文件载入java类
/** * 个人学习工程 * 日期:2015年11月08日22时52分 */ package com.jsup.transaction.validator; import com.jsup.transaction.util.TransactionConfigXmlUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * <pre> * 功能说明:xml文件载入 * </pre> * * @author 小娃娃 * @version 1.0 * @email urumqimxl@126.com * @issue <> */ public class TransactionXMLLoader {protected static final Logger log = LoggerFactory.getLogger(TransactionXMLLoader.class); private static Map validatorsLoaded;//将transaction.xml解析为map存储 /** * 获取交易配置集合 * @return Map 交易配置集合 * @throws Exception */ public static Map getValidatorsMap() throws Exception {if (validatorsLoaded == null)throw new Exception("JSUP-Transaction数据报校验规则尚未初始化"); return validatorsLoaded; }public static Map refresh() throws Exception{validatorsLoaded = null; return load(); }/** * 载入transaction.xml文件信息,并存储为Map结构 * @return Map 交易配置集合 * @throws Exception */ public static Map load() throws Exception {log.info("开始载入jSUP-Transaction数据报校验规则..."); //获取运行时,transaction.xml文件路径 String configPath = TransactionXMLLoader.class.getClassLoader().getResource("config/transaction/transaction.xml").getPath(); if (validatorsLoaded == null) {loadValidators(configPath); }if (validatorsLoaded == null) {throw new Exception("jSUP-Transaction数据报校验规则初始化失败"); }log.info("载入成功(count=" + validatorsLoaded.size() + ")..."); return validatorsLoaded; }/** * 载入transaction.xml配置文件 * @param configPath transaction.xml文件路径 * @throws Exception */ private static void loadValidators(String configPath) throws Exception {if ((configPath == null) || (configPath.length() == 0)) {throw new Exception("传入的配置文件路径为空,jSUP-Transaction数据报校验规则加载失败."); }try {//读取transaction.xml文件流 FileInputStream fis = new FileInputStream(configPath); validatorsLoaded = parseJSUPValidationRule(fis); } catch (IOException ex) {ex.printStackTrace(System.out); throw new Exception(ex.getMessage()); }}/** * 分析数据包校验规则 * @param in transaction.xml文件流 * @return Map 交易配置集合 * @throws Exception */ private static Map parseJSUPValidationRule(InputStream in) throws Exception {Map ret = new HashMap(); try {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(in); Element root = doc.getDocumentElement(); //获取子节点[requestHeadCommon标签、responseHeadCommon标签]集合 List reqHeadComVals = TransactionConfigXmlUtil.getChildrenByNodeName(root, "requestHeadCommon", false); List respHeadComVals = TransactionConfigXmlUtil.getChildrenByNodeName(root, "responseHeadCommon", false); if (reqHeadComVals.size() > 1){throw new Exception("requestHeadCommon标签存在多个,"); }if (respHeadComVals.size() > 1){throw new Exception("responseHeadCommon标签存在多个,"); }if (reqHeadComVals.size() == respHeadComVals.size() && reqHeadComVals.size() == 1) {//获取指定节点子节点[<transaction标签>]集合 List allValidators = TransactionConfigXmlUtil.getChildrenByNodeName(root, "transaction", false); for (int j = 0; j < allValidators.size(); ++j) {Node validatorNode = (Node) allValidators.get(j); TransactionXML aValidatorInstance = getValidator(validatorNode,(Node)reqHeadComVals.get(0),(Node)respHeadComVals.get(0)); //存储为Map结构 key:交易码 value:交易码对应校验规则 ret.put(aValidatorInstance.getTransactionID(), aValidatorInstance); }}} catch (Exception ex) {ex.printStackTrace(System.out); throw new Exception(ex.getMessage()); }return ret; }/** * 获取每一transaction子节点配置信息 * @param transactionNode 节点transaction配置信息 * @param reqHeadNode 请求响应头节点集合 * @param respHeadNode 响应请求头节点集合 * @return TransactionXML 子节点信息 * @throws Exception */ private static TransactionXML getValidator(Node transactionNode,Node reqHeadNode,Node respHeadNode) throws Exception {//获取交易ID String transactionID = TransactionConfigXmlUtil.getNodeAttr(transactionNode, "transactionID", false); //初始化交易配置xml对象 TransactionXML aValidator = new TransactionXML(transactionID); //获取transaction节点对应子节点message的结合 List messagesNode = TransactionConfigXmlUtil.getChildrenByNodeName(transactionNode, "message", false); for (Iterator iter = messagesNode.iterator(); iter.hasNext();) {Node element = (Node) iter.next(); //获取message节点的type属性 String type = TransactionConfigXmlUtil.getNodeAttr(element, "type",false); if ("request".equals(type)) {aValidator.setRule4Request(getValidationRule(element,reqHeadNode)); } else if ("response".equals(type))aValidator.setRule4Response(getValidationRule(element,respHeadNode)); else {throw new Exception("校验规则的类型(" + type + ")非法,只能为请求(request)或应答(response)"); }}return aValidator; }/** * 获取校验规则 * @param messageNode message节点对象 * @param commHeadNode 公共请求节点对象 * @return TransactionXMLRule 规则对象 * @throws Exception */ private static TransactionXMLRule getValidationRule(Node messageNode,Node commHeadNode) throws Exception {TransactionXMLRule aNewRule = new TransactionXMLRule(); //获取head节点 Node headNode = TransactionConfigXmlUtil.getFirstChildByNodeName(commHeadNode, "head", false); //设置校验规则 setValidationRuleDetails(aNewRule, headNode, 100, 101); //获取body节点 Node bodyNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "body", false); //设置校验规则 setValidationRuleDetails(aNewRule, bodyNode, 102, 103); return aNewRule; }/** * 设置校验规则明晰 * @param aNewRule TransactionXMLRule对象 * @param transactionResponseNode 节点对象 * @param mandatoryConst 必要元素 * @param optionalConst 可选元素 * @throws Exception */ private static void setValidationRuleDetails(TransactionXMLRule aNewRule, Node transactionResponseNode, int mandatoryConst, int optionalConst) throws Exception {//获取head或者body下field节点集合 List allFieldNodes = TransactionConfigXmlUtil.getChildrenByNodeName(transactionResponseNode, "field", true); if (allFieldNodes != null) {for (int i = 0; i < allFieldNodes.size(); ++i) {Node aParam = (Node) allFieldNodes.get(i); /*********获取field属性值 开始************/ String isOptional = TransactionConfigXmlUtil.getNodeAttr(aParam, "isOptional", false);//true 可选 false必选 String ocrmFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "ocrmFieldName", false);//Po 内属性 String pin = TransactionConfigXmlUtil.getNodeAttr(aParam, "pin", true); String encode = TransactionConfigXmlUtil.getNodeAttr(aParam, "encode", true); String defaul = TransactionConfigXmlUtil.getNodeAttr(aParam, "default", true); String stdCode = TransactionConfigXmlUtil.getNodeAttr(aParam, "stdCode", true); String desc = TransactionConfigXmlUtil.getNodeAttr(aParam, "desc", true); //属性描述 String format = TransactionConfigXmlUtil.getNodeAttr(aParam, "format", true); /*********获取field属性值 结束************/ boolean pinNeeded = (pin != null) && ("true".equals(pin)); boolean encodeNeeded = (encode != null) && ("true".equals(encode)); boolean bStdCode = (stdCode != null) && ("true".equals(stdCode)); //获取field标签文本值 String jsupTransFieldName = TransactionConfigXmlUtil.getNodeTextValue(aParam, false); if ("false".equalsIgnoreCase(isOptional))aNewRule.addField(mandatoryConst, ocrmFieldName, jsupTransFieldName); else {aNewRule.addField(optionalConst, ocrmFieldName,jsupTransFieldName); }if (pinNeeded) {aNewRule.addPin(ocrmFieldName); }if (encodeNeeded) {aNewRule.addEncode(ocrmFieldName); }if (bStdCode) {aNewRule.addStdCode(ocrmFieldName); }aNewRule.setDefaul(ocrmFieldName, defaul); aNewRule.setDesc(ocrmFieldName, desc); aNewRule.setFormat(ocrmFieldName, format); }}//获取field-list内节点 List allFieldListNodes = TransactionConfigXmlUtil.getChildrenByNodeName(transactionResponseNode, "field-list", true); if (allFieldListNodes == null)return; for (int i = 0; i < allFieldListNodes.size(); ++i) {Node aParam = (Node) allFieldListNodes.get(i); /*********获取field-list属性值 开始************/ String isOptional = TransactionConfigXmlUtil.getNodeAttr(aParam, "isOptional", false);//true 可选 false必选 String ocrmFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "ocrmFieldName", false);//Po 内属性 String jsupTransFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "name", false); String jsupTransFieldClass = TransactionConfigXmlUtil.getNodeAttr(aParam, "class", true); //对应class String encode = TransactionConfigXmlUtil.getNodeAttr(aParam, "encode", true); String defaul = TransactionConfigXmlUtil.getNodeAttr(aParam, "default", true); String stdCode = TransactionConfigXmlUtil.getNodeAttr(aParam, "stdCode", true); String desc = TransactionConfigXmlUtil.getNodeAttr(aParam, "desc", true); //属性描述 String format = TransactionConfigXmlUtil.getNodeAttr(aParam, "format", true); /*********获取field-list属性值 结束************/ boolean encodeNeeded = (encode != null) && ("true".equals(encode)); boolean bStdCode = (stdCode != null) && ("true".equals(stdCode)); if ("false".equalsIgnoreCase(isOptional)) {aNewRule.addField(mandatoryConst, ocrmFieldName, jsupTransFieldName); } else {aNewRule.addField(optionalConst, ocrmFieldName, jsupTransFieldName); }aNewRule.setClassName(ocrmFieldName, jsupTransFieldClass); aNewRule.setDefaul(ocrmFieldName, defaul); aNewRule.setDesc(ocrmFieldName, desc); aNewRule.setFormat(ocrmFieldName, format); if (encodeNeeded) {aNewRule.addEncode(ocrmFieldName); }if (bStdCode) {aNewRule.addStdCode(ocrmFieldName); }addSubFieldMapping(aNewRule, aParam); }}/** * 获取循环内信息 * @param aNewRule TransactionXMLRule对象 * @param aNode 相应节点 * @throws Exception */ private static void addSubFieldMapping(TransactionXMLRule aNewRule, Node aNode) throws Exception {//获取field-list下 field节点集合 List allFieldNodes = TransactionConfigXmlUtil.getChildrenByNodeName(aNode, "field", true); if (allFieldNodes != null) {for (int i = 0; i < allFieldNodes.size(); ++i) {Node aParam = (Node) allFieldNodes.get(i); /*********获取field属性值 开始************/ String isOptional = TransactionConfigXmlUtil.getNodeAttr(aParam, "isOptional", false);//true 可选 false必选 String ocrmFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "ocrmFieldName", false); String jsupFieldName = TransactionConfigXmlUtil.getNodeTextValue(aParam, false); String encode = TransactionConfigXmlUtil.getNodeAttr(aParam, "encode", true); String defaul = TransactionConfigXmlUtil.getNodeAttr(aParam, "default", true); String stdCode = TransactionConfigXmlUtil.getNodeAttr(aParam, "stdCode", true); String desc = TransactionConfigXmlUtil.getNodeAttr(aParam, "desc", true); //属性描述 String format = TransactionConfigXmlUtil.getNodeAttr(aParam, "format", true); /*********获取field属性值 结束************/ boolean encodeNeeded = (encode != null) && ("true".equals(encode)); boolean bStdCode = (stdCode != null) && ("true".equals(stdCode)); aNewRule.addField(204, jsupFieldName, ocrmFieldName); if (encodeNeeded) {aNewRule.addEncode(ocrmFieldName); }if (bStdCode) {aNewRule.addStdCode(ocrmFieldName); }aNewRule.setDefaul(ocrmFieldName, defaul); aNewRule.setDesc(ocrmFieldName, desc); aNewRule.setFormat(ocrmFieldName, format); }}//获取field-list下 field-list节点集合 List allFieldListNodes = TransactionConfigXmlUtil.getChildrenByNodeName(aNode, "field-list", true); if (allFieldListNodes == null)return; for (int i = 0; i < allFieldListNodes.size(); ++i) {Node aParam = (Node) allFieldListNodes.get(i); /*********获取field属性值 开始************/ String isOptional = TransactionConfigXmlUtil.getNodeAttr(aParam, "isOptional", false);//true 可选 false必选 String ocrmFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "ocrmFieldName", false);//Po 内属性 String jsupFieldName = TransactionConfigXmlUtil.getNodeAttr(aParam, "name", false); String encode = TransactionConfigXmlUtil.getNodeAttr(aParam, "encode", true); String defaul = TransactionConfigXmlUtil.getNodeAttr(aParam, "default", true); String stdCode = TransactionConfigXmlUtil.getNodeAttr(aParam, "stdCode", true); String desc = TransactionConfigXmlUtil.getNodeAttr(aParam, "desc", true); //属性描述 String format = TransactionConfigXmlUtil.getNodeAttr(aParam, "format", true); /*********获取field属性值 开始************/ boolean encodeNeeded = (encode != null) && ("true".equals(encode)); boolean bStdCode = (stdCode != null) && ("true".equals(stdCode)); aNewRule.addField(204, jsupFieldName, ocrmFieldName); if (encodeNeeded) {aNewRule.addEncode(ocrmFieldName); }if (bStdCode) {aNewRule.addStdCode(ocrmFieldName); }aNewRule.setDefaul(ocrmFieldName, defaul); aNewRule.setDesc(ocrmFieldName, desc); aNewRule.setFormat(ocrmFieldName, format); addSubFieldMapping(aNewRule, aParam); }} }
xml载体类
/** * 个人学习工程 * 日期:2015年11月08日23时56分 */ package com.jsup.transaction.validator; /** * <pre> * 功能说明: * </pre> * * @author 小娃娃 * @version 1.0 * @email urumqimxl@126.com * @issue <> */ public class TransactionXML {private String transactionID; private TransactionXMLRule rule4Request; private TransactionXMLRule rule4Response; public TransactionXML(String transactionID) {this.transactionID = transactionID; }public TransactionXMLRule getRule4Request() {return this.rule4Request; }public TransactionXMLRule getRule4Response() {return this.rule4Response; }public String getTransactionID() {return this.transactionID; }public void setRule4Request(TransactionXMLRule rule) {this.rule4Request = rule; }public void setRule4Response(TransactionXMLRule rule) {this.rule4Response = rule; }public String toString() {String ret = ""; ret = ret + "transactionID:" + this.transactionID + "\n"; ret = ret + "rule4Request:" + this.rule4Request + "\n"; ret = ret + "rule4Response:" + this.rule4Response + "\n"; return ret; }public boolean isPinNeeded(String ocrmFieldName) throws Exception {return ((getRule4Response().isPinNeeded(ocrmFieldName)) || (getRule4Request().isPinNeeded(ocrmFieldName))); }public boolean isEncodeNeeded(String ocrmFieldName) throws Exception {return ((getRule4Response().isEncodeNeeded(ocrmFieldName)) || (getRule4Request().isEncodeNeeded(ocrmFieldName))); }public boolean isStdCodeNeeded(String ocrmFieldName) throws Exception {return ((getRule4Response().isStdCodeNeeded(ocrmFieldName)) || (getRule4Request().isStdCodeNeeded(ocrmFieldName))); } }
校验规则java类
/** * 个人学习工程 * 日期:2015年11月08日23时56分 */ package com.jsup.transaction.validator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * <pre> * 功能说明:校验规则对象 * </pre> * * @author 小娃娃 * @version 1.0 * @email urumqimxl@126.com * @issue <> */ public class TransactionXMLRule {private Map headOptionalFieldNames = new HashMap(); //head 可选元素集合 private Map bodyOptionalFieldNames = new HashMap(); //body 可选元素集合 private Map headMandatoryFieldNames = new HashMap(); //head 必选元素集合 private Map bodyMandatoryFieldNames = new HashMap(); //body 必选元素集合 private Map platNamingMap = new HashMap(); private Map pin = new HashMap(); private Map encode = new HashMap(); private Map defaul = new HashMap(); private Map stdCode = new HashMap(); private Map className = new HashMap(); //class 集合 private Map desc = new HashMap(); //Po内属性 描述 private Map format = new HashMap(); public static final int HEAD_MANDATORY = 100; //head 必选元素标示 public static final int HEAD_OPTIONAL = 101; //head 可选元素标示 public static final int BODY_MANDATORY = 102; //body 必选元素标示 public static final int BODY_OPTIONAL = 103; //body 可选元素标示 public static final int ALL_MANDATORY = 200; public static final int ALL_OPTIONAL = 201; public static final int HEAD_ALL = 202; //所有head元素集合 public static final int BODY_ALL = 203; //所有body元素集合 public static final int SUB_FIELD_LIST_ITEM_NAME_MAPPING = 204;//循环列表 公告元素 /** * 添加映射关系 * @param type 设置类型 * @param ocrmFieldName PO 内属性 * @param jsupTransFieldName 接口内 属性 * @throws Exception */ public void addField(int type, String ocrmFieldName, String jsupFieldName) throws Exception {Map targetMap = null; switch (type) {case HEAD_MANDATORY:targetMap = this.headMandatoryFieldNames; break; case HEAD_OPTIONAL:targetMap = this.headOptionalFieldNames; break; case BODY_MANDATORY:targetMap = this.bodyMandatoryFieldNames; break; case BODY_OPTIONAL:targetMap = this.bodyOptionalFieldNames; break; case SUB_FIELD_LIST_ITEM_NAME_MAPPING:targetMap = this.platNamingMap; break; default:throw new Exception("无法增加字段对应,字段类型非法"); }targetMap.put(ocrmFieldName, jsupFieldName); }/** * 根据类型获取相关映射Map * @param type 类型 * @return Map 相关类型映射Map * @throws Exception */ public Map getFields(int type) throws Exception {Map targetMap = new HashMap(); switch (type) {case HEAD_MANDATORY:targetMap = this.headMandatoryFieldNames; break; case HEAD_OPTIONAL:targetMap = this.headOptionalFieldNames; break; case BODY_MANDATORY:targetMap = this.bodyMandatoryFieldNames; break; case BODY_OPTIONAL:targetMap = this.bodyOptionalFieldNames; break; case ALL_MANDATORY:targetMap.putAll(this.headMandatoryFieldNames); targetMap.putAll(this.bodyMandatoryFieldNames); break; case ALL_OPTIONAL:targetMap.putAll(this.headOptionalFieldNames); targetMap.putAll(this.bodyOptionalFieldNames); break; case HEAD_ALL:targetMap.putAll(this.headOptionalFieldNames); targetMap.putAll(this.headMandatoryFieldNames); break; case BODY_ALL:targetMap.putAll(this.bodyMandatoryFieldNames); targetMap.putAll(this.bodyOptionalFieldNames); break; case SUB_FIELD_LIST_ITEM_NAME_MAPPING:targetMap.putAll(this.platNamingMap); break; default:throw new Exception("无法得到字段mapping,传入的类型非法"); }return targetMap; }public Map getFieldNameMappings(int type) throws Exception {Map ret = new HashMap(); switch (type) {case 300:ret.putAll(this.headOptionalFieldNames); ret.putAll(this.bodyOptionalFieldNames); ret.putAll(this.headMandatoryFieldNames); ret.putAll(this.bodyMandatoryFieldNames); break; case 301:Map mappingFromOcrm2ECTIP = getFieldNameMappings(300); Iterator iter = mappingFromOcrm2ECTIP.keySet().iterator(); while (iter.hasNext()) {String ocrmFieldName = (String) iter.next(); String ECTIPFieldName = (String) mappingFromOcrm2ECTIP.get(ocrmFieldName); if (ret.containsKey(ECTIPFieldName)) {throw new Exception("在JSUP校验规则配置中的字段名非法,JSUP字段名(" + ECTIPFieldName + ")出现重复,JSUP的字段名和OCRM的字段名必须是一一对应的."); }ret.put(ECTIPFieldName, ocrmFieldName); }break; default:throw new Exception("无法得到JSUP和OCRM字段名的映射,传入的类型非法"); }return ret; }public String toString() {String ret = "ValidationRule listed :"; ret = ret + "mandatory header :" + this.headMandatoryFieldNames + "\n"; ret = ret + "optional header :" + this.headOptionalFieldNames + "\n"; ret = ret + "mandatory body :" + this.bodyMandatoryFieldNames + "\n"; ret = ret + "optional body :" + this.bodyOptionalFieldNames + "\n"; return ret; }public void addPin(String ocrmFieldName) {this.pin.put(ocrmFieldName, "true"); }public boolean isPinNeeded(String ocrmFieldName) {return this.pin.containsKey(ocrmFieldName); }public void addEncode(String ocrmFieldName) {this.encode.put(ocrmFieldName, "true"); }public boolean isEncodeNeeded(String ocrmFieldName) {return this.encode.containsKey(ocrmFieldName); }public void setClassName(String ocrmFieldName, String className) {this.className.put(ocrmFieldName, className); }public String getClassName(String ocrmFieldName) {return ((String) this.className.get(ocrmFieldName)); }public void setDefaul(String ocrmFieldName, String strDefaul) {this.defaul.put(ocrmFieldName, strDefaul); }public String getDefaul(String ocrmFieldName) {return ((String) this.defaul.get(ocrmFieldName)); }public void addStdCode(String ocrmFieldName) {this.stdCode.put(ocrmFieldName, "true"); }public boolean isStdCodeNeeded(String ocrmFieldName) {return this.stdCode.containsKey(ocrmFieldName); }public void setDesc(String ocrmFieldName, String strDesc) {this.desc.put(ocrmFieldName, strDesc); }public String getDesc(String ocrmFieldName) {return ((String) this.desc.get(ocrmFieldName)); }public void setFormat(String ocrmFieldName, String strFormat) {this.format.put(ocrmFieldName, strFormat); }public String getFormat(String ocrmFieldName) {return ((String) this.format.get(ocrmFieldName)); }public int getMandatoryNum() {if (this.bodyMandatoryFieldNames != null) {return this.bodyMandatoryFieldNames.size(); }return 0; }public int getFieldListNum() {if (this.platNamingMap != null) {return this.platNamingMap.size(); }return 0; } }
交易配置解析类
/** * 个人学习工程 * 日期:2015年11月08日23时52分 */ package com.jsup.transaction.util; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.List; /** * <pre> * 功能说明:交易配置解析工具类 * </pre> * * @author 小娃娃 * @version 1.0 * @email urumqimxl@126.com * @issue <> */ public class TransactionConfigXmlUtil {/** * 获取指定节点属性值 * @param aNode 节点对象 * @param attrName 属性名称 * @param isOptional 是否可选 * @return String 指定节点属性值 * @throws Exception */ public static String getNodeAttr(Node aNode, String attrName, boolean isOptional) throws Exception {if ((aNode == null) || (attrName == null) || (attrName.length() == 0)) {throw new Exception("无法得到节点的属性,节点名为空或节点为空"); }//获取属性集合 NamedNodeMap nnm = aNode.getAttributes(); //获取指定属性值 Node attrNode = nnm.getNamedItem(attrName); if ((attrNode == null) && (!(isOptional))) {throw new Exception("配置文件格式错误," + aNode.getNodeName() + "节点应指定属性" + attrName); }if (attrNode == null) {return null; }return attrNode.getNodeValue(); }/** * 获取指定节点文本值 * @param element 节点对象 * @param isOptional 是否可选 * @return 返回文本值 * @throws Exception */ public static String getNodeTextValue(Node element, boolean isOptional) throws Exception {String ret = new String(""); if (element == null) {throw new Exception("无法得到节点的文本值,节点为空"); }for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {if ((node.getNodeType() != 3) && (node.getNodeType() != 4))continue; ret = ret.concat(node.getNodeValue()); }if ((ret == null) && (!(isOptional))) {throw new Exception("配置文件格式错误,节点没有文本值"); }return ret; }/** * 获取指定节点子节点集合 * @param aNode 跟节点对象 * @param childNodeName 子节点名称 * @param isOptional 是否可选 * @return List集合 指定节点子节点集合 * @throws Exception */ public static List getChildrenByNodeName(Node aNode, String childNodeName, boolean isOptional) throws Exception {//创建List集合,存放子节点 List ret = new ArrayList(); for (Node child = aNode.getFirstChild(); child != null; child = child.getNextSibling()) {if (!(childNodeName.equals(child.getNodeName())))continue; ret.add(child); }if ((ret.size() == 0) && (!(isOptional))) {throw new Exception("配置文件格式错误,指定的节点" + aNode.getNodeName() + "没有" + childNodeName + "子节点"); }return ret; }/** * 获取指定节点子节点 * @param aNode 跟节点对象 * @param childNodeName 子节点名称 * @param isOptional 是否可选 * @return List集合 指定节点子节点集合 * @throws Exception */ public static Node getFirstChildByNodeName(Node aNode, String childNodeName, boolean isOptional) throws Exception {Node ret = null; for (Node child = aNode.getFirstChild(); child != null; child = child.getNextSibling()) {if (!(childNodeName.equalsIgnoreCase(child.getNodeName())))continue; ret = child; }if ((ret == null) && (!(isOptional))) {throw new Exception("配置文件格式错误,指定的节点" + aNode.getNodeName() + "没有" + childNodeName + "子节点"); }return ret; }/** * 格式化xml * @param sbRet 字符 * @param level 级别 需要添加多少空格 * @param aLine 待添加字符串 */ public static void appendLine(StringBuffer sbRet, int level, String aLine) {String indent = ""; for (int i = 0; i < level; ++i)indent = indent + " "; sbRet.append(indent + aLine + "\n"); } }
发送交易工具类
/** * 个人学习工程 * 日期:2016年11月08日24时42分 */ package com.jsup.transaction.util; import com.jsup.core.transaction.bean.BaseTransBean; import com.jsup.core.utils.ConfigUtils; import com.jsup.core.utils.DateUtils; import com.jsup.transaction.validator.TransactionXML; import com.jsup.transaction.validator.TransactionXMLLoader; import com.jsup.transaction.validator.TransactionXMLRule; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.beans.PropertyDescriptor; import java.io.*; import java.net.*; import java.util.*; import java.util.concurrent.TimeoutException; /** * <pre> * 功能说明:发送交易工具类 * </pre> * * @author 小娃娃 * @version 1.0 * @email urumqimxl@126.com * @issue <> */ public class TransactionUtil {private static int TIMEOUT = 20000;//交易默认超时时间 private static final Log log = LogFactory.getLog(TransactionUtil.class);//初始化log对象 static {try {TIMEOUT = Integer.parseInt(ConfigUtils.getPathByName(("TRANS_SERVLET_TIMEOUT")));//获取报文超时时间 } catch (Exception e) {e.printStackTrace(); TIMEOUT = 20000; }}/** * 向交易网关发送交易请求 * @param reqBean 请求对象 需要继承BaseTransBean * @param resBean 相应对象 需要继承BaseTransBean * @throws ConnectException * @throws SocketException * @throws IOException * @throws TimeoutException * @throws Exception */ public static void send(BaseTransBean reqBean,BaseTransBean resBean) throws ConnectException, SocketException, IOException, TimeoutException, Exception {try {//获取交易码,一般在PO内,无参构造器内进行setHeadTranCode操作 String transactionID = reqBean.getHeadTranCode(); //获取transaction.xml文件map集合 Map validators = TransactionXMLLoader.getValidatorsMap(); //根据交易码获取校验规则 TransactionXML validator = (TransactionXML) validators.get(transactionID); if (validator == null) {throw new Exception("交易类型(" + transactionID + ")未定义校验规则,无法进行交易"); }//请求xml字符 StringBuffer xmlDatagramToSend = null; //报文组包开始时间 long dealReqBeg = System.currentTimeMillis(); //组包xml xmlDatagramToSend = getXMLDatagram(reqBean, validator); //报文组包结束时间 long dealReqEnd = System.currentTimeMillis(); long dealReqTime = dealReqEnd - dealReqBeg; log.info("向jSUP-Transaction发送报文: \n" + xmlDatagramToSend.toString()); //获取交易响应流 InputStream xmlDatagramResponse = getXMLResponse(xmlDatagramToSend.toString(), transactionID); long sendReqEnd = System.currentTimeMillis(); //报文收发耗时 long sendTime = sendReqEnd - dealReqEnd; Map retMap = null; //对返回流进行处理 if ("SMS".equals(transactionID)) {retMap = transformXMLDatagramToMap4Sms(xmlDatagramResponse); } else retMap = transformXMLDatagramToMap(transactionID, xmlDatagramResponse); changeFieldNameFromJsupTrans2Ocrm(retMap, validator, resBean); long dealEnd = System.currentTimeMillis(); long dealTime = dealEnd - sendReqEnd; log.warn("当前交易[" + transactionID + "]发送时间:" + DateUtils.convertDateToString(new Date())); log.warn("当前交易[" + transactionID + "]报文组包耗时:" + dealReqTime + "ms"); log.warn("当前交易[" + transactionID + "]报文收发耗时:" + sendTime + "ms"); log.warn("当前交易[" + transactionID + "]报文解析耗时:" + dealTime + "ms"); } catch (ConnectException ce) {ce.printStackTrace(System.out); log.error("网路连接故障,无法连接jSUP_Transaction系统,可能是端口或服务没有开放,请联系系统管理员!"); throw ce; } catch (SocketException se) {se.printStackTrace(System.out); log.error("网路连接故障,无法连接jSUP_Transaction系统,可能是网络地址无法访问,请联系系统管理员!"); throw se; } catch (IOException ioe) {ioe.printStackTrace(System.out); log.error("I/O操作失败,原因[" + ioe.toString() + "],请联系系统管理员!"); throw ioe; } catch (TimeoutException tox) {tox.printStackTrace(System.out); log.error(tox.toString()); throw tox; } catch (Exception ex) {ex.printStackTrace(System.out); log.error("交易异常,原因[" + ex.toString() + "],请联系系统管理员!"); throw ex; }}/** * 获取请求交易xml字符串 * @param baseTransBean 请求对象 * @param validator 交易码对应交易规则 * @return 返回交易所需xml * @throws Exception */ private static StringBuffer getXMLDatagram(BaseTransBean baseTransBean, TransactionXML validator) throws Exception {StringBuffer ret = new StringBuffer(); TransactionConfigXmlUtil.appendLine(ret, 0, "<?xml version=\"1.0\" encoding=\"" + ConfigUtils.getPathByName("TRANS_SERVLET_ENCODE") + "\"?>"); TransactionConfigXmlUtil.appendLine(ret, 0, "<message>"); TransactionConfigXmlUtil.appendLine(ret, 1, "<head>"); Map headFieldToSend = validator.getRule4Request().getFields(TransactionXMLRule.HEAD_ALL); Iterator iter = headFieldToSend.keySet().iterator(); while (iter.hasNext()) {String ocrmName = (String) iter.next(); String jsupTransItemName = (String) headFieldToSend.get(ocrmName); String value = getAttribute(baseTransBean, ocrmName); if ((value != null) && (!(value.trim().equals("null")))) {if (value.trim().equals("")) {continue; }TransactionConfigXmlUtil.appendLine(ret, 2, "<field name=\"" + jsupTransItemName + "\">" + value.trim() + "</field>"); }}String transSN = SeqnumGenerator.generatorCodeForAG(); TransactionConfigXmlUtil.appendLine(ret, 2, "<field name=\"chanl_flow_no\">" + transSN + "</field>"); TransactionConfigXmlUtil.appendLine(ret, 1, "</head>"); TransactionConfigXmlUtil.appendLine(ret, 1, "<body>"); Map bodyFieldToSend = validator.getRule4Request().getFields(TransactionXMLRule.BODY_ALL); iter = bodyFieldToSend.keySet().iterator(); while (iter.hasNext()) {String ocrmName = (String) iter.next(); String jsupTransItemName = (String) bodyFieldToSend.get(ocrmName); List ocrmObject = null; try {ocrmObject = (ArrayList) getAttributeObject(baseTransBean, ocrmName); } catch (Exception localException) {}if (ocrmObject != null) {Map subFieldListMappingFromOcrm2Ectip = validator.getRule4Request().getFields(TransactionXMLRule.SUB_FIELD_LIST_ITEM_NAME_MAPPING); TransactionConfigXmlUtil.appendLine(ret, 2, "<" + jsupTransItemName + ">"); for (int i = 0; i < ocrmObject.size(); ++i) {TransactionConfigXmlUtil.appendLine(ret, 3, "<field-list>"); Object listObj = ocrmObject.get(i); Iterator subIter = subFieldListMappingFromOcrm2Ectip.keySet().iterator(); while (subIter.hasNext()) {String subJsupTransFieldName = (String) subIter.next(); String subOcrmName = (String) subFieldListMappingFromOcrm2Ectip.get(subJsupTransFieldName); String strValue = getAttribute(listObj, subOcrmName); if ((strValue == null)|| (strValue.trim().equals("null"))) {if (validator.getRule4Request().getDefaul(subOcrmName) != null)strValue = validator.getRule4Request().getDefaul(subOcrmName); else {strValue = ""; }}TransactionConfigXmlUtil.appendLine(ret, 4, "<field name=\"" + subJsupTransFieldName + "\"" + ">" + strValue.trim() + "</field>"); }TransactionConfigXmlUtil.appendLine(ret, 3, "</field-list>"); }TransactionConfigXmlUtil.appendLine(ret, 2, "</" + jsupTransItemName + ">"); } else {String value = getAttribute(baseTransBean, ocrmName); if ((value == null) || (value.trim().equals("null"))) {if (validator.getRule4Request().getDefaul(ocrmName) == null)continue; value = validator.getRule4Request().getDefaul(ocrmName); }validator.isStdCodeNeeded(ocrmName); String pinStr = ""; if (validator.isPinNeeded(ocrmName)) {pinStr = " pin=\"true\""; }validator.isEncodeNeeded(ocrmName); TransactionConfigXmlUtil.appendLine(ret, 2, "<field name=\"" + jsupTransItemName + "\"" + pinStr + ">" + value.trim() + "</field>"); }}TransactionConfigXmlUtil.appendLine(ret, 1, "</body>"); TransactionConfigXmlUtil.appendLine(ret, 0, "</message>"); return ret; }private static String getAttribute(Object obj, String ocrmName)throws Exception {ocrmName = ocrmName.replace('.', '#'); String[] names = ocrmName.split("#"); Object objTmp = obj; for (int i = 0; i < names.length; ++i) {objTmp = PropertyUtils.getProperty(objTmp, names[i]); }return (String)objTmp; }/** * 获取属性值 * @param obj 对象 * @param ocrmName Po内属性 * @return Object 对象 * @throws Exception */ private static Object getAttributeObject(Object obj, String ocrmName) throws Exception {ocrmName = ocrmName.replace('.', '#'); String[] names = ocrmName.split("#"); Object objTmp = obj; for (int i = 0; i < names.length; ++i) {objTmp = PropertyUtils.getProperty(objTmp, names[i]); }return objTmp; }/** * 获取交易网关返回流 * @param datagram 请求交易字符串 * @param transactionId 交易码 * @return 响应流 * @throws ConnectException * @throws SocketException * @throws Exception */ private static InputStream getXMLResponse(String datagram, String transactionId) throws ConnectException, SocketException, Exception {//目标URL String destUrl = ""; //从config.properties文件获取交易网关地址 destUrl = ConfigUtils.getPathByName("TRANS_SERVLET_URL"); //获取交易码 destUrl = destUrl + "?TranCode=" + transactionId; //对请求交易xml进行编码 destUrl = destUrl + "&xml=" + URLEncoder.encode(datagram, ConfigUtils.getPathByName("TRANS_SERVLET_ENCODE")); log.info("jSUP_Transaction_URL>>>>>>>>>>" + destUrl); URL url = new URL(destUrl); URLConnection conn = url.openConnection(); //设置链接超时时间 conn.setReadTimeout(TIMEOUT); conn.setDoOutput(true); conn.setDoInput(true); try {//获取返回流 InputStream in = conn.getInputStream(); return in; } catch (ConnectException ce) {ce.printStackTrace(); throw ce; } catch (SocketException se) {se.printStackTrace(); throw se; } catch (Exception e) {e.printStackTrace(); throw new TimeoutException("从jSUP_Transaction获得返回报文超时!"); }}private static Map transformXMLDatagramToMap4Sms(InputStream in) throws Exception {BufferedReader reader = new BufferedReader(new InputStreamReader(in, ConfigUtils.getPathByName("TRANS_SERVLET_ENCODE"))); String xmlDatagram = ""; String aLine = ""; while ((aLine = reader.readLine()) != null) {xmlDatagram = xmlDatagram + aLine; xmlDatagram = xmlDatagram + "\n"; }Map ret = new HashMap(); if (xmlDatagram == null) {throw new Exception("返回报文为空!"); }InputSource is = new InputSource(new StringReader(xmlDatagram)); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); Element messageNode = doc.getDocumentElement(); Node messageItemNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "MessageItem", false); Node bodyNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageItemNode, "body", false); for (Node child = bodyNode.getFirstChild(); child != null; child = child.getNextSibling()) {String nodeName = child.getNodeName(); String nodeValue = TransactionConfigXmlUtil.getNodeTextValue(child, true); ret.put(nodeName, nodeValue); }return ret; }private static Map transformXMLDatagramToMap(String xmlDatagram)throws Exception {log.info("挡板报文: \n" + xmlDatagram); Map ret = new HashMap(); if (xmlDatagram == null) {throw new Exception("jSUP_Transaction系统返回报文为空!"); }InputSource is = new InputSource(new StringReader(xmlDatagram)); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); Element messageNode = doc.getDocumentElement(); List nodesToBeParsed = new ArrayList(); Node headNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "head", false); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(headNode, "field", false)); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(headNode, "field-list", true)); Node bodyNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "body", false); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(bodyNode, "field", true)); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(bodyNode, "field-list", true)); ret = parseDatagram(nodesToBeParsed); return ret; }/** * 对返回流进行Map转换 * @param transactionID 交易码 * @param in 交易返回流 * @return 返回Map结构数据 * @throws Exception */ private static Map transformXMLDatagramToMap(String transactionID, InputStream in) throws Exception {//编码设置 String charseName = ConfigUtils.getPathByName("TRANS_SERVLET_ENCODE"); BufferedReader reader = null; //返回xml String xmlDatagram = ""; String aLine = ""; try {//读取流操作 reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(in), charseName)); while ((aLine = reader.readLine()) != null) {xmlDatagram = xmlDatagram + aLine; xmlDatagram = xmlDatagram + "\n"; }} catch (Exception e) {e.printStackTrace(System.out); log.error("I/O操作失败,原因[" + e.toString() + "],请联系系统管理员!"); throw e; } finally {if (reader != null) {reader.close(); }if (in != null) {in.close(); }}log.info("jSUP_Transaction系统返回报文: \n" + xmlDatagram); Map ret = new HashMap(); if (StringUtils.isEmpty(xmlDatagram)) {throw new Exception("jSUP_Transaction系统返回报文为空!"); }InputSource is = new InputSource(new StringReader(xmlDatagram)); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(is); Element messageNode = doc.getDocumentElement(); List nodesToBeParsed = new ArrayList(); Node headNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "head", false); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(headNode, "field", false)); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(headNode, "field-list", true)); Node bodyNode = TransactionConfigXmlUtil.getFirstChildByNodeName(messageNode, "body", false); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(bodyNode, "field", true)); nodesToBeParsed.addAll(TransactionConfigXmlUtil.getChildrenByNodeName(bodyNode, "field-list", true)); ret = parseDatagram(nodesToBeParsed); return ret; }/** * 解析为Map结构 * @param nodesToBeParsed * @return * @throws Exception */ private static Map parseDatagram(List nodesToBeParsed) throws Exception {Map ret = new HashMap(); for (Iterator iter = nodesToBeParsed.iterator(); iter.hasNext();) {Node element = (Node) iter.next(); String nodeName = element.getNodeName(); if ("field".equals(nodeName)) {ret.putAll(processFieldNode(element)); } else if ("field-list".equals(nodeName)) {String fieldListName = TransactionConfigXmlUtil.getNodeAttr(element, "name", false); ret.put(fieldListName, processListNode(element)); } else {throw new Exception("节点名称错误,名称应为 field 或 field-list ,现有名称为:" + nodeName); }}return ret; }/** * 对field-list进行处理 * @param element * @return * @throws Exception */ private static Map processListNode(Node element) throws Exception {Map ret = new TreeMap(); List fieldNodes = TransactionConfigXmlUtil.getChildrenByNodeName(element, "field", true); for (Iterator iter = fieldNodes.iterator(); iter.hasNext();) {Node aFieldNode = (Node) iter.next(); ret.putAll(processFieldNode(aFieldNode)); }List fieldListNodes = TransactionConfigXmlUtil.getChildrenByNodeName(element, "field-list", true); for (Iterator iter = fieldListNodes.iterator(); iter.hasNext();) {Node aFieldListNode = (Node) iter.next(); Map tmpMap = processListNode(aFieldListNode); String listItemName = TransactionConfigXmlUtil.getNodeAttr(aFieldListNode, "name", false); try {Integer listSeqNum = Integer.valueOf(listItemName); ret.put(listSeqNum, tmpMap); } catch (Exception ex) {ex.printStackTrace(System.out); throw new Exception("二级 field-list 节点名称的取值应为非负整数,现有返回报文中的数据(" + listItemName + ")非法"); }}return ret; }/** * 对field进行MAP处理 * @param element * @return * @throws Exception */ private static Map processFieldNode(Node element) throws Exception {Map ret = new HashMap(); String itemName = TransactionConfigXmlUtil.getNodeAttr(element, "name", false); String itemValue = TransactionConfigXmlUtil.getNodeTextValue(element, false); ret.put(itemName, itemValue); return ret; }/** * 将结果处理为系统对象 * @param origMap 返回Map * @param validator 校验规则 * @param resBean 返回对象 * @throws Exception */ private static void changeFieldNameFromJsupTrans2Ocrm(Map origMap, TransactionXML validator, BaseTransBean resBean) throws Exception {Map fieldNameMappingFromJsupTrans2Ocrm = validator.getRule4Response().getFieldNameMappings(301); Map subFieldListMappingFromJsupTrans2Ocrm = validator.getRule4Response().getFields(TransactionXMLRule.SUB_FIELD_LIST_ITEM_NAME_MAPPING); HashMap listMap = new HashMap(); Iterator iter = origMap.keySet().iterator(); while (iter.hasNext()) {String jsupTransFieldName = (String) iter.next(); Object value = origMap.get(jsupTransFieldName); String ocrmFieldName = (String) fieldNameMappingFromJsupTrans2Ocrm.get(jsupTransFieldName); String className = validator.getRule4Response().getClassName(ocrmFieldName); if (!(StringUtils.isEmpty(jsupTransFieldName))) {if (StringUtils.isEmpty(ocrmFieldName)) {continue; }if (value instanceof Map) {List list = new ArrayList(); setSubValue((Map) value, subFieldListMappingFromJsupTrans2Ocrm, className, resBean, list, validator); value = list; if (!(StringUtils.isEmpty(className)))setAttribute(resBean, ocrmFieldName, value); } else {Object tmp = preAdjust(validator, ocrmFieldName, value); setAttribute(resBean, ocrmFieldName, tmp); }}}}private static void setSubValue(Map origMap, Map nameMapping, String className, Object bean, List list, TransactionXML validator) throws Exception {Object objTmp = null; Iterator iter = origMap.keySet().iterator(); while (iter.hasNext()) {Object jsupTransFieldName = iter.next(); Object value = origMap.get(jsupTransFieldName); String ocrmFieldName = (jsupTransFieldName instanceof Integer) ? jsupTransFieldName.toString() : (String) nameMapping.get(jsupTransFieldName); if (StringUtils.isEmpty(ocrmFieldName)) {continue; }if (value instanceof Map) {setSubValue((Map) value, nameMapping, className, bean, list, validator); } else if (StringUtils.isEmpty(className)) {Object tmp = preAdjust(validator, ocrmFieldName, value); setAttribute(bean, ocrmFieldName, tmp); } else if (objTmp == null) {objTmp = Class.forName(className).newInstance(); Object tmp = preAdjust(validator, ocrmFieldName, value); setAttribute(objTmp, ocrmFieldName, tmp); } else {Object tmp = preAdjust(validator, ocrmFieldName, value); setAttribute(objTmp, ocrmFieldName, tmp); }}if (objTmp != null)list.add(objTmp); }private static void setAttribute(Object obj, String ocrmName, Object value) throws Exception {ocrmName = ocrmName.replace('.', '#'); String[] names = ocrmName.split("#"); Object objTmp1 = obj; Object objTmp2 = null; for (int i = 0; i < names.length - 1; ++i) {objTmp2 = PropertyUtils.getProperty(objTmp1, names[i]); if (objTmp2 == null) {PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(objTmp1, names[i]); objTmp2 = propertyDescriptor.getPropertyType().newInstance(); PropertyUtils.setProperty(objTmp1, names[i], objTmp2); }objTmp1 = objTmp2; }PropertyUtils.setProperty(objTmp1, names[(names.length - 1)], value); }private static Object preAdjust(TransactionXML validator, String ocrmFieldName, Object value) throws Exception {if (!(value instanceof String)) {return value; }String strValue = (String) value; StringBuffer result = new StringBuffer(); String format = validator.getRule4Response().getFormat(ocrmFieldName); if (!(StringUtils.isEmpty(format))) {char[] aryChar = format.toCharArray(); char[] aryResult = strValue.toCharArray(); int j = 0; for (int i = 0; i < aryChar.length; ++i) {if (aryChar[i] == '?') {if (j < aryResult.length) {result.append(aryResult[(j++)]); }} else {result.append(aryChar[i]); }}}if (StringUtils.isEmpty(result.toString())) {result.append(strValue); }return result.toString(); }}
代码描述
以上java类为核心代码,通过这几个文件,极大的简化了开发流程,使用者只要通过配置接口,将发送交易的事情交由交易网关处理即可。如此一来,应用系统只要关注业务即可。当然以上代码只是描述了应用系统如何与交易网关对接。后续文章将会跟进。
欢迎大家提出建议,就让我们一起享受代码的乐趣吧。
转载于:https://my.oschina.net/jsup/blog/822821
应用系统如何与外部渠道进行对接?java代码实现篇相关推荐
- adobe reader java_请问,如何用JAVA读PDF文件在浏览器中显示,不需要在本地系统中安装Adobe Reader。求java代码...
JAVA读PDF可以实现,重点是如何在网页中显示PDF文件,而且不需要安装AdobeReader.没有安装AdobeReader,在网页显示PDF文件时,浏览器会提示下载.请问如何在网页中显示PDF文 ...
- ROS中阶笔记(一):机器人系统设计—ROS系统下连接外部传感器
ROS中阶笔记(一):机器人系统设计-ROS系统下连接外部传感器 文章目录 01 连接摄像头 1.1 ROS下连接usb_cam 1.1.1 前期准备 1.1.2 问题 1.1.3 安装usb_cam ...
- 管家婆全渠道可以对接的WMS说明文档
管家婆全渠道可以对接以下WMS: 支持的单据类型(不支持批次.序列号) 1.辉煌.辉煌ERP: 入库类: 采购入库.调拨入库.销售退货.其他入库.报溢单 出库类: 销售出库.调拨出库.采购退货.其他出 ...
- 头条巨量快手广点通等平台APPAPI回传事件注册激活-转化联调-API对接原理代码分析和功能实现
2022年最新的头条巨量快手广点通等各推广平台APP&API回传事件-转化联调注册激活-API对接原理代码分析和功能实现! 在商户推广管理当中,经常碰到 需要将用户行为数据回传给推广平台.做转 ...
- 使用Java代码在应用层获取Android系统属性
之前使用Native代码的property_get()/property_set()来获取Android系统属性,现在需要改写到Java上面, 但是System.getProperty() / Sys ...
- 成绩查询系统源java代码_基于jsp的成绩查询系统-JavaEE实现成绩查询系统 - java项目源码...
基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的成绩查询系统, 该项目可用各类java课程设计大作业中, 成绩查询系统的系统架构分为前后台两部分, 最终实现在线上 ...
- 体验.NET Core使用IKVM对接Java
[导读]与第三方对接最麻烦的是语言不同,因语言不同内置实现相关标准加密算法还是略微有所差异 对接单点登录场景再寻常不过,由于时间紧迫且对接方使用Java,所以留给我对接开发和联调的时间本就不多,于是乎 ...
- oracle java javapath_系统找不到C:\ProgramData\Oracle\Java\javapath\java.exe问题及解决方案...
前一段时间本人的电脑崩溃了,系统还原之后,eclipse就用不了,也找不大原因.eclipse报错原因是jvm出现问题:JVM terminated Exit code=2 C:\ProgramDat ...
- java 试卷自动生成_基于JAVA的试题自动生成系统 - WEB源码|JSP源码/Java|源代码 - 源码中国...
压缩包 : 试卷自动生成系统.rar 列表 试卷自动生成系统/.classpath 试卷自动生成系统/.project 试卷自动生成系统/bin/Db/Sql.class 试卷自动生成系统/bin/f ...
最新文章
- python中tornado的第一个例子
- 关于Visual Studio2019的4996错误警告解决方法
- 水平和垂直翻转可视对象
- Android Display buffer_handle_t的定义
- python可以自学吗-没学过编程可以自学python吗
- 错误:返回局部变量数组名 \ 解决方案
- Swift 开发的工具类,主要是提供正则表达式及其它,Github会长期维护
- 是vans_Vans 的旧海报上原来有这么多学问…
- SpringBoot精通系列-开发案例之配置Druid数据库连接池
- 路径-真机和虚拟机共享
- jQuery length和size()区别总结如下:
- button按钮提交form表单的js方法不要使用关键字login
- 卡密激活php代码,全自动PHP授权检测系统,卡密功能自助授权功能源码
- .net core linux 界面,C# dotnet core + AvaloniaUI 开发桌面软件,hello world
- 「实战」南京房价的秘密——准备篇
- 后端程序员必会:并发情况下redis-lua保证原子操作
- 微博官方API使用方法【全流程教学】
- Ubuntu 22.04 ‘Jammy Jellyfish‘ 的新功能
- 蓝桥杯——瓷砖样式(第八届决赛)
- CSS,font-family,好看,常用,中文,字体(更新中)
热门文章
- 国三数据库系统工程师与软考中的数据库工程师,谁的难度更高?
- Spark数据分区(partitionBy分区、partitioner获取分区方式、自定义分区)
- 2022年磺化工艺考试练习题及模拟考试
- JVM 垃圾回收详解
- QPST 2.7.460 高通产品专用支持套件 (Qualcomm Product Support Tools)
- 用Python校验下载文件的完整性(md5),游戏之类的大型文件
- mysql 查看等待事件_分享两个实用SQL--查看故障时间等待事件、问题sql及会话访问次数...
- UUID去横杠的5种方式
- iPhone自动旋转控制代码-IOS开发
- 计算机应用基础上册周测7,计算机应用基础(第3版)周南岳(win7+office10)期末复习及答案-20210614221003.docx-原创力文档...