asp.net core 3.1开发交通银行支付接口笔记一底层代码

asp.net core 3.1开发交通银行支付接口笔记二支付

asp.net core 3.1开发交通银行支付接口笔记三退款、查询和收尾

例行吐槽

这个接口上一年很早时候客户就和银行对接了。知道元旦后才给的接口。这效率。。。没谁了。所以,我回老家过完元旦赶紧火急火燎的赶回来写码。按照经验,这
个接口只要写得好没歧义、完整难度不大。如果有源码接口DEMO提供,速度可以控制在半天内。可是呢提供过来有助于开发的只有2个

1:交通银行“慧智付”报文交换规范(商户正式版)文档(只有接口说明连流程都没有)

2:签名验签方法代码(java版一份,socket版其它语言一份)

当时没说明这个socket是干嘛的,java的还是看使用配置说明看出是java版。socket我看了是java的包,顿时懵逼结果一顿很久的沟通操作后回复说其它语言用socket,我去,在说明包里面加个说明文档就那么难?好了,接下来开始

开始开发前的选择

因为我这个项目要求手机公众号支付,当时因为不懂交行支付是啥流程,文档也没写流程。

于是自己按照经验设计是跳转交行他们的H5页面输入卡号信息支付完成后再跳转回来

文档没有写流程只好看文字盲猜选定跳转支付扣款,不过后来又折腾了一顿客户和交行开发人员一起建了个群,通过咨询得知,这个这个跳转支付是在本地网页点击支付>跳转交行服务器>输入微信密码>完成支付。唉在文档加个流程就这么难?

配置:原来SOCKET启动后发送加签信息返回00000000联系了交行技术人员,然后提供了2个商户号。一个加签用一个交易用。。。。这操作。。。

按照说明书放置电子证书。写配置商户号和密码。日志路径即可。文档这个倒是写的明白。

开始开发

第一步:写底层代码。这里代码比较多。就放入有代表性的一些意思意思即可

 第一点:先是生成xml信息的

其它的生成只要按照这个生成即可

        /// <summary>
        /// 生成支付报文
        /// </summary>
        /// <param name="orderNo">订单号</param>
        /// <param name="pay">支付金额</param>
        /// <param name="tranContent">客户看的内容</param>
        /// <param name="remark">后台看的备注</param>
        /// <returns></returns>
        public static string CreatePayMessage(string orderNo, decimal pay, string tranContent, string remark)
        {
            XmlDocument xmldoc = new XmlDocument();
            //加入XML的声明段落:<?xmlversion="1.0" encoding="utf-8"?>
            XmlDeclaration xmldecl = xmldoc.CreateXmlDeclaration("1.0", "utf-8", null);
            xmldoc.AppendChild(xmldecl);
            //root节点
            XmlElement rootNode = xmldoc.CreateElement("Document");
            rootNode.AppendChild(createHeadXML(xmldoc, "接口标识号"));
            rootNode.AppendChild(createPayBodyXML(xmldoc, orderNo, pay, tranContent, remark));
            xmldoc.AppendChild(rootNode);
            return signMessage(xmldoc);
        }
        /// <summary>
        /// 生成支付内容XML
        /// </summary>
        /// <param name="xmldoc">主XML</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="pay">支付金额</param>
        /// <param name="tranContentStr">客户看的内容</param>
        /// <param name="remark">后台看的备注</param>
        /// <returns></returns>
        private static XmlElement createPayBodyXML(XmlDocument xmldoc, string orderNo, decimal pay, string tranContentStr, string remark)
        {
            XmlElement bodyNode = xmldoc.CreateElement("Body");
            //商户交易编号
            XmlElement payMerTranNo = xmldoc.CreateElement("PayMerTranNo");
            payMerTranNo.InnerText = orderNo;
            bodyNode.AppendChild(payMerTranNo);
            //线上或线下
            XmlElement location = xmldoc.CreateElement("Location");
            location.InnerText = "ONLINE";
            bodyNode.AppendChild(location);
            //交易场景
            XmlElement tranScene = xmldoc.CreateElement("TranScene");
            tranScene.InnerText = "B2C-JSAPI-WECHAT";
            bodyNode.AppendChild(tranScene);
            //金额
            XmlElement amount = xmldoc.CreateElement("Amount");
            amount.InnerText = pay.ToString("0.00");
            bodyNode.AppendChild(amount);
            //币种
            XmlElement currency = xmldoc.CreateElement("Currency");
            currency.InnerText = "CNY";
            bodyNode.AppendChild(currency);
            //交易内容
            XmlElement tranContent = xmldoc.CreateElement("TranContent");
            tranContent.InnerText = tranContentStr;
            bodyNode.AppendChild(tranContent);
            //商户内部备注
            XmlElement merMemo = xmldoc.CreateElement("MerMemo");
            merMemo.InnerText = remark;
            bodyNode.AppendChild(merMemo);
            //交易选项(暂时不用。留着)
            //交易失效时间
            XmlElement validPeriod = xmldoc.CreateElement("ValidPeriod");
            validPeriod.InnerText = DateTime.Now.AddMinutes(30).ToString("yyyyMMddHHmmss");
            bodyNode.AppendChild(validPeriod);
            //后台通知地址
            XmlElement notifyURL = xmldoc.CreateElement("NotifyURL");
            notifyURL.InnerText = GlobalData.TranInfo["notifyurl"];
            bodyNode.AppendChild(notifyURL);
            //前台通知地址(暂时不用微信公众号无法通知,员工后台让操作员自己刷新页面即可)
            //需要通知中返回的字段(暂时不用)
            return bodyNode;
        }

   第二点:加签解签。

要吐槽一下。文档给的这段极为有歧义,这个AttachedSign和AttachedVerify没说明是啥。就写这个英文单词在这里,因为看了java代码,当时我理解成是加签后的字符串,或者调用java里面的一个加签方法。,然后可想而知,一顿操作猛如虎,返回加签0000000,问了技术人员才知道正确意思。又浪费N多时间

 

加签,这里注意。是要AttachedSign开始到末尾的字节长度。不是字符长度。这里文档没仔细看。。。。可是呢?如果长度<文档字节长度才出现问题,当然。。这个长度是从单词AttachedSign或AttachedVerify开始算起。。这个文档没说。。这里继续浪费时间。。。。。。

.

        /// <summary>
        /// 给报文签名
        /// </summary>
        /// <param name="xmldoc">xml报文</param>
        /// <returns></returns>
        private static string signMessage(XmlDocument xmldoc)
        {
            string temp = "AttachedSign" + GlobalData.TranInfo["商户号"] + xmldoc.OuterXml;
            int strLength = Encoding.UTF8.GetByteCount(temp);
            string tempSign = BCMSocket.GetData(strLength.ToString().PadLeft(8, '0') + temp);
            return tempSign.Substring(8);
        }

解签的。同样道理是要AttachedVerify开始到末尾的字节长度。不是字符长度。。这里文档没仔细看。。。。

        /// <summary>
        /// 解签报文
        /// </summary>
        /// <param name="signStr"></param>
        /// <returns></returns>
        public static XmlDocument UnSignMessage(string signStr)
        {
            string temp = "AttachedVerify" + signStr;
            int strLength = Encoding.UTF8.GetByteCount(temp);
            //int strLength = temp.Length;
            string tempSign = BCMSocket.GetData(strLength.ToString().PadLeft(8, '0') + temp);
            tempSign= tempSign.Substring(8);
            StringReader Reader = new StringReader(tempSign);
            XmlDocument xmlDoc = new XmlDocument();

            xmlDoc.Load(Reader);
            return xmlDoc;
        }

顺便附上获得指定标签值的代码。

   private string getXMLInnerText(Dictionary<string, string> xmlNodeDic, string key)
        {
            if (xmlNodeDic.ContainsKey(key))
            {
                return xmlNodeDic[key];
            }

            return "";
        }

   第三点:服务器发送接收代码

就写一段代表性的,注意这里用TCL连接。而且发送和接收都用UTF-8编码。我就是因为没注意导致接收到的中文全是  “?” 号,当时还以为SOCKET出问题了。。。唉

 public class BCMSocket
    {
        public static string GetData(string sendStr)
        {
            string url = "127.0.0.1";   // URL也可以是(http://www.baidu.com/)这种形式
            int port = Convert.ToInt32(GlobalData.TranInfo["signPoint"]);    //端口

            BCMSocketHelper o = new BCMSocketHelper();  //创建新对象
            o.Connection(url, port);                //打开远程端口
            o.Send(sendStr);                     //发送数据
            string rs = o.Recev();

            o.Dispose(); //销毁对象
            return rs;
        }
    }

这是SOCKET的资料:https://www.cnblogs.com/feifeiwzh/articles/1267895.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值