现在的网页支付(PC和微信H5)和app支付,用的比较多的是微信支付、银联支付和支付宝支付,其余的是这些支付的第三方支付,我目前了解的只有这么多。我目前做了银联支付和微信支付,这里说一些银联支付的开发的一些介绍吧。

根据我们公司的应用经验,银联支付时费率最低的,如果和银联商务谈判的好,自身的交易量比较大,费率可能更低(具体不能透露了)。银联支付一种是按百分比收取手续费,另一种按笔数收取手续费,例如,每笔0.9元。我们公司用了2种银联支付,一开始用的是银联支付,后来因费率问题,使用银联支付第三方平台--千引支付,实质上也是银联支付。

我们申请的银联支付,在网上营业厅、微信服务号、Android和iOS平台都在使用,是“手机WAP支付产品”。主要用了2个接口,第一个是“消费类交易”,即银联支付申请接口。它也可以分为两部分,(1)通过拼接报文,签名加密,生成html网页,浏览器跳转请求到银联支付页面。此时,订单生成,用户可以在银联页面完成支付。(2)支付成功后,银联会根据请求参数里的配置,主动回调前台、后台通知地址,通知用户支付成功。第二个接口是“交易状态查询交易”,即查询订单交易结果。

现在具体讲一下代码:

消费类交易接口:官方文档地址:https://open.unionpay.com/ajweb/help/api

(1)交易申请。初始化证书,拼接报文,数据签名,创建表单或取得tn号。调用此接口,微信、网厅可得到一个html的https post表单,浏览器执行js自动提交,访问银联支付申请接口,跳转银联支付页面。此时,服务端只是拼接报文,签名加密,请求的动作,是用户的浏览器做的,可以保证银联支付的安全性。app端则是,调用接口,取得tn号,调用app已安装的银联控件跳往银联支付页面。

private String pc2UnionPay(String orderId, String incMoney,
            String txnTime) {
        /**
         * 初始化证书
         */
        SDKConfig.getConfig().loadPropertiesFromSrc();// 从classpath加载acp_sdk.properties文件

/**
         * 交易请求url 从配置文件读取
         */
        String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();

/**
         * 组装请求报文
         */
        Map<String, String> data = new HashMap<String, String>();
        // 版本号
        data.put("version", "5.0.0");
        // 字符集编码 默认"UTF-8"
        String encoding = "UTF-8";
        data.put("encoding", encoding);
        // 签名方法 01 RSA
        data.put("signMethod", "01");
        // 交易类型 01-消费
        data.put("txnType", "01");
        // 交易子类型 01:自助消费 02:订购 03:分期付款
        data.put("txnSubType", "01");
        // 业务类型 000201 B2C网关支付
        data.put("bizType", "000201");
        // 渠道类型 07-互联网渠道
        data.put("channelType", "07");
        // 商户/收单前台接收地址 选送
        // 后台服务对应的写法参照 FrontRcvResponse.java
        data.put("frontUrl", frontUrl);
        // 商户/收单后台接收地址 必送
        // 后台服务对应的写法参照 BackRcvResponse.java
        data.put("backUrl", backUrl);
        // 接入类型:商户接入填0 0- 商户 , 1: 收单, 2:平台商户
        data.put("accessType", "0");
        // 商户号码
        data.put("merId", merId);
        // 订单号 商户根据自己规则定义生成,每订单日期内不重复
        data.put("orderId", orderId);
        // 订单发送时间 格式: YYYYMMDDhhmmss 商户发送交易时间,根据自己系统或平台生成
        data.put("txnTime", txnTime);

// 交易金额 分
        data.put("txnAmt", incMoney);
        // 交易币种
        data.put("currencyCode", "156");

// 若报文中的数据元标识的key对应的value为空,不上送该报文域

/**
         * 创建表单
         */
        String html = null;
        for (int i = 1; i <= 3; i++) {
            html = createHtml(requestFrontUrl, signData(data));
            if (html != null) {
                return html;
            }
        }
        return "服务器忙";
    }

public static String createHtml(String action, Map<String, String> hiddens) {
        StringBuffer sf = new StringBuffer();
        sf.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head><body>");
        sf.append("<form id = \"pay_form\" action=\"" + action
                + "\" method=\"post\">");
        if (null != hiddens && 0 != hiddens.size()) {
            Set<Entry<String, String>> set = hiddens.entrySet();
            Iterator<Entry<String, String>> it = set.iterator();
            while (it.hasNext()) {
                Entry<String, String> ey = it.next();
                String key = ey.getKey();
                String value = ey.getValue();
                sf.append("<input type=\"hidden\" name=\"" + key + "\" id=\""
                        + key + "\" value=\"" + value + "\"/>");
            }
        }
        sf.append("</form>");
        sf.append("</body>");
        sf.append("<script type=\"text/javascript\">");
        sf.append("document.all.pay_form.submit();");
        sf.append("</script>");
        sf.append("</html>");
        return sf.toString();
    }

(2)支付成功通知商户。根据申请时取得的前后台通知地址,银联在支付成功后,会主动通知商户交易结果,但应以后台通知为准。前台应答是通过 浏览器,用户点击“返回商户”按钮发送给商户的,后台通知是银联系统异步把交易状态为成功的交易通知给商户,失败交易不发送。前台应答及后台通知,商户都需要验签。

public class BackNoticeServlet extends HttpServlet {
    private static final long serialVersionUID = -900467945307979675L;
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            LogUtil.writeLog("后台接收银行通知开始……");
            BankService bService = (BankService) PayCache.getInstance().getBean("bankService");
            RechargeService service =  (RechargeService)PayCache.getInstance().getBean("rechargeService");
//            request.setCharacterEncoding("ISO-8859-1");
            String encoding = request.getParameter(SDKConstants.param_encoding);
            // 获取请求参数中所有的信息
            Map<String, String> reqParam = getAllRequestParam(request);
            // 打印请求报文
            LogUtil.printRequestLog(reqParam);

Map<String, String> valideData = null;
            if (null != reqParam && !reqParam.isEmpty()) {
                Iterator<Entry<String, String>> it = reqParam.entrySet()
                        .iterator();
                valideData = new HashMap<String, String>(reqParam.size());
                while (it.hasNext()) {
                    Entry<String, String> e = it.next();
                    String key = (String) e.getKey();
                    String value = (String) e.getValue();
                    value = new String(value.getBytes("ISO-8859-1"), encoding);
                    valideData.put(key, value);
                }
                Map<String, String> res = new HashMap<String, String>();
                // 验证签名
                if (!SDKUtil.validate(valideData, encoding)) {
                    LogUtil.writeLog("验证签名结果[失败].");
                } else {
                    LogUtil.writeLog("验证签名结果[成功].");
                    // 持久化银行返回的数据
                    LogUtil.writeLog("持久化银行返回的数据");
                    String settleDate = reqParam.get("settleDate");
                    Calendar cal=Calendar.getInstance();
                    settleDate = String.valueOf(cal.get(Calendar.YEAR)) + settleDate;//加上年份
                    reqParam.put("settleDate", settleDate);
                    service.addPayresult(reqParam);
                    if("00".equals(reqParam.get("respCode"))){
                        service.updOrder(reqParam.get("orderId"),settleDate);
                    }
                    LogUtil.writeLog("返回银行数据给商户开始……");
                    res.put("respCode", reqParam.get("respCode"));
                    res.put("respMsg", reqParam.get("respMsg"));
                    res.put("orderId", reqParam.get("orderId"));
                    res.put("txnTime", reqParam.get("txnTime"));
                    res.put("txnAmt", reqParam.get("txnAmt"));
                    res.put("queryId", reqParam.get("queryId"));
                    res.put("settleDate", reqParam.get("settleDate"));
                    res.put("settleAmt", reqParam.get("settleAmt"));
                    res.put("txnType", reqParam.get("txnType"));
                    String statusCode = "";
                    ProfitApplyOrder order = bService.queryOrder(reqParam.get("orderId"));
                    for(int i=0;i<5;i++){
                        statusCode = XmlUtil.invokeMethod(res,order.getBackUrl());
                        if(statusCode.equals("success")){
                            LogUtil.writeLog("返回银行数据给商户结束[成功].");
                            break;
                        }
                    }
                    LogUtil.writeLog("银行数据接受完成!");
                }
            }

} catch (Exception e) {
            e.printStackTrace();
            LogUtil.writeLog("接受银行数据失败:" + e.getMessage());
        } finally {
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            PrintWriter writer = response.getWriter();
            writer.print(System.currentTimeMillis());
            writer.flush();
        }
    }
    
    public static Map<String, String> getAllRequestParam(
            final HttpServletRequest request) {
        Map<String, String> res = new HashMap<String, String>();
        Enumeration<?> temp = request.getParameterNames();
        if (null != temp) {
            while (temp.hasMoreElements()) {
                String en = (String) temp.nextElement();
                String value = request.getParameter(en);
                res.put(en, value);
                // 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
                // System.out.println(" temp数据的键=="+en+"     值==="+value);
                if (null == res.get(en) || "".equals(res.get(en))) {
                    res.remove(en);
                }
            }
        }
        return res;
    }
}

交易状态查询交易:(以下摘自银联官方文档)

商户收到后台通知后,应根据通知报文中订单号等关键信息,更新系统中的订单支付状态。
商户在以下情况下,可主动发起交易状态查询,并根据查询结果更新交易状态。
(1)前台交易,在5分钟内未收到后台通知。
(2)后台交易,在1秒内未收到后台通知 。
(3)商户在特殊情况下没有正确处理后台通知,需要重新判定交易状态。
商户应注意对同一笔交易,对不同时间点可能先后收到的查询结果及后台通知进行合适的处理。

以上,此接口调用查询订单交易结果,是商户主动发起的,没什么好说的,把官方文档贴了一下。附上交易应答码地址:https://open.unionpay.com/ajweb/help?id=262

银联支付开发、使用的一些总结相关推荐

  1. 西米支付:支付宝/微信支付/银联支付通道的接入介绍

    本文以电脑网站支付为例,着重对第三方支付通道的接入进行了分析,包括支付宝支付接入.微信支付接入及银联支付接入. 1.支付宝支付接入 支付宝支付能力主要有当面付.刷脸付.App支付.手机网站支付.电脑网 ...

  2. H5APP WEB 支付开发 (银联 微信 支付宝)流程

    这里采用ionic+angular进行前台开发 ssh+jpay做后台支付接口 银联:配置好参数 接口采用JPAY 他会自动生成HTML并提交表单到银联 app只需用iframe套用就行 paylog ...

  3. php银联支付接口 demo,php版银联支付接口开发简单实例详解

    这篇文章主要介绍了php版银联支付接口开发的方法,结合实例形式分析了php银联支付接口开发的具体流程与相关操作技巧,需要的朋友可以参考下 支付接口现在有第三方的支付接口也有银行的支付接口.这里就来介绍 ...

  4. iOS开发 支付之银联支付集成

    iOS开发之银联支付集成 最近在做支付这一块的东西,就记录下来以便以后参考和各位交流学习,这里是银联支付 银联官网在这里,这里能下载SDK或者是看文档.文档嘛,对银联来说,还是不要看的太仔细的好,以前 ...

  5. Android开发之——银联支付深入

    前言 上一遍讲解了银联支付的入门和演示,这篇文章继续介绍银联支付中的一些关键点解析和注意事项,希望对在银联开发接入的你有所帮助. 银联支付接入流程 第一步:申请入网 入网即签约,分银联官网注册和服务商 ...

  6. Android开发:app工程集成银联支付功能(服务器端)

    一功能描述 二实现过程 1下载银联支付SDK和Demo 1银联商家服务地址httpsopenunionpaycomajwebindex 2下载的文件如下 2集成过程 1先试官方Demo 2集成到自己的 ...

  7. Android开发:app工程集成银联支付功能(客户端)

    Android开发:app工程集成银联支付功能(客户端) email:chentravelling@163.com 上一篇博文完成了服务器端的集成,可参考: Android开发:app工程集成银联支付 ...

  8. 玩转iOS开发:集成 Union Pay - 银联支付

    文章转至:https://cainrun.github.io/14740149724404.html 作者感言 前面已经把WeChat SDK的支付, AliPay SDK搞得七七八八了, 接下来就是 ...

  9. Android开发之——银联支付初探

    前言 现在网上支付用的比较多的是微信支付,支付宝支付和银联支付.关于微信和支付宝支付前面已经讲过了,本文主要介绍关于银联支付集成的过程和步骤. 银联支付 资源查找 集成文档 点击上面的集成文档,打开如 ...

最新文章

  1. 清华大学计算机李雪,李雪 | 北京外国语大学国际商学院|International Business School,BFSU|本硕博,北外留学,来华留学Solbridge,EDP...
  2. php处理二进制,PHP应用:PHP处理二进制数据的实现方法
  3. android百度地图覆盖物异步加载图片,Android 百度地图marker中图片不显示的解决方法(推荐)...
  4. python----面向对象:1类的定义
  5. 解决QT5中文显示出现乱码
  6. 滑动窗口解决最小子串问题 leetcode3. Longest Substring Without Repeating Characters
  7. No qualifying bean of type;Unsatisfied dependency expressed through field 解决办法(总结全网)
  8. 韦东山freeRTOS系列教程之【第五章】队列(queue)
  9. 黑苹果卡在苹果logo_黑苹果的历史
  10. 使程序在后台运行,后台进程实现原理
  11. 平房误差函数_平方误差函数(square error function)与平方损失函数(square loss function)...
  12. MATLAB与信号处理课程手册
  13. 【Windows11+Ubuntu20.04】双系统安装及美化、优化记录
  14. 【电路设计小白】ADC芯片配置学习之一初期理论
  15. IDE 的主题应该用亮色还是暗色?终极答案来了!
  16. 操作教程:大华摄像头通过GB28181协议注册EasyCVR平台的详细配置
  17. Python爬虫爬取智联招聘(进阶版)
  18. JVM笔记:Java虚拟机的字节码指令详解
  19. go module无法下载golang.org/x
  20. 安卓小项目之EveryDay(6)----使用第三方平台获取短信验证码

热门文章

  1. 5e怎么绑定一键跳投_苹果cms怎么使用?
  2. 读书笔记//《数据分析:企业的贤内助》
  3. 相空间重构matlab代码
  4. 15、历史上的今天API接口,免费好用
  5. GDL学习笔记(一)——概要+图基本知识
  6. 接口和协议组成 游戏测试中的接口测试总结
  7. 设计模式(20)解释器模式
  8. linux zcat 使用方法,使用linux的zcat命令查看压缩文件的内容
  9. 公众号 接收手机验证码发送给用户
  10. 肉丝姐js逆向课程保姆级笔记