WeChat mini program Webview handles payment issues

 Handling Webview payment issues

The webview in the WeChat mini program can do many things, but there are still many limitations. For example, the regular payment interface of the mini program cannot be used in the webview. But we can use webview to jump to the internal page of the mini program with parameters, obtain these parameters on the internal page of the mini program, and initiate payment.
Here we integrate information from the Internet to talk about this process.

Front-end steps:


  ①: After clicking the payment button, request the java background and obtain the necessary parameters 'timeStamp', 'package', 'paySign', 'signType', 'nonceStr' to hang up the mini program ②: Jump to a certain point in the mini program with
  parameters Page
  ③: Directly parse the parameters when loading the mini program page, and raise the payment interface: wx.requestPayment
  ④: Process the payment result, jump back to webview or other pages
  


Front-end code display:

1. webview (inside html)

 <button id="buttom8xx">购买一年会员</button>
    <script type="text/javascript">
        $("#buttom8xx").click(function() {
            $.ajax({
                type : 'Get',
                url : "http://192.168.0.15:8080/carplatform/User/BecomeVip",
                dataType : 'json',
                contentType : "application/json;charset=UTF-8",
                success : function(data) {
                    if(data.state)
                    {
                      alert(data.payinform.package);
                      var pid=(data.payinform.package).split('=')[1];  //跳转到小程序时这个参数有等号,小程序只能获取到‘=’前面的字符,这里我们发送=后面字符,小程序里面自行拼凑
                                                                       //注意这个地方是有坑的,小程序在跳转传参时如果某一个参数key对应的内容形如“xxx=yyy”这中格式,                                                                     
                                                                       //我们在小程序页面解析参数时实际是只能获取到‘=’前面一部分,也就是‘xxx’
                var params = '?timeStamp='+data.payinform.timeStamp
                +'&package='+pid
                    +'&paySign='+data.payinform.paySign
                    +'&signType='+data.payinform.signType
                    +'&nonceStr='+data.payinform.nonceStr;
                var payurl='/pages/wxpay/wxpay'+params;
                //小程序跳转到指定的小程序页面.跳转不需要加载jssdk配置
                                 alert(payurl);
                wx.miniProgram.navigateTo({url: payurl}); //带参跳转到小程序内部页面
                 console.log(data);
                }
                else
                {
                                  alert(data.message);
                }
                }
            });
        });
    </script>

 wxpay.js in the payment page of the mini program:

/**
   * 页面加载,获取支付参数直接吊起支付
   */
  onLoad: function (options) {
    var that = this;
    //页面加载调取微信支付(原则上应该对options的携带的参数进行签名计算,校验)
    var param = {
      "timeStamp": options.timeStamp,
      "package": 'prepay_id=' +options.package,//组装下参数
      "paySign": options.paySign,
      "signType": "MD5",
      "nonceStr": options.nonceStr
    }
    console.log(param);
    that.pay(param)//吊起支付
  },

 /**
 *  调起支付函数
 */
  pay: function (param) {
    wx.requestPayment({
      timeStamp: param.timeStamp,//时间搓
      nonceStr: param.nonceStr,//随机码
      package: param.package,//统一下单接口返回的  prepay_id
      signType: param.signType,//签名算法MD5
      paySign: param.paySign,//签名字符串
      success: function (res) {
        // success
        console.log(res)
        wx.navigateBack({
          delta: 1, // 回退前 delta(默认为1) 页面
          success: function (res) {
            wx.showToast({
              title: '支付成功',
              icon: 'success',
              duration: 2000
            })
          },
          fail: function (res) {
            // fail
            console.log(res)
          },
          complete: function (res) {
            // complete
            console.log(res)
          }
        })
      },
      fail: function (res) {
        // fail
        console.log("支付失败");
        console.log(res)
      },
      complete: function (res) {
        // complete
        console.log("pay complete");
        console.log(res)
      }
    })
  },

Background logic:

 ①: Calculate the payment parameters, call the unified ordering interface of the WeChat applet in the background, obtain the payment parameter prepay_id=xxx, and then calculate the parameters required to lift the payment interface of the applet. There is nothing to say about this. Just write it according to the wx interface ②
 : Callback handling.
  This is my understanding: I am relatively sensitive to things involving money. After receiving the WeChat callback, we should not make database changes or account changes directly based on its status. Here we need to verify it multiple times. If we compare it multiple times, the other party can think that the other party has really paid. To ensure the safety of your funds, you might as well sacrifice some backend performance! ! ! So after receiving the callback, I took the following steps
  : 1°: To prevent the callbacks from being too concentrated and causing data confusion, I used a lock to determine whether a callback has been processed. If it has not been processed, no other callbacks will come in (of course this is obvious at a glance) There are defects. Specifically, a queue should be established for processing).
  2°: Callback parameter signature verification
  3°: Determine whether various methods are successful in callback parameters.
  4°: After all the status and payment status in the parameters are successful, check whether the order status in our database has been paid (mainly to prevent us from returning to WeChat 'SUCCESS' if he did not receive it or something, causing WeChat to continue to repeat notifications ).
  5°: We get the WeChat order number in the parameter and call the WeChat order query interface. Check to see if the order return has actually been paid.
  6°: Modify the database and modify session storage. (The session modification here is through the 'attach' field of the merchant data packet passed by the user's sessionid when the user places an order. The sessionid is obtained during the callback, and the corresponding user session modification content is found in our listening class.)

    Java background payment callback code:

 // 成为会员,用户支付回调!
    @ResponseBody
    @RequestMapping(value = "User/wx/bvipback")
    public String Userwxbvipback(@RequestBody String request, HttpSession session) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, Exception {
        Map<String,String> result = new HashMap<>();
        
        if(!vip_paybackend)//一次还未处理完,收到其它回调,直接返回
        {
            result.put("return_code", "FAIL");
            return user_wxAPI.GetInstance().mapToXml(result);
        }
        else
        {
            vip_paybackend=false; //设置为正在处理,不予许其它回调进入
        }
        
        if(!user_wxAPI.GetInstance().CheckReturn(request))//验证签名是否一致,签名不一致直接返回
        {
            result.put("return_code", "FAIL");
            vip_paybackend=true;//可以接收下一次数据回调
            return user_wxAPI.GetInstance().mapToXml(result);
        }
        else
        {
            Map<String, String> data = user_wxAPI.GetInstance().xmlToMap(request);//转成map
            if (data.get("return_code").equals("FAIL"))//通讯为失败,直接返回
            {
                result.put("return_code", "FAIL");
                vip_paybackend=true;//可以接收下一次数据回调
                return user_wxAPI.GetInstance().mapToXml(result);
            }
            if (data.get("result_code").equals("FAIL"))//业务结果为失败,支付失败直接返回
            {
                result.put("return_code", "FAIL");
                vip_paybackend=true;//可以接收下一次数据回调
                return user_wxAPI.GetInstance().mapToXml(result);
            }
            if(data.get("result_code").equals("SUCCESS"))//业务结果成功,我们再次查询订单状态,在决定是否写入数据库
            {
                String transaction_id=data.get("transaction_id"); //得到这个微信订单号
                String out_trade_no=data.get("out_trade_no"); //得到这个商户订单号
                wxorder onewxorder=ordersdao.GetWXOrder(out_trade_no);//查询微信我们数据库订单状态
                if(!data.get("total_fee").equals(String.valueOf(onewxorder.wxorder_money)))//如果订单金额不匹配
                {
                    result.put("return_code", "FAIL");
                    vip_paybackend=true;//可以接收下一次数据回调
                    return user_wxAPI.GetInstance().mapToXml(result);
                }
                
                if(!onewxorder.wxorder_state.equals(1)) //如果不是未支付状态我们就返回
                {
                    result.put("return_code", "SUCCESS");
                    vip_paybackend=true;//可以接收下一次数据回调
                    return user_wxAPI.GetInstance().mapToXml(result);//告诉微信服务器,我已经处理过数据
                }
                
                Map<String, String> wxorder_infom=user_wxAPI.GetInstance().OrderQuery(transaction_id);//用微信订单号,订单查询
                if(wxorder_infom.get("return_code").equals("FAIL"))//查询订单失败了
                {
                    result.put("return_code", "FAIL");
                    vip_paybackend=true;//可以接收下一次数据回调
                    return user_wxAPI.GetInstance().mapToXml(result);
                }
                if(wxorder_infom.get("return_code").equals("SUCCESS")
                   &&wxorder_infom.get("result_code").equals("SUCCESS")
                   &&wxorder_infom.get("trade_state").equals("SUCCESS"))//查询订单返回三个success作为,支付成功的判断
                {
                    String session_id=wxorder_infom.get("attach");//商家数据包中获取用户sessionid
                    HttpSession usersession=MyHttpsessions.GetSession(session_id);
                    //修改微信订单状态,添加或者修改用户的会员时间,包括user自身
                    if(onewxorder.wxorder_state.equals(1))//如果是未支付状态,我们才进行数据库处理
                    {
                        onewxorder.wxorder_state=2;//状态改为已支付
                        onewxorder.wxorder_wxnum=transaction_id;//添加微信订单号
                        ordersdao.UpdateOneWxOrder_State(onewxorder);//跟新为已支付
                        Date user_endtime=ordersdao.saveviporder(onewxorder.wxorder_userid);//插入、跟新vip订单表
                        Userdao.UpdateUserEndtime(user_endtime, onewxorder.wxorder_userid);//跟新用户endtime
                        
                        //修改用户ession状态
                        User user=new User();
                        if(usersession!=null) user=(User) usersession.getAttribute("user");
                        user.setUser_bvip(1);//是vip
                        user.setUser_endtime(df.format(user_endtime));
                        usersession.setAttribute("user", user);
                        
                        result.put("return_code", "SUCCESS");
                        vip_paybackend=true;//可以接收下一次数据回调
                        return user_wxAPI.GetInstance().mapToXml(result);//告诉微信服务器,已经处理好数据
                    }
                }
                else 
                {
                    result.put("return_code", "FAIL");
                    vip_paybackend=true;//可以接收下一次数据回调
                    return user_wxAPI.GetInstance().mapToXml(result);
                }
            }
        }
        result.put("return_code", "FAIL");
        vip_paybackend=true;//可以接收下一次数据回调
        return user_wxAPI.GetInstance().mapToXml(result);
    }

 


 

Guess you like

Origin blog.csdn.net/qq_22824481/article/details/82258595