微信小程序支付功能,完成整个交易的思路和代码

开发工具:微信开发者工具,Intellij idea 2018

框架:spring boot 

交易流程图:

下面直接上代码:

1.在wxml添加一个支付按钮,点击监听payMethod方法

<view><button bindtap='payMethod'>支付</button></view>

2.payMethod方法种调用wx.login微信接口,获取code。调用getOpenId方法

/**
   *  支付例子
   * const config = require('../../config')获取全局配置
   * const appInstance = getApp();获取全局上下文实例
   */
  payMethod(){
    let _this = this ;//当前上下文
    //获取登录code  
    wx.login({
      success: result =>{
        console.info(result.code)
        //获取openid 
        _this.getOpenId(result.code) 
      }
    }); 
  },

3.将code作为参数,请求Java服务,获取openId

 /**
   * 用code作为参数请求Java服务,像微信服务换取openId,access_token
   * 此处用到openId,access_token暂时无用,为安全起见,此字段不返回客户端
   */
  getOpenId(code){
    let _this = this;//当前上下文
    wx.request({
      url: config.localServer + 'api/wc/jscode2session.wc',
      data: { code: code},
      method: 'POST',
      success: result =>{
        console.info('返回openId')
        console.info(result.data)
        _this.generateOrder(result.data.data.openid)
      },
      fail:() => {
        console.info('fail')
      },
      complete: () => {
        // complete 
      }
    }) 
  },

4.Java服务jscode2session接口,调用微信sns/jscode2session服务,获取openId,将openid返回给小程序客户端

/**
     * 换取 用户唯一标识 OpenID 和 会话密钥 session_key   ->>>  oopenid 和 session_key 组成会话标识,发给客户端,客户端凭借这个标识进行通信
     * 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。
     * 为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
     * 临时登录凭证 code 只能使用一次
     * @param request
     * @param requestEntity
     * @param code
     * @return
     */
    @PostMapping("/jscode2session.wc")
    public ResponseBean jscode2session(HttpServletRequest request, HttpEntity<String> requestEntity,String code) {

        HttpMethod requestMethod = HttpMethod.resolve(request.getMethod());
        String body = requestEntity.getBody();
        Map<String,String> mapParam = JacksonUtil.fromJson(body,Map.class);
        code = mapParam.get("code");
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        requestEntity = new HttpEntity<>(requestEntity.getBody(), headers);

        ResponseEntity<String> response = null;
        response = restTemplate.exchange(
                wcHost+"sns/jscode2session?appid=wxd0ad6e09b4f09a2a&secret=919f06b91b6adbe682c0bd9edc0a008f&js_code="+code+"&grant_type=authorization_code",
                requestMethod,
                requestEntity,
                String.class);

        String result =  response.getBody();
        LOGGER.info("result="+result);
        Map<String,String> mapResult = JacksonUtil.fromJson(result,Map.class);
        return ResponseBean.response(mapResult);

    }

5.小程序获取openid,调用generateOrder方法,生成订单信息,调用Java服务payOrderPublic.wc接口,以获取支付参数

/**
   * 用openid,在Java服务请求微信服务,获取支付的请求参数
   */
  generateOrder(openid){
    var _this = this 

    var paymentPo={
      openid: openid,
      total_fee: '0.1',
      mch_id: 'mch_id',
      body: '支付测试',
      detail: 'detail',
      attach: '假酒'
    }

    wx.request({
      url: config.localServer + 'api/wc/payOrderPublic.wc',
      method: 'POST',
      data: paymentPo,
      success: result => {
        console.info(result)
        var pay = result.data.data
        //发起支付 
        var timeStamp = pay[0].timeStamp;
        console.info("timeStamp:" + timeStamp)
        var packages = pay[0].package;
        console.info("package:" + packages)
        var paySign = pay[0].paySign;
        console.info("paySign:" + paySign)
        var nonceStr = pay[0].nonceStr;
        console.info("nonceStr:" + nonceStr)
        var param = { "timeStamp": timeStamp, "package": packages, "paySign": paySign, "signType": "MD5", "nonceStr": nonceStr };
        _this.pay(param)
      },
    }) 
  },

6.Java服务payOrderPublic.wc接口,将参数生成签名,打包成xml格式,请求微信的统一下单接口/pay/unifiedorder,将获取的结果进行再次签名,得到支付接口需要的参数,返回给小程序客户端。

/**
     *  商户server调用支付统一下单
//     * @param openid 用户唯一标识
//     * @param mch_id 商品编号
//     * @param total_fee 商品价格
//     * @param body 商品描述
//     * @param detail 商品详情
//     * @param attach 附加数据
//     * @param time_start 交易开始时间
//     * @param time_expire 交易结束时间
     * @return
     */
    @PostMapping("/payOrderPublic.wc")
    public ResponseBean  payOrderPublic(HttpServletRequest request,HttpEntity<String> requestEntity,PaymentPo paymentPo) throws UnsupportedEncodingException, DocumentException {

        paymentPo = JacksonUtil.fromJson(requestEntity.getBody(),PaymentPo.class);
        paymentPo.setBody(new String(paymentPo.getBody().getBytes("UTF-8"),"ISO-8859-1")) ;
//        String appid = "替换为自己的小程序ID";//小程序ID
        //当前时间
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        //生成8位随机数
        String code = PayUtil.createCode(8);
        //商户订单号
        String out_trade_no = paymentPo.getMch_id()+today+code;//商户订单号
        String spbill_create_ip = HttpUtil.getIpAddress(request);//终端IP
        String notify_url = "http://www.weixin.qq.com/wxpay/pay.php";//通知地址
        String trade_type = "JSAPI";//交易类型

        paymentPo.setAppid(appid);
        //随机字符串 32位
        String str=UUIDHexGeneratorUtil.generate();
        paymentPo.setNonce_str(str);
        paymentPo.setOut_trade_no(out_trade_no);
        paymentPo.setSpbill_create_ip(spbill_create_ip);
        paymentPo.setNotify_url(notify_url);
        paymentPo.setTrade_type(trade_type);

        // 把请求参数放进hashmap
        Map<String,String> sParaTemp = new HashMap<String,String>();
        sParaTemp.put("appid", paymentPo.getAppid());
        sParaTemp.put("mch_id", paymentPo.getMch_id());
        sParaTemp.put("nonce_str", paymentPo.getNonce_str());
        sParaTemp.put("body",  paymentPo.getBody());
        sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
        sParaTemp.put("total_fee",paymentPo.getTotal_fee());
        sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
        sParaTemp.put("notify_url",paymentPo.getNotify_url());
        sParaTemp.put("trade_type", paymentPo.getTrade_type());
        sParaTemp.put("openid", paymentPo.getOpenid());

        // 除去map中的空值和签名参数
        Map<String,String> sPara = PayUtil.paraFilter(sParaTemp);
        // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        String prestr = PayUtil.createLinkString(sPara);
        String key = "&key=替换为商户支付密钥"; // 商户支付密钥
        //MD5运算生成签名
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        paymentPo.setSign(mysign);
        //打包要发送的xml
        String respXml = MessageUtil.messageToXML(paymentPo);
        // 打印respXml发现,得到的xml中有“__”不对,应该替换成“_”
        respXml = respXml.replace("__", "_");
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接
        String param = respXml;
        String result =PayUtil.httpRequest(url, "POST", param);
        // 将解析结果存储在HashMap中
        Map<String,String> map = new HashMap<String,String>();
        InputStream in = new ByteArrayInputStream(result.getBytes());
        // 读取输入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(in);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子节点
        @SuppressWarnings("unchecked")
        List<Element> elementList = root.elements();
        for (Element element : elementList) {
            map.put(element.getName(), element.getText());
        }
        // 返回信息
        String return_code = map.get("return_code");//返回状态码
        String return_msg = map.get("return_msg");//返回信息
        System.out.println("return_msg"+return_msg);
        Map<String,Object> resultMap = new HashMap<String,Object>();
        if(return_code=="SUCCESS"||return_code.equals(return_code)){
            // 业务结果
            String prepay_id = map.get("prepay_id");//返回的预付单信息
            String nonceStr=UUIDHexGeneratorUtil.generate();
            resultMap.put("nonceStr", nonceStr);
            resultMap.put("package", "prepay_id="+prepay_id);
            Long timeStamp= System.currentTimeMillis()/1000;
            resultMap.put("timeStamp", timeStamp+"");
            String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
            //再次签名
            String paySign=PayUtil.sign(stringSignTemp, "&key=替换为自己的密钥", "utf-8").toUpperCase();
            resultMap.put("paySign", paySign);
        }
            return ResponseBean.response(resultMap) ;
    }

7.小程序端得到支付参数,用pay方法调用微信的支付接口,完成支付

/**
   * 支付的动作
   */
  pay(param){
    console.info("支付")
    console.info(param)
    wx.requestPayment({
      timeStamp: param.timeStamp,
      nonceStr: param.nonceStr,
      package: param.package,
      signType: param.signType,
      paySign: param.paySign,
      success: (result) => {
        console.info("支付")
        console.info(result)
     
      },
      fail: (result) => {
        console.info("支付失败")
        console.info(result)
      },
      complete: () => {
        console.info("pay complete")
      }
    }) 
  }

 

老规矩,先看本节效果图我们实现这个支付功能完全是借助小程序云开发实现的,不用搭建自己的服务器,不用买域名,不用备案域名,不用支持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、付费专栏及课程。

余额充值