借助小程序云开发实现小程序支付功能(含源码)

我们在做小程序支付相关的开发时,总会遇到这些难题。小程序调用微信支付时,必须要有自己的服务器,有自己的备案域名,有自己的后台开发。这就导致我们做小程序支付时的成本很大。本节就来教大家如何使用小程序云开发实现小程序支付功能的开发。不用搭建自己的服务器,不用有自己的备案域名。只需要简简单单的使用小程序云开发。

老规矩先看效果图:

本节知识点

1,云开发的部署和使用

2,支付相关的云函数开发

3,商品列表

4,订单列表

5,微信支付与支付成功回调

支付成功给用户发送推送消息的功能会在后面讲解。

下面就来教大家如何借助云开发使用小程序支付功能。

支付所需要用到的配置信息

1,小程序appid

2,云开发环境id

3,微信商户号

4,商户密匙

一,准备工作

1,已经申请小程序,获取小程序 AppID 和 Secret 在小程序管理后台中,【设置】 →【开发设置】 下可以获取微信小程序 AppID 和 Secret。

2,微信支付商户号,获取商户号和商户密钥在微信支付商户管理平台中,【账户中心】→【商户信息】 下可以获取微信支付商户号。

在【账户中心】 ‒> 【API安全】 下可以设置商户密钥。

这里特殊说明下,个人小程序是没有办法使用微信支付的。所以如果想使用微信支付功能,必须是非个人账号(当然个人可以办个体户工商执照来注册非个人小程序账号)3,微信开发者 IDE https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

4,开通小程序云开发功能:https://edu.csdn.net/course/play/9604/204526

二,商品列表的实现

效果图如下,由于本节重点是支付的实现,所以这里只简单贴出关键代码。

wxml布局如下:

<view class="container">

<view class="good-item" wx:for="{{goods}}" wx:key="*this" ontap="getDetail" data-goodid="{{item._id}}">

<view class="good-image">

<image src="{{pic}}"></image>

</view>

<view class="good-detail">

<view class="title">商品: {{item.name}}</view>

<view class="content">价格: {{item.price / 100}} 元 </view>

<button

class="button"

type="primary"

bindtap="makeOrder"

data-goodid="{{item._id}}"

>下单</button>

</view>

</view>

</view>

我们所需要做的就是借助云开发获取云数据库里的商品信息,然后展示到商品列表,关于云开发获取商品列表并展示本节不做讲解(感兴趣的同学可以翻看我的历史博客,有写过的)

三,支付云函数的创建

首先看下我们支付云函数都包含那些内容

简单先讲解下每个的用处

config下的index.js是做支付配置用的,主要配置支付相关的账号信息

lib是用的第三方的支付库,这里不做讲解。

重点讲解的是云函数入口 index.js下面就来教大家如何去配置

1,配置config下的index.js,

这一步所需要做的就是把小程序appid,云开发环境ID,商户id,商户密匙。填进去。

2,配置入口云函数

详细代码如下,代码里注释很清除了,这里不再做单独讲解:

const cloud = require('wx-server-sdk')

cloud.init()

const app = require('tcb-admin-node');

const pay = require('./lib/pay');

const {

mpAppId,

KEY

} = require('./config/index');

const {

WXPayConstants,

WXPayUtil

} = require('wx-js-utils');

const Res = require('./lib/res');

const ip = require('ip');

/**

*

* @param {obj} event

* @param {string} event.type 功能类型

* @param {} userInfo.openId 用户的openid

*/

exports.main = async function(event, context) {

const {

type,

data,

userInfo

} = event;

const wxContext = cloud.getWXContext()

const openid = userInfo.openId;

app.init();

const db = app.database();

const goodCollection = db.collection('goods');

const orderCollection = db.collection('order');

// 订单文档的status 0 未支付 1 已支付 2 已关闭

switch (type) {

// [在此处放置 unifiedorder 的相关代码]

case 'unifiedorder':

{

// 查询该商品 ID 是否存在于数据库中,并将数据提取出来

const goodId = data.goodId

let goods = await goodCollection.doc(goodId).get();

if (!goods.data.length) {

return new Res({

code: 1,

message: '找不到商品'

});

}

// 在云函数中提取数据,包括名称、价格才更合理安全,

// 因为从端里传过来的商品数据都是不可靠的

let good = goods.data[0];

// 拼凑微信支付统一下单的参数

const curTime = Date.now();

const tradeNo = `${goodId}-${curTime}`;

const body = good.name;

const spbill_create_ip = ip.address() || '127.0.0.1';

// 云函数暂不支付 http 触发器,因此这里回调 notify_url 可以先随便填。

const notify_url = 'http://www.qq.com'; //'127.0.0.1';

const total_fee = good.price;

const time_stamp = '' + Math.ceil(Date.now() / 1000);

const out_trade_no = `${tradeNo}`;

const sign_type = WXPayConstants.SIGN_TYPE_MD5;

let orderParam = {

body,

spbill_create_ip,

notify_url,

out_trade_no,

total_fee,

openid,

trade_type: 'JSAPI',

timeStamp: time_stamp,

};

// 调用 wx-js-utils 中的统一下单方法

const {

return_code,

...restData

} = await pay.unifiedOrder(orderParam);

let order_id = null;

if (return_code === 'SUCCESS' && restData.result_code === 'SUCCESS') {

const {

prepay_id,

nonce_str

} = restData;

// 微信小程序支付要单独进地签名,并返回给小程序端

const sign = WXPayUtil.generateSignature({

appId: mpAppId,

nonceStr: nonce_str,

package: `prepay_id=${prepay_id}`,

signType: 'MD5',

timeStamp: time_stamp

}, KEY);

let orderData = {

out_trade_no,

time_stamp,

nonce_str,

sign,

sign_type,

body,

total_fee,

prepay_id,

sign,

status: 0, // 订单文档的status 0 未支付 1 已支付 2 已关闭

_openid: openid,

};

let order = await orderCollection.add(orderData);

order_id = order.id;

}

return new Res({

code: return_code === 'SUCCESS' ? 0 : 1,

data: {

out_trade_no,

time_stamp,

order_id,

...restData

}

});

}

// [在此处放置 payorder 的相关代码]

case 'payorder':

{

// 从端里出来相关的订单相信

const {

out_trade_no,

prepay_id,

body,

total_fee

} = data;

// 到微信支付侧查询是否存在该订单,并查询订单状态,看看是否已经支付成功了。

const {

return_code,

...restData

} = await pay.orderQuery({

out_trade_no

});

// 若订单存在并支付成功,则开始处理支付

if (restData.trade_state === 'SUCCESS') {

let result = await orderCollection

.where({

out_trade_no

})

.update({

status: 1,

trade_state: restData.trade_state,

trade_state_desc: restData.trade_state_desc

});

let curDate = new Date();

let time = `${curDate.getFullYear()}-${curDate.getMonth() +

1}-${curDate.getDate()} ${curDate.getHours()}:${curDate.getMinutes()}:${curDate.getSeconds()}`;

}

return new Res({

code: return_code === 'SUCCESS' ? 0 : 1,

data: restData

});

}

case 'orderquery':

{

const {

transaction_id,

out_trade_no

} = data;

// 查询订单

const {

data: dbData

} = await orderCollection

.where({

out_trade_no

})

.get();

const {

return_code,

...restData

} = await pay.orderQuery({

transaction_id,

out_trade_no

});

return new Res({

code: return_code === 'SUCCESS' ? 0 : 1,

data: { ...restData,

...dbData[0]

}

});

}

case 'closeorder':

{

// 关闭订单

const {

out_trade_no

} = data;

const {

return_code,

...restData

} = await pay.closeOrder({

out_trade_no

});

if (return_code === 'SUCCESS' &&

restData.result_code === 'SUCCESS') {

await orderCollection

.where({

out_trade_no

})

.update({

status: 2,

trade_state: 'CLOSED',

trade_state_desc: '订单已关闭'

});

}

return new Res({

code: return_code === 'SUCCESS' ? 0 : 1,

data: restData

});

}

}

}

其实我们支付的关键功能都在上面这些代码里面了。

再来看下,支付的相关流程截图

上图就涉及到了我们的订单列表,支付状态,支付成功后的回调。

今天就先讲到这里,后面会继续给大家讲解支付的其他功能。比如支付成功后的消息推送,也是可以借助云开发实现的。

由于源码里涉及到一些私密信息,这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言

原文地址:https://www.toutiao.com/article/6691987356116845063/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340