现在的网页支付(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. [公测]微信小程序设计指南文档
  2. [众包]Eclipse 运行简单亚马逊AMT模板
  3. mac 编译android系统,mac 编译 Android 系统杂记
  4. 【数据湖加速篇】 —— 如何利用缓存加速服务来提升数据湖上机器学习训练速度
  5. 谈谈双亲委派模型的第四次破坏-模块化
  6. Can't locate ExtUtils/MakeMaker.pm
  7. mysql 游戏背包_用sql实现背包问题
  8. MySQL之MHA架构的介绍
  9. 读《产品经理的第一本书》有感
  10. Stata:产生唯一数据编码的三种方法
  11. Shopee菲律宾站如何选品?听Shopee Man本土多店管理系统告诉你
  12. Excel如何从一组数据中随机抽取若干个数据
  13. 戴尔电脑vostro恢复出厂(预装Win10)的设置方法
  14. 【MTK Sensor2.0】SCP与AP数据流分析
  15. 洛谷P1957口算练习题
  16. mono java 性能_Mono对Java的支持
  17. mac 升级自带Python方法
  18. 清华刘知远团队巨作!Pre-trained Prompt Tuning框架,让超大模型调参变简单
  19. 对求一个数的各个位数的理解
  20. Excel2010重复打印标题行

热门文章

  1. Java core 基础概念
  2. 高中同学相识二十年聚会
  3. 【Java面试题】MVC是什么?MVC设计模式的好处有哪些?
  4. 39、count_rpkm_fpkm_TPM
  5. HarmonyOS 2.0 手机版使用初体验 ——手机开发者 (Beta版)
  6. php中getenv函数,PHP函数getenv简介和使用实例
  7. 关于VO,BO,PO,DO,DTO的简单理解
  8. 4、fluentd之配置文件的格式
  9. 幽默:老公和老婆斗智
  10. “十四五”城市交通基础设施发展方向及重点分析