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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_15556155/article/details/83625335

开发工具:微信开发者工具,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")
      }
    }) 
  }

 

展开阅读全文

10分钟实现微信程序支付功能

08-13

<p style="color:#2F2F2F;">n 老规矩,先看本节效果图n</p>n<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-fce2f4ffa8f92d99.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/418/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 我们实现这个支付功能完全是借助小程序云开发实现的,不用搭建自己的服务器,不用买域名,不用备案域名,不用支持https。只需要一个简单的云函数,就可以轻松的实现微信小程序支付功能。<br />n核心代码就下面这些n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-7433fba3b792bb28.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/922/format/webp" alt="" /></div>n </div>n</div>nn 一,创建一个云开发小程序nn<p style="color:#2F2F2F;">n 关于如何创建云开发小程序,这里我就不再做具体讲解。不知道怎么创建云开发小程序的同学,可以去翻看我之前的文章,或者看下我录制的视频:<a href="https://links.jianshu.com/go?to=https%3A%2F%2Fedu.csdn.net%2Fcourse%2Fplay%2F9604%2F204528">https://edu.csdn.net/course/play/9604/204528</a>n</p>nn 创建云开发小程序有几点注意的nn<p style="color:#2F2F2F;">n 1,一定不要忘记在app.js里初始化云开发环境。n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-c436567c3368ac74.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 2,创建完云函数后,一定要记得上传n</p>nn 二, 创建支付的云函数nn<p style="color:#2F2F2F;">n 1,创建云函数payn</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-32302ade305b8a18.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/564/format/webp" alt="" /></div>n </div>n</div>n<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-8ea47ffa0b4cffca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/708/format/webp" alt="" /></div>n </div>n</div>nn 三,引入三方依赖tenpaynn<p style="color:#2F2F2F;">n 我们这里引入三方依赖的目的,是创建我们支付时需要的一些参数。我们安装依赖是使用里npm 而npm必须安装node,关于如何安装node,我这里不做讲解,百度一下,网上一大堆。n</p>nn 1,首先右键pay,然后选择在终端中打开nn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-8881030499ebe5ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>nn 2,我们使用npm来安装这个依赖。nn<p style="color:#2F2F2F;">n 在命令行里执行 npm i tenpayn</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-c61cb1cb5880c475.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/684/format/webp" alt="" /></div>n </div>n</div>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-cd34c63e39e6427f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-768712337485bf67.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 安装完成后,我们的pay云函数会多出一个package.json 文件n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-7e9236d8983ebb21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/682/format/webp" alt="" /></div>n </div>n</div>n<br /><span style="color:#2F2F2F;">到这里我们的tenpay依赖就安装好了。</span>nn 四,编写云函数paynn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-cd36f9084fada492.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 完整代码如下n</p>n<span style="color:#929292;">//云开发实现支付</span> <span style="color:#C678DD;">const</span> cloud = <span style="color:#E6C07B;">require</span>(<span style="color:#98C379;">'wx-server-sdk'</span>)ncloud.init() <span style="color:#929292;">//1,引入支付的三方依赖</span> <span style="color:#C678DD;">const</span> tenpay = <span style="color:#E6C07B;">require</span>(<span style="color:#98C379;">'tenpay'</span>); <span style="color:#929292;">//2,配置支付信息</span> <span style="color:#C678DD;">const</span> config = { <span style="color:#D19A66;">appid</span>: <span style="color:#98C379;">'你的小程序appid'</span>, <span style="color:#D19A66;">mchid</span>: <span style="color:#98C379;">'你的微信商户号'</span>, <span style="color:#D19A66;">partnerKey</span>: <span style="color:#98C379;">'微信支付安全密钥'</span>, <span style="color:#D19A66;">notify_url</span>: <span style="color:#98C379;">'支付回调网址,这里可以先随意填一个网址'</span>, <span style="color:#D19A66;">spbill_create_ip</span>: <span style="color:#98C379;">'127.0.0.1'</span> <span style="color:#929292;">//这里填这个就可以</span> };nnexports.main = <span style="color:#C678DD;">async</span>(event, context) =&gt; { <span style="color:#C678DD;">const</span> wxContext = cloud.getWXContext() <span style="color:#C678DD;">let</span> {n orderid,n moneyn } = event; <span style="color:#929292;">//3,初始化支付</span> <span style="color:#C678DD;">const</span> api = tenpay.init(config); <span style="color:#C678DD;">let</span> result = <span style="color:#C678DD;">await</span> api.getPayParams({ <span style="color:#D19A66;">out_trade_no</span>: orderid, <span style="color:#D19A66;">body</span>: <span style="color:#98C379;">'商品简单描述'</span>, <span style="color:#D19A66;">total_fee</span>: money, <span style="color:#929292;">//订单金额(分),</span> openid: wxContext.OPENID <span style="color:#929292;">//付款用户的openid</span> }); <span style="color:#C678DD;">return</span> result;n}nn 一定要注意把appid,mchid,partnerKey换成你自己的。nn<p style="color:#2F2F2F;">n 到这里我们获取小程序支付所需参数的云函数代码就编写完成了。<br />n不要忘记上传这个云函数。n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-ba99ca6fe33401ec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/992/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 出现下图就代表上传成功n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-6133d61bc300dac4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/626/format/webp" alt="" /></div>n </div>n</div>nn 五,写一个简单的页面,用来提交订单,调用pay云函数。nn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-ee974aecada48f7c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 这个页面很简单,<br />n1,自己随便编写一个订单号(这个订单号要大于6位)<br />n2,自己随便填写一个订单价(单位是分)<br />n3,点击按钮,调用pay云函数。获取支付所需参数。n</p>n<p style="color:#2F2F2F;">n 下图是官方支付api所需要的一些必须参数。n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-2708b7475409199b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 下图是我们调用pay云函数获取的参数,和上图所需要的是不是一样。n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-d94c566dd744f128.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>nn 六,调用wx.requestPayment实现支付nn<p style="color:#2F2F2F;">n 下图是官方的示例代码n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-00e9315590e4e14c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 这里不在做具体讲解了,完整的可以看视频。n</p>nn 实现效果nnn 1,调起支付键盘nn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-b20becb49e6fd26e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/234/format/webp" alt="" /></div>n </div>n</div>nn 2,支付完成nn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-b2a8266fdc83edc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/270/format/webp" alt="" /></div>n </div>n</div>nn 3,log日志,可以看出不同支付状态的回调nn<div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-3a1fca73b650742e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<br /><p style="color:#2F2F2F;">n 上图是支付成功的回调,我们可以在支付成功回调时,改变订单支付状态。n</p>n<p style="color:#2F2F2F;">n 下图是支付失败的回调,n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-1b306a9b35b292e0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<p style="color:#2F2F2F;">n 下图是支付完成的状态。n</p>n<br /><div style="text-align:center;color:#2F2F2F;">n <div style="background-color:transparent;">n <div>n </div>n <div>n <img src="https://upload-images.jianshu.io/upload_images/6273713-906f64407be62c4c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp" alt="" /></div>n </div>n</div>n<p style="color:#2F2F2F;">n 到这里我们就轻松的实现了微信小程序的支付功能了。是不是很简单啊,完整的讲解可以看视频。n</p>

没有更多推荐了,返回首页