微信公众号JSAPI支付详细开发过程

简介:这几天公司有个活动需要用到微信公众号支付,最后成功了完成支付。但第一次使用微信的支付中间遇到一些问题方便以后参考,下面总结整个调用的过程。

  • 开发环境:java
  • 开发系统:win10
  • 开发工具:idea2018
  • 2018-11-26

在开发之前我们要准备以下资料:

  • 开发者ID(AppID) 这个资料在微信公众号开发配置里查看
  • (AppSecret) 这个资料在微信公众号开发配置里查看
  • 接口权限网页服务 网页白名单(这个地方要备案域名)
    支付界面设置这里要开通 JSAPI支付 -https://pay.weixin.qq.com
    产品中心
    -配置好授权的支付页面(此处主要是支付的回调和页面授权)

下面是操作环节和代码code核心部分

  1. 统一下单
    接口地址 URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
  • 下面是请求的参数
    公众账号ID appid 是 String(32) wxd678efh567hg6787 微信支付分配的公众账号ID(企业号corpid即为此appId)
    官方地址 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
字段名 变量名 必填 类型 描述
公众账号ID appid String(21) 这里就是你公众号appid
商户号 mch_id String(32) 这个是支付商户号
随机字符串 nonce_str String(32) 这可以用自带的例子里面生成
签名 sign String(32) 详见签名生成算法
商品描述 body String(128) 这是简单的描述支持中文
商户订单号 out_trade_no String(32) 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-* 且在同一个商户号下唯一
标价金额 total_fee Int 订单总金额,单位为分
终端IP spbill_create_ip String(16) 提交的IP123.12.12.123
通知地址 notify_url String(256) http://www.weixin.qq.com/wxpay/pay.php这个后面通知用的
交易类型 trade_type String(16) JSAPI JSAPI支付 NATIVE Native支付 APP APP支付https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2

以上参数是必填项目
从上面的格式我们看到很多东西都是自己定义的,唯一的一个东西就是 签名
设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
也就是说 上面你要发送的这些信息都要拼接成一个字符串
比如你要发送这些

mch_id: 10000100 
device_info: 1000 
body: test 
nonce_str: ibuaiVcKdpRxkhJA 

最后拼接后的格式是

string A="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA"; 

按照参数名ASCII码从小到大排序(字典序) 使用下面的函数拼接比较方便

    public static String formatUrlMap(Map paramsMap, boolean urlEncode, boolean keyToLower) {

        String buff = "";
        Map tmpMap = paramsMap;

        try {
            List> infoIds = new ArrayList>(tmpMap.entrySet());

            //对所有传入参数按照字段名的ASCII码从小到大排序(字典序)
            Collections.sort(infoIds, new Comparator>() {
                public int compare(Map.Entry o1, Map.Entry o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });

            //构造URL 键值对的格式
            StringBuffer buf = new StringBuffer();
            for (Map.Entry item : infoIds) {
                if (StringUtils.isNotBlank(item.getKey())) {
                    String key = item.getKey();
                    String value = item.getValue();
                    if (urlEncode) {
                        value = URLEncoder.encode(value, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "=" + value);
                    } else {
                        buf.append(key + "=" + value);
                    }
                    buf.append("&");
                }
            }
            buff = buf.toString();

            if (StringUtils.isNotEmpty(buff)) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        return buff;
    }

第二步 key 在商户注册里面设置 https://pay.weixin.qq.com

stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d" //注:key为商户平台设置的密钥key 

第三步:拼接API密钥: 有二个方式 我用的是md5

string SignTemp=A+"&key=192006250b4c09247ec02edce69f6a2d" //注:key为商户平台设置的密钥key 

sign=MD5(SignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5签名方式

sign=hash_hmac("sha256",SignTemp,key).toUpperCase()="6A9AE1657590FD6257D693A078E1C3E4BB6BA4DC30B23E0EE2496E54170DACD6" //注:HMAC-SHA256签名方式

这里注意都要转成大写

到这里第一大步骤就完成了。可以post数据了,如果post成功会得到类似下面的数据


这里最主要的是 prepay_id=wx26125**********b3701824863 这样的一个类型
然后二次签名
参数需要重新进行签名计算,参与签名的参数为:appId、timeStamp、nonceStr、package、signType,参数区分大小写
下面是我的二次签名代码

Map paraMap = new HashMap();
paraMap.put("appId",wappId);
paraMap.put("timeStamp", timeStamp);
paraMap.put("nonceStr", nonceStr);
paraMap.put("package",spackage);
paraMap.put("signType",signType);
String SinSring = StringUtil.formatUrlMap(paraMap,false,false);//按照参数名ASCII码从小到大排序(字典序)

String paySign= WXPayUtil.MD5((SinSring+"&key="+key));
paraMap.put("paySign",paySign);

Map mapky = new HashMap<>();
mapky.put("appId", wappId);
mapky.put("timeStamp", timeStamp);
mapky.put("nonceStr", nonceStr);
mapky.put("package", spackage);
mapky.put("signType", signType);
mapky.put("paySign",paySign);

将二次签名的信息发送到客户端
这个是官方给的唤醒 支付界面
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
注:JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回。由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分。
示例代码如下:


function onBridgeReady(){
   WeixinJSBridge.invoke(
      'getBrandWCPayRequest', {
         "appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     
         "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     
         "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     
         "package":"prepay_id=u802345jgfjsdfgsdg888",     
         "signType":"MD5",         //微信签名方式:     
         "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
      },
      function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
      } 
   }); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener ){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}

最后支付完成你会收到一个 微信支付的 支付结果通知
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

就是上面 统一下单 那个地址会得到一个通知成功的信息,只要返回 下面格式的代码就可以了



以上是腾讯的微信支付过程

你可能感兴趣的:(微信公众号JSAPI支付详细开发过程)