小程序开发——微信支付篇

小程序开发中常常会用到微信支付。微信支付里面的坑谁做谁知道。

先来个官方贴图谈一下支付的流程

对,支付是个异步的过程。

收集到用户的openid,支付金额,ip地址之后,我们生成随机串nonce_str和时间戳、订单号。当然商户号、商户秘钥、小程序的APPID、通知地址这些也是提前存好的。然后用这些信息按字典排序,它要求的是键值对,也就是key=value&  这样来拼接(具体的下面说)。拼接完成后尾处加上商户秘钥。最后用md5加密,提交到微信服务器生成预付单。拿到预付单之后我们传给小程序,小程序中用预付单的参数调起微信支付。然后支付结果通过我们前面传递的通知地址来通知我们(就是普通post请求传给你一个xml)。收到回调的xml后,我们去验证sign,如果验证通过则返回一个回馈给微信服务器(不然它还会持续发给你),然后我们执行支付成功的业务操作。

那我们现在从代码的角度来走一遍支付流程。

首先我们应该已知以下参数:appid(小程序appid)、mch_id(商户号)、key(商户秘钥)、trade_type(交易类型,JSAPI)、notify_url(支付回调地址,也就是通知我们的请求地址)

然后前端的提交一些信息,我们算出支付金额,获取支付用户的openid、支付用户客户端的IP地址、商品名称(其实可以固定写测试商品)。然后我们生成订单号,随机串和时间戳在后面生成。一个简单的controller如下:

/**
 * 请求支付接口,当然参数不可能这么简单,其他业务参数我们就省去了
 * @param openid   支付用户的openid
 * @param request  用来获取支付用户的IP地址
 *
 * @return  预付单的信息  ,你也可以用其他类来进行封装,这里我直接用Map传回给前端了
 */
@RequestMapping("pay")
public Map insert(String openid,HttpServletRequest request) {
   //我们假装计算出了支付金额,记住不能支付0元
   //如果你不想用BigDecimal ,用其他也行。但是记住,最后提交的时候是以分为单位的
   BigDecimal money = new BigDecimal(20);
   //生成一个订单号,生成策略自己决定
   String id = "123456";
   //准备一个回调地址,为了给pay方法解耦,我们每种不同支付采用不同回调地址
   String notifyUrl ="http://www.baidu.com/wxnotify";//要填能访问到的,别用本地localhost或者内网IP,尽量使用域名和公网IP
   Map map = null;
   //用异常包围起来,也许你想用事物来做
   try {
      map = pay(id,openid,money,request);
   }catch (Exception e){
      //处理一下异常
   }
   return map;
}

然后我们看一下这个pay方法。下面会调用StringUtil和HttpRequestor ,这两个是我自己准备的工具包,文末会贴上

/**
 *  发起支付请求
 * @param orderid  订单ID
 * @param openid   用户ID
 * @param money   支付金额
 * @param request   请求体
 * @param notifyUrl 支付结果回调通知地址
 * @return   预付单参数
 * @throws Exception
 */
public  Map pay(String orderid, String openid, BigDecimal money,String notifyUrl, HttpServletRequest request) throws Exception {
   //转化为分为单位
   money = money.multiply(new BigDecimal(100));
   //转换格式,最终还是转换成了long类型。。。。。但是绝对不要忘记是以分为单位
   Long price = money.longValue();
   //不能支付0元
   if(price==0L){
      return  null;
   }
   // 生成的随机字符串,最长32位,uuid去掉“-”正好
   String nonce_str = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
   // 商品名称,这里我写死了商品名称,如果你不想这样就改成参数吧
   String productName = "测试商品";
   // 获取终端IP
   String ip = HttpRequestor.getIpFromRequest(request);
  //GlobalPerties 是一个参数类,里面的所有变量都是static final的,方便访问。我用来存不会变动的参数
   // 组装参数,用户生成统一下单接口的签名,这里用TreeMap 来就不需要自己排序了
   SortedMap<String, String> packageParams = new TreeMap<String, String>();
   packageParams.put("appid", GlobalProperties.APPID);// 小程序的aapid
   packageParams.put("mch_id", GlobalProperties.MCHID);// 商户号
   packageParams.put("nonce_str", nonce_str);// 随机字符串
   packageParams.put("body", productName);// 商品名称
   packageParams.put("out_trade_no", orderid);// 商户订单号
   packageParams.put("total_fee", price + "");// 标价金额
   packageParams.put("spbill_create_ip", ip);// 终端IP
   packageParams.put("notify_url",notifyUrl);// 通知地址
   packageParams.put("trade_type", "JSAPI");// 交易类型
   packageParams.put("openid", openid);// 微信用户的openid
   //参数map准备好之后我们进行拼接并加密。具体方法往后看
   // MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
   String mysign = getSign(packageParams);
   // 拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
   String xml = "<xml>" + "<appid>" + GlobalProperties.APPID + "</appid>" + "<body><![CDATA[" + productName + "]]></body>"
         + "<mch_id>" + GlobalProperties.MCHID + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>"
         + "<notify_url>" + notifyUrl + "</notify_url>" + "<openid>" + openid + "</openid>"
         + "<out_trade_no>" + orderid + "</out_trade_no>" + "<spbill_create_ip>" + ip + "</spbill_create_ip>"
         + "<total_fee>" + price + "</total_fee>" + "<trade_type>" + GlobalProperties.TRADETYPE + "</trade_type>"
         + "<sign>" + mysign + "</sign>" + "</xml>";
   //打印一下日志方便调试,用了@Slf4j
   log.info("调试模式_统一下单接口 请求XML数据:" + xml);
   
   // 调用统一下单接口,并接受预付订单参数。这里我执行了一个post请求,这个请求工具类我放在文末
   String result = HttpRequestor.doPost(GlobalProperties.PAYREQUEST_URL, xml);
   //打印日志
   log.info("调试模式_统一下单接口 返回XML数据:" + result);
   
   // 将解析结果存储在HashMap中,xml转map 我是用了dom4j
   
   Map<String, Object> map = StringUtil.doXMLParse(result);
   /**
    * 返回状态码
    */
   String return_code = (String) map.get("return_code");
   /**
    * 准备返回给前端的map集合
    */
   Map<String, Object> response = new HashMap<String, Object>(16);
   // 判断一下预付订单是否成功的
   if ("SUCCESS".equals(return_code)) {
      /**
       * 分析预付单信息
       */
      String prepay_id = (String) map.get("prepay_id");
      //前端需要的参数:nonceStr、package、timeStamp、paySign、appid,所以我们只需要关心这几个
      response.put("nonceStr", nonce_str);
      response.put("package", "prepay_id=" + prepay_id);
      Long timeStamp = System.currentTimeMillis() / 1000;
      /**
       * 这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
       */
      response.put("timeStamp", timeStamp + "");
      // 拼接签名需要的参数
      String stringSignTemp = "appId=" + GlobalProperties.APPID + "&nonceStr=" + nonce_str + "&package=prepay_id="
           
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
老规矩,先看本节效果图我们实现这个支付功能完全是借助小程序云开发实现的,不用搭建自己的服务器,不用买域名,不用备案域名,不用支持https。只需要一个简单的云函数,就可以轻松的实现微信小程序支付功能。核心代码就下面这些一,创建一个云开发小程序关于如何创建云开发小程序,这里我就不再做具体讲解。不知道怎么创建云开发小程序的同学,可以去翻看我之前的文章,或者看下我录制的视频:https://edu.csdn.net/course/play/9604/204528创建云开发小程序有几点注意的1,一定不要忘记在app.js里初始化云开发环境。2,创建完云函数后,一定要记得上传二, 创建支付的云函数1,创建云函数pay三,引入三方依赖tenpay我们这里引入三方依赖的目的,是创建我们支付时需要的一些参数。我们安装依赖是使用里npm 而npm必须安装node,关于如何安装node,我这里不做讲解,百度一下,网上一大堆。1,首先右键pay,然后选择在终端中打开2,我们使用npm来安装这个依赖。在命令行里执行 npm i tenpay安装完成后,我们的pay云函数会多出一个package.json 文件到这里我们的tenpay依赖就安装好了。四,编写云函数pay完整代码如下//云开发实现支付 const cloud = require('wx-server-sdk')cloud.init() //1,引入支付的三方依赖 const tenpay = require('tenpay'); //2,配置支付信息 const config = ;exports.main = async(event, context) => 一定要注意把appid,mchid,partnerKey换成你自己的。到这里我们获取小程序支付所需参数的云函数代码就编写完成了。不要忘记上传这个云函数。出现下图就代表上传成功五,写一个简单的页面,用来提交订单,调用pay云函数。这个页面很简单,1,自己随便编写一个订单号(这个订单号要大于6位)2,自己随便填写一个订单价(单位是分)3,点击按钮,调用pay云函数。获取支付所需参数。下图是官方支付api所需要的一些必须参数。下图是我们调用pay云函数获取的参数,和上图所需要的是不是一样。六,调用wx.requestPayment实现支付下图是官方的示例代码这里不在做具体讲解了,完整的可以看视频。实现效果1,调起支付键盘2,支付完成3,log日志,可以看出不同支付状态的回调上图是支付成功的回调,我们可以在支付成功回调时,改变订单支付状态。下图是支付失败的回调,下图是支付完成的状态。到这里我们就轻松的实现了微信小程序的支付功能了。是不是很简单啊,完整的讲解可以看视频。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值