文档章节

应用系统如何与外部渠道进行对接?java代码实现篇

jSUP
 jSUP
发布于 2017/01/11 12:42
字数 6194
阅读 1089
收藏 57

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

 

欢迎大家提出建议,就让我们一起享受代码的乐趣吧。

© 著作权归作者所有

jSUP
粉丝 21
博文 4
码字总数 9507
作品 0
海淀
高级程序员
私信 提问
加载中

评论(6)

jSUP
jSUP 博主

引用来自“田舍先生”的评论

网关独立抽象出来,避免直接调用,统一调用入口, 屏蔽调用差异。
恩恩,还需要不断的改善
O龙猫O
O龙猫O
网关独立抽象出来,避免直接调用,统一调用入口, 屏蔽调用差异。
jSUP
jSUP 博主

引用来自“zzuqiang”的评论

没看懂讲解的是什么?
批评的有道理。不过我这部分代码不是在实现ESB相关的东西。嘿嘿......
jSUP
jSUP 博主

引用来自“zzuqiang”的评论

没看懂讲解的是什么?
实在不好意思,可能写的不是很清晰。其实我的想法是这样的:一般应用系统与外围系统对接,可能在对接的前面会有一个统一通讯网关平台。所有的对接任务都由统一通讯网关完成。由统一通讯网关去适配外围系统提供的接口。再由统一通讯网关统一返回应用系统所需的内容。如此这样考虑,应用系统就只专注业务层即可。贴出的代码就是应用系统如何与统一通讯网关对接。而非统一通讯网关的实现。你想外围系统接口你不能保证都是统一的风格,难道这些任务都交接给应用系统实现,那应用系统对开发多少适配代码啊......
有云的天空
有云的天空
何必轮子,请用ESB
zzuqiang
zzuqiang
没看懂讲解的是什么?
在Kubernetes 部署基于 MicroProfile 的 Java 微服务

要在如今快节奏的开发环境中取得成功,利用容器技术和 DevOps 实践来构建并持续交付微服务非常重要。本篇 Code Pattern 将展示如何使用 MicroProfile 和 Kubernetes 并借助您已掌握的技能和经...

宋庆离
2018/02/05
4.5K
3
Eclipse jni应用中遇到的问题

一个android的软件因为要用C库,因此采用JNI技术实现,使用中遇到一问题请大牛们帮忙解决。 C函数库中增加一个Java接口文件,其中一接口如下: jint Java_com_example_xxx_ecuAddr( JNIEnv*...

fcsong000833
2013/09/02
124
0
三流程序员与一流程序员之间的区别,看看你是属于哪一类?

源码系列 手写spring mvc框架 基于Spring JDBC手写ORM框架 实现自己的MyBatis Spring AOP实战之源码分析 Spring IOC高级特性应用分析 ORM框架底层实现原理剖析 手写Spring MVC框架实现 手把手...

茶轴的青春
2018/04/17
34
0
Java开发者不会这些永远都只能是三流程序员,细数一下你是不是?

源码系列 手写spring mvc框架 基于Spring JDBC手写ORM框架 实现自己的MyBatis Spring AOP实战之源码分析 Spring IOC高级特性应用分析 ORM框架底层实现原理剖析 手写Spring MVC框架实现 手把手...

美的让人心动
2018/04/16
122
5
禁止JVM执行外部命令Runtime.exec -- 由Apache Commons Collections漏洞引发的思考

update: 2015-11-16 新版apache commons collections 3.2.2修复漏洞 新版本的apache commons collections默认禁止了不安全的一些转换类。可以通过升级来修复漏洞。参考release说明:https:/...

横云断岭
2015/11/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
64
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
26
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
43
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
27
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
昨天
44
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部