一个应用系统要与支付对接,要与短信平台对接,要与其他业务系统对接,甚至于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类为核心代码,通过这几个文件,极大的简化了开发流程,使用者只要通过配置接口,将发送交易的事情交由交易网关处理即可。如此一来,应用系统只要关注业务即可。当然以上代码只是描述了应用系统如何与交易网关对接。后续文章将会跟进。
欢迎大家提出建议,就让我们一起享受代码的乐趣吧。