微信小程序 支付 之 完整过程

 

微信小程序支付 官方文档 如下

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

支付的过程如下

1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】

2、商户server调用支付统一下单,api参见公共api【统一下单API】

3、商户server调用再次签名,api参见公共api【再次签名】

4、商户server接收支付通知,api参见公共api【支付结果通知API】

5、商户server查询支付结果,api参见公共api【查询订单API】

å°ç¨åºæ¯ä»æ¶åºå¾

准备工作:

1、在pom.xml 添加 微信支付的sdk

  
    
      com.github.wxpay
      wxpay-sdk
      0.0.3
    

wxpay-sdk 里面已经封装好了 生成签名,map转xml,xml转map 等 工具方法了真的超方便

2.接着创建一个 名为 IWXPayDomain 的接口 主要是 主备域名切换使用 没有必要 可以不改直接用下面的类就行了

public abstract interface IWXPayDomain {
    /**
     * 上报域名网络状况
     * @param domain 域名。 比如:api.mch.weixin.qq.com
     * @param elapsedTimeMillis 耗时
     * @param ex 网络请求中出现的异常。
     *           null表示没有异常
     *           ConnectTimeoutException,表示建立网络连接异常
     *           UnknownHostException, 表示dns解析异常
     */
    abstract void report(final String domain, long elapsedTimeMillis, final Exception ex);

    /**
     * 获取域名
     * @param config 配置
     * @return 域名
     */
    abstract DomainInfo getDomain(final WXPayConfig config);

    static class DomainInfo{
        public String domain;       //域名
        public boolean primaryDomain;     //该域名是否为主域名。例如:api.mch.weixin.qq.com为主域名
        public DomainInfo(String domain, boolean primaryDomain) {
            this.domain = domain;
            this.primaryDomain = primaryDomain;
        }

        @Override
        public String toString() {
            return "DomainInfo{" +
                    "domain='" + domain + '\'' +
                    ", primaryDomain=" + primaryDomain +
                    '}';
        }
    }

}

3.实现 WXPayConfig 这个类

public class WXMCHPayConfig implements WXPayConfig {

    IWXPayDomain getWXPayDomain() {
        return new IWXPayDomain(){
            public void report(String domain, long elapsedTimeMillis, Exception ex) {

            }

            public DomainInfo getDomain(WXPayConfig config) {
                return new IWXPayDomain.DomainInfo("api.mch.weixin.qq.com",true);
            }
        };
    }

    public String getAppID() {
        return "AppID";//填上微信小程序的appid
    }

    public String getMchID() {
        return "MchID";//商户的MchID
    }

    public String getKey() {
        return "";//商户的key  这个是用来做签名的
    }

    public InputStream getCertStream() {
        return null;
    }

    @Override
    public int getHttpConnectTimeoutMs() {
        return 19000;
    }

    @Override
    public int getHttpReadTimeoutMs() {
        return 19000;
    }

}

进入主题:

微信支付的第一步:

1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】

关于这步就不细说了 小程序 登录完 返回 的openid 可以直接用了  相信很多人都懂了

第二步,

2、商户server调用支付统一下单,api参见公共api【统一下单API】

 /*   
     在这里生成工单 取出工单号 
*/

//微信统一下单
Map data = new HashMap<>();
data.put("openid", openid);//用户ID--微信登录返回的openid
data.put("body", body);//商品描述
data.put("out_trade_no", "29a5a115be54410a89c3394aa6b83f55");//32位数的工单号
data.put("total_fee", "1"); //金额 单位: 分--这里一定要用字符串
data.put("spbill_create_ip", Ip);// 用户IP地址
data.put("trade_type", "JSAPI");//支付类型
//异步接收微信支付结果通知的回调地址--不能携带参数 而且外网必须能正常访问 
data.put("notify_url", "http://locahost:8888/monitorNotif");
WXPay wxPay = new WXPay( new WXMCHPayConfig() , MD5 ,false  );//创建 WXPay  实例调用 统一下单接口
Map resultMap = wxPay.unifiedOrder(data);//统一下单接口

 

看着上面的代码你可能会很疑惑 为什么 官网文档中统一下单接口 必须传的 "appid 、mchid 、nonce_str "还有最重要的签名sign 都没有传就可以下单了。

其实 你跟着 unifiedOrder 这个方法debug 下去 你会发现 WXPay 这个工具类 都自动帮你添加了appid 、mchid、 nonce_str 还有生成sign签名。

一路debug下去 找到 一下方法 fillRequestData 这里可以看到 剩下的信息都添加了

签名 sign 如WXPayUtil.generateSignature(reqData, this.config.getKey(), this.signType) 生成

public Map fillRequestData(Map reqData) throws Exception {
        reqData.put("appid", this.config.getAppID());
        reqData.put("mch_id", this.config.getMchID());
        reqData.put("nonce_str", WXPayUtil.generateNonceStr());
        if (SignType.MD5.equals(this.signType)) {
            reqData.put("sign_type", "MD5");
        } else if (SignType.HMACSHA256.equals(this.signType)) {
            reqData.put("sign_type", "HMAC-SHA256");
        }

        reqData.put("sign", WXPayUtil.generateSignature(reqData, this.config.getKey(), this.signType));
        return reqData;
    }

第三步

统一下单成功后将会返回一个 prepay_id 用于 再次签名

        Map res = new HashMap<>();
        res.put("package", "prepay_id="+prepay_id);
        res.put("signType", "MD5");
        res.put("nonceStr", WXPayUtil.generateNonceStr());//获取32位随机字符串
        res.put("appId", AppID);//小程序的appid
        res.put("timeStamp", System.currentTimeMillis() / 1000 +"");//到秒的时间戳

        String paySign = WXPayUtil.generateSignature(res,WXMCHPayConfig.Key);//获取签名

        res.put("paySign", paySign); //签名

将 集合 res 回传到小程序端

小程序调用 以下接口 调起支付页面

wx.requestPayment(
{

'appId':'',
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){},
'fail':function(res){},
'complete':function(res){}
})

 

开发工具 看到的是二维码支付页面

微信小程序 支付 之 完整过程_第1张图片

当支付成功时 微信就会根据 统一下单时传的 通知接口("notify_url", "http://locahost:8888/monitorNotif")返回 支付账单相关信息。

第四步,微信支付通知处理

4、商户server接收支付通知,api参见公共api【支付结果通知API】

 //监听 微信支付通知
    @RequestMapping("/monitorNotify")
    @ResponseBody
    public String monitorNotify(HttpServletRequest request, HttpServletResponse response ) throws Exception{
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        String result = new String(outSteam.toByteArray(), "utf-8");
        System.out.println(result);//获取到支付结果 xml
        /* 以下来自官网的例子
        
          
          
          
          
          
          
          
          
          
          
          
          
          
          1
        
        
        
        
        
          
          
        
        */
        // 将 xml转换为map 方便操作数据
        Map resultMap = WXPayUtil.xmlToMap(result);
        //通过支付结果里面的数据生成签名 对比 支付结果中的签名是否一致
        String signTest = WXPayUtil.generateSignature(resultMap, WXMCHPayConfig.Key);//生成签名

        // 签名验证
        if(!signTest.equals(resultMap.get("sign"))){
            Map res = new HashMap<>();
            res.put("return_code","FAIL"); //SUCCESS/FAIL  SUCCESS表示商户接收通知成功并校验成功
            res.put("return_msg","签名失败");
            String resStr = WXPayUtil.mapToXml(res); //以xml 的形式告知微信
            return resStr;
        }
        /*假如签名验证成功  最好对比一下 金额是否一样 是否重复 接收通知 验证*/

        验证成功 ,就修改工单状态 生成支付流水 等等操作
        // 以上验证用过后 应答微信通知
        Map resXml = new HashMap<>();
        resXml.put("return_code","SUCCESS"); //SUCCESS/FAIL  SUCCESS表示商户接收通知成功并校验成功
        resXml.put("return_msg","OK");
        String resStr = WXPayUtil.mapToXml(resXml);
        return resStr;

}

第五步:查询订单

5、商户server查询支付结果,api参见公共api【查询订单API】

/*
    * 查询订单
    * */
    @GetMapping("/selectOrder")
    @ResponseBody
    public Result selectOrder(String orderid) throws Exception {

        WXPay wxPay = new WXPay( new WXMCHPayConfig() , MD5 ,false  );

        Map data = new HashMap<>();
        data.put("out_trade_no", orderid);//生成的工单ID
        Map res = wxPay.orderQuery(data);//微信查询订单接口
       
        return res ;
    }

其实在第四步 处理的通知的时候可以 通过查询订单的状态    验证该工单是否支付成功  

 

好了  到这里结束。。。。

你可能感兴趣的:(小程序支付)