一个应用系统要与支付对接,要与短信平台对接,要与其他业务系统对接,甚至于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代码实现篇相关推荐

  1. adobe reader java_请问,如何用JAVA读PDF文件在浏览器中显示,不需要在本地系统中安装Adobe Reader。求java代码...

    JAVA读PDF可以实现,重点是如何在网页中显示PDF文件,而且不需要安装AdobeReader.没有安装AdobeReader,在网页显示PDF文件时,浏览器会提示下载.请问如何在网页中显示PDF文 ...

  2. ROS中阶笔记(一):机器人系统设计—ROS系统下连接外部传感器

    ROS中阶笔记(一):机器人系统设计-ROS系统下连接外部传感器 文章目录 01 连接摄像头 1.1 ROS下连接usb_cam 1.1.1 前期准备 1.1.2 问题 1.1.3 安装usb_cam ...

  3. 管家婆全渠道可以对接的WMS说明文档

    管家婆全渠道可以对接以下WMS: 支持的单据类型(不支持批次.序列号) 1.辉煌.辉煌ERP: 入库类: 采购入库.调拨入库.销售退货.其他入库.报溢单 出库类: 销售出库.调拨出库.采购退货.其他出 ...

  4. 头条巨量快手广点通等平台APPAPI回传事件注册激活-转化联调-API对接原理代码分析和功能实现

    2022年最新的头条巨量快手广点通等各推广平台APP&API回传事件-转化联调注册激活-API对接原理代码分析和功能实现! 在商户推广管理当中,经常碰到 需要将用户行为数据回传给推广平台.做转 ...

  5. 使用Java代码在应用层获取Android系统属性

    之前使用Native代码的property_get()/property_set()来获取Android系统属性,现在需要改写到Java上面, 但是System.getProperty() / Sys ...

  6. 成绩查询系统源java代码_基于jsp的成绩查询系统-JavaEE实现成绩查询系统 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的成绩查询系统, 该项目可用各类java课程设计大作业中, 成绩查询系统的系统架构分为前后台两部分, 最终实现在线上 ...

  7. 体验.NET Core使用IKVM对接Java

    [导读]与第三方对接最麻烦的是语言不同,因语言不同内置实现相关标准加密算法还是略微有所差异 对接单点登录场景再寻常不过,由于时间紧迫且对接方使用Java,所以留给我对接开发和联调的时间本就不多,于是乎 ...

  8. oracle java javapath_系统找不到C:\ProgramData\Oracle\Java\javapath\java.exe问题及解决方案...

    前一段时间本人的电脑崩溃了,系统还原之后,eclipse就用不了,也找不大原因.eclipse报错原因是jvm出现问题:JVM terminated Exit code=2 C:\ProgramDat ...

  9. java 试卷自动生成_基于JAVA的试题自动生成系统 - WEB源码|JSP源码/Java|源代码 - 源码中国...

    压缩包 : 试卷自动生成系统.rar 列表 试卷自动生成系统/.classpath 试卷自动生成系统/.project 试卷自动生成系统/bin/Db/Sql.class 试卷自动生成系统/bin/f ...

最新文章

  1. python中tornado的第一个例子
  2. 关于Visual Studio2019的4996错误警告解决方法
  3. 水平和垂直翻转可视对象
  4. Android Display buffer_handle_t的定义
  5. python可以自学吗-没学过编程可以自学python吗
  6. 错误:返回局部变量数组名 \ 解决方案
  7. Swift 开发的工具类,主要是提供正则表达式及其它,Github会长期维护
  8. 是vans_Vans 的旧海报上原来有这么多学问…
  9. SpringBoot精通系列-开发案例之配置Druid数据库连接池
  10. 路径-真机和虚拟机共享
  11. jQuery length和size()区别总结如下:
  12. button按钮提交form表单的js方法不要使用关键字login
  13. 卡密激活php代码,全自动PHP授权检测系统,卡密功能自助授权功能源码
  14. .net core linux 界面,C# dotnet core + AvaloniaUI 开发桌面软件,hello world
  15. 「实战」南京房价的秘密——准备篇
  16. 后端程序员必会:并发情况下redis-lua保证原子操作
  17. 微博官方API使用方法【全流程教学】
  18. Ubuntu 22.04 ‘Jammy Jellyfish‘ 的新功能
  19. 蓝桥杯——瓷砖样式(第八届决赛)
  20. CSS,font-family,好看,常用,中文,字体(更新中)

热门文章

  1. 国三数据库系统工程师与软考中的数据库工程师,谁的难度更高?
  2. Spark数据分区(partitionBy分区、partitioner获取分区方式、自定义分区)
  3. 2022年磺化工艺考试练习题及模拟考试
  4. JVM 垃圾回收详解
  5. QPST 2.7.460 高通产品专用支持套件 (Qualcomm Product Support Tools)
  6. 用Python校验下载文件的完整性(md5),游戏之类的大型文件
  7. mysql 查看等待事件_分享两个实用SQL--查看故障时间等待事件、问题sql及会话访问次数...
  8. UUID去横杠的5种方式
  9. iPhone自动旋转控制代码-IOS开发
  10. 计算机应用基础上册周测7,计算机应用基础(第3版)周南岳(win7+office10)期末复习及答案-20210614221003.docx-原创力文档...