个人案例
- 飞机打气球打泡泡游戏
打泡泡小游戏
打泡泡小游戏扫码体验
- 同城跑腿代办
同城跑腿代办
同城跑腿代办扫码体验
- 零基础编程开发学习软件程序开发
零基础编程开发学习
零基础编程开发学习扫码体验
- 手把手带你使用云开发实现微信小程序支付功能(完整视频讲解)
首先看下效果图 [图片] 下面把完整的讲解视频,免费发给大家。 1~注册企业小程序 [视频] 2~微信支付商户号注册及注意事项 [视频] 3~小程序关联微信支付的商户号 [视频] 4~创建云开发项目 [视频] 5~云开发控制台配置微信支付商户号 [视频] 6~编写支付的云函数 [视频] 7~云开发实现微信支付 [视频] 8~动态修改商品名和价格 [视频] 9~编写商品页面 [视频] 10~单个商品的支付 [视频] 11~商品列表实现购买支付 [视频] 如果你是B站用户,也可以去石头哥B站观看完整的视频讲解: https://www.bilibili.com/video/BV1Lp4y1D7oY/
2020-06-11 - uploader组件示例代码
uploader组件文档说的很不清除,这里做了一个代码片段,有兴趣可以看看 /** * 这里使用到云函数,需要填写正确的云开发配置字段才可以正常使用 * uploader组件主要就是两个方法removeImage,uploadFile,一个删除,一个上传,其他的可以暂时不考虑 */ Page({ data: { files: [ {url:'http://n.sinaimg.cn/photo/transform/700/w1000h500/20200219/ca9a-iprtayz8150608.jpg'} ] }, onLoad() { console.log(this); this.setData({ uploadFile: this.uploadFile.bind(this) //这里需要绑定uploadFile函数,因为在uploader组件中会调用这个方法,不绑定的话,this会指向uploader组件中的this,但是uploader组件中没有这个方法,这个方法需要用户自定义 }); }, removeImage: async function ({detail}) { console.log(detail); this.data.files.splice(detail.index,1);//同步更新files字段数据 await wx.cloud.deleteFile({//直接调用云函数删除 fileList:[detail.item.url] }); }, uploadFile: async function (files) { console.log('upload files', files) let tempFilePaths = files.tempFilePaths; let arr=[];//保存最后返回的结果 for (let i = 0; i < tempFilePaths.length; i++) { let {fileID}= await wx.cloud.uploadFile({ //云存储中的文件名这里直接截取本地文件路径的一部分使用,方便 cloudPath: 'images/'+tempFilePaths[i].match(/\w+\.\w+$/g)[0], filePath: tempFilePaths[i], // 文件路径 }); arr.push(fileID); //更新files字段 this.data.files.push({ url:fileID }) } console.log(arr); return {urls:arr}; //返回的格式是{urls:['xxx.jpg','xxx.jpg']} }, uploadError(e) { console.log('upload error', e.detail) }, uploadSuccess(e) { console.log('upload success', e.detail) } }); https://developers.weixin.qq.com/s/28TTpgmR7UfQ
2020-02-20 - 小程序开发常见问题及解决方案
一,input不触发bindinput事件 关于input使用bindinput事件时,没法获取用户输入信息的问题。 解决: 这个是官方2.9.3的bug,退到2.9.2后就好了,回退操作如下图 [图片] 二,getImageInfo:fail download image fail 出现这种问题,是因为没有给小程序的downloadFile配置域名白名单。 [图片] 三,获取小程序用户高清图像 [代码]//获取高清微信头像 headimgHD(imageUrl) { console.log('原来的头像', imageUrl); imageUrl = imageUrl.split('/'); //把头像的路径切成数组 //把大小数值为 46 || 64 || 96 || 132 的转换为0 if (imageUrl[imageUrl.length - 1] && (imageUrl[imageUrl.length - 1] == 46 || imageUrl[imageUrl.length - 1] == 64 || imageUrl[imageUrl.length - 1] == 96 || imageUrl[imageUrl.length - 1] == 132)) { imageUrl[imageUrl.length - 1] = 0; } imageUrl = imageUrl.join('/'); //重新拼接为字符串 console.log('高清的头像', imageUrl); return imageUrl; }, [代码]
2019-11-17 - 微信小程序云开发常见问题及解决方案
我们在做微信小程序云开发的过程中,总会遇到各种奇葩的问题。今天就把我在小程序云开发过程中遇到的各种问题,及对应的解决方案总结在这里,方便以后自己回顾,也方便大家查看。 一,云函数调用失败问题(404011) [云函数] [login] 调用失败 Error: errCode: -404011 cloud function execution error | errMsg: cloud.callFunction:fail requestID , cloud function service error code -504002, error message Function not found: [login]; at cloud.callFunction api; [图片] 通常出现这种问题无非是下面2个原因 1,云函数没有部署,或者没有部署成功 2,你创建了多个云开发环境,没有配置对应的环境id 下面就针对这两个问题,具体说下解决方案 1,云函数没有部署,或者没有部署成功 [图片] 选中我们要部署的云函数,右键,如上图红色框里所示。如果点一次不能上传,就多点几次,一直到出现下面提示框为止 [图片] 2,你创建了多个云开发环境,没有配置对应的环境id 如果你创建了多个云开发环境,有时候开发者工具会脑残的不知道该选择使用那个云开发环境,这个时候,我们就要指定云开发环境了。 [图片] [图片] 如果你是多个开发环境,一定要注意环境名,和环境id必须一一对应。 二,云数据库set或者update数据时报如下错误(502001) Error: errCode: -502001 database request fail | errMsg: [FailedOperation.Insert] multiple write errors: [{write errors: [{E11000 duplicate key error collection: tnt-12p3936xo.x-j-l index: id dup key: { : “xjl” }}]}, {<nil>}] 详细错误如下图: [图片] 错误原因 造成这种错误的主要原因是因为,你修改的这条数据不是你创建的。我们直接操作云数据库时,在数据库里设置里如下权限。 [图片] 这个权限只能让你读所有人的数据,但是修改的话,你还是只能修改自己创建的数据。什么样的数据才是自己创建的呢。如下图。 [图片] 所以到这里我们就大概明白如何解决这个问题了。 解决方案 1,把_openid改为自己的openid 2,借助云函数。 这里说下借助云函数,因为你是没有办法直接修改别人的数据的,但是你借助云函数的话,就可以修改任何人的数据。 三,云函数老是不能上传成功,或者上传成功后是错误的。 [图片] 如果你上传云函数老是报上面的错误,就先关闭开发者工具。然后再打开,开发者工具,进入云开发管理界面,把错误的云函数删除了。 [图片] 然后再到你的代码目录里做下同步。 [图片] 这样我们就可以重新上传我们的pay函数了。 [图片] 上传云函数时,一定要记得选择如上图箭头所指的。 上传的时候,会有下面这个提示,可以忽略不管。 [图片] 出现下图就代码你云函数上传成功了。 [图片] 四, -404011 error message wx is not defined [图片] 问题是出在云函数里,就是你在云函数里使用数据库请求的时候代码写成下面这样了。 [图片] 解决方法 我们在云函数里使用cloud.database时,不用再写wx.cloud了,直接写成cloud.database就可以了。只有在小程序的页面的js里使用时,才需要写成 wx.cloud.database****** 五,-502005 Db or Table not exist. Please check your request, but if the problem cannot be solved, contact us 错误信息如下图所示 [图片] 其实这个问题算是官方的一个bug,因为我在app.js里已经初始化过了,但是这里找不到db或者数据表的原因还是因为我没有初始化过。奇怪的是这个问题我电脑上是没问题的,但是我的一些学员电脑上就会有这个问题。 [图片] 解决方法 这个解决方法就是在你云函数里再做下初始化。 [图片] 六,-404011 请先调用init 完成初始化 其实这个问题和上面第五个是一样的,解决方式同第五个 [图片] 云开发视频讲解 https://edu.csdn.net/course/detail/9604 持续更新中。。。。。。 有关于小程序的问题可以加我微信 2501902696(备注小程序)
2019-11-14 - 小程序可以读取Excel表格或者txt文件里的数据吗?
我现在有一张Excel表格,打开小程序时需要读取表格里的数据,小程序可以读取Excel表格的数据吗?
2018-02-26 - 云开发中的update如何更新对象数组中的值?
[图片] [图片] 比如说我想更新kqTime第一条中的宋江的HP为500,该怎么写啊
2019-08-12 - 小程序用webview内嵌网页,可以在网页直接调起小程序支付吗
小程序用webview内嵌网页,可以在网页直接调起小程序支付吗
2019-07-20 - 5行代码实现微信小程序模版消息推送 (含推送后台和小程序源码)
由于小程序2020年1月10日以后改模板消息为订阅消息,所以我写了一篇新的文章来更新这个知识点 《小程序订阅消息推送(含源码)java实现小程序推送,springboot实现微信消息推送》 我们在做小程序开发时,消息推送是不可避免的。今天就来教大家如何实现小程序消息推送的后台和前台开发。源码会在文章末尾贴出来。 其实我之前有写过一篇:《springboot实现微信消息推送,java实现小程序推送,含小程序端实现代码》 但是有同学反应这篇文章里的代码太繁琐,接入也比较麻烦。今天就来给大家写个精简版的,基本上只需要几行代码,就能实现小程序模版消息推送功能。 老规矩先看效果图 [图片] 这是我们最终推送给用户的模版消息。这是用户手机微信上显示的推送消息截图。 本节知识点 1,java开发推送后台 2,springboot实现推送功能 3,小程序获取用户openid 4,小程序获取fromid用来推送 先来看后台推送功能的实现 只有下面一个简单的PushController类,就可以实现小程序消息的推送 [图片] 再来看下PushController类,你没看错,实现小程序消息推送,就需要下面这几行代码就可以实现了。 [图片] 由于本推送代码是用springboot来实现的,下面就来简单的讲下。我我们需要注意的几点内容。 1,需要在pom.xml引入一个三方类库(推送的三方类库) [图片] pom.xml的完整代码如下 [代码]<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.qcl</groupId> <artifactId>wxapppush</artifactId> <version>0.0.1-SNAPSHOT</version> <name>wxapppush</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--微信小程序模版推送--> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-miniapp</artifactId> <version>3.4.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> [代码] 其实到这里我们java后台的推送功能,就已经实现了。我们只需要运行springboot项目,就可以实现推送了。 下面贴出完整的PushController.java类。里面注释很详细了。 [代码]package com.qcl.wxapppush; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaTemplateData; import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage; import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig; import me.chanjar.weixin.common.error.WxErrorException; /** * Created by qcl on 2019-05-20 * 微信:2501902696 * desc: 微信小程序模版推送实现 */ @RestController public class PushController { @GetMapping("/push") public String push(@RequestParam String openid, @RequestParam String formid) { //1,配置小程序信息 WxMaInMemoryConfig wxConfig = new WxMaInMemoryConfig(); wxConfig.setAppid("XXX");//小程序appid wxConfig.setSecret("xxx");//小程序AppSecret WxMaService wxMaService = new WxMaServiceImpl(); wxMaService.setWxMaConfig(wxConfig); //2,设置模版信息(keyword1:类型,keyword2:内容) List<WxMaTemplateData> templateDataList = new ArrayList<>(2); WxMaTemplateData data1 = new WxMaTemplateData("keyword1", "获取老师微信"); WxMaTemplateData data2 = new WxMaTemplateData("keyword2", "2501902696"); templateDataList.add(data1); templateDataList.add(data2); //3,设置推送消息 WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder() .toUser(openid)//要推送的用户openid .formId(formid)//收集到的formid .templateId("eDZCu__qIz64Xx19dAoKg0Taf5AAoDmhUHprF6CAd4A")//推送的模版id(在小程序后台设置) .data(templateDataList)//模版信息 .page("pages/index/index")//要跳转到小程序那个页面 .build(); //4,发起推送 try { wxMaService.getMsgService().sendTemplateMsg(templateMessage); } catch (WxErrorException e) { System.out.println("推送失败:" + e.getMessage()); return e.getMessage(); } return "推送成功"; } } [代码] 看代码我们可以知道,我们需要做一些配置,需要下面信息 1,小程序appid 2,小程序AppSecret(密匙) 3,小程序推送模版id 4,用户的openid 5,用户的formid(一个formid只能用一次) 下面就是小程序部分,来教大家如何获取上面所需的5个信息。 1,appid和AppSecret的获取(登录小程序管理后台) [图片] 2,推送模版id [图片] 3,用户openid的获取,可以看下面的这篇文章,也可以看源码,这里不做具体讲解 小程序开发如何获取用户openid 4,获取formid [图片] 看官方文档,可以知道我们的formid有效期是7天,并且一个form_id只能使用一次,所以我们小程序端所需要做的就是尽可能的多拿些formid,然后传个后台,让后台存到数据库中,这样7天有效期内,想怎么用就怎么用了。 所以接下来要讲的就是小程序开发怎么尽可能多的拿到formid了 [图片] 看下官方提供的,只有在表单提交时把report-submit设为true时才能拿到formid,比如这样 [代码] <form report-submit='true' > <button form-type='submit'>获取formid</button> </form> [代码] 所以我们就要在这里下功夫了,既然只能在form组件获取,我们能不能把我们小程序里用到最多的地方用form来伪装呢。 下面简单写个获取formid和openid的完整示例,方便大家学习 效果图 [图片] 我们要做的就是点击获取formid按钮,可以获取到用户的formid和openid,正常我们开发时,是需要把openid和formid传给后台的,这里简单起见,我们直接用获取到的formid和openid实现推送功能 下面来看小程序端的实现代码 1,index.wxml [图片] 2,index.js [图片] 到这里我们小程序端的代码也实现了,接下来测试下推送。 [代码]formid: 6ee9ce80c1ed4a2f887fccddf87686eb openid o3DoL0Uusu1URBJK0NJ4jD1LrRe0 [代码] [图片] 可以看到我们用了上面获取到的openid和formid做了一次推送,显示推送成功 [图片] [图片] 到这里我们小程序消息推送的后台和小程序端都讲完了。 这里有两点需要大家注意 1,推送的openid和formid必须对应。 2,一个formid只能用一次,多次使用会报一下错误。 [代码]{"errcode":41029,"errmsg":"form id used count reach limit hint: [ssun8a09984113]"} [代码] 编程小石头,码农一枚,非著名全栈开发人员。分享自己的一些经验,学习心得,希望后来人少走弯路,少填坑。 这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言,我会把源码下载链接贴在留言区。 单独找我要源码也行(微信2501902696) 视频讲解:https://edu.csdn.net/course/detail/23750 源码链接:https://github.com/qiushi123/wxapppush
2020-01-08 - 借助小程序云开发实现小程序支付功能(含源码)
我们在做小程序支付相关的开发时,总会遇到这些难题。小程序调用微信支付时,必须要有自己的服务器,有自己的备案域名,有自己的后台开发。这就导致我们做小程序支付时的成本很大。本节就来教大家如何使用小程序云开发实现小程序支付功能的开发。不用搭建自己的服务器,不用有自己的备案域名。只需要简简单单的使用小程序云开发。 老规矩先看效果图: [图片] 本节知识点 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> [代码] 我们所需要做的就是借助云开发获取云数据库里的商品信息,然后展示到商品列表,关于云开发获取商品列表并展示本节不做讲解(感兴趣的同学可以翻看我的历史博客,有写过的) 也有视频讲解: https://edu.csdn.net/course/detail/9604 [图片] 三,支付云函数的创建 首先看下我们支付云函数都包含那些内容 [图片] 简单先讲解下每个的用处 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 }); } } } [代码] 其实我们支付的关键功能都在上面这些代码里面了。 [图片] 再来看下,支付的相关流程截图 [图片] 上图就涉及到了我们的订单列表,支付状态,支付成功后的回调。 今天就先讲到这里,后面会继续给大家讲解支付的其他功能。比如支付成功后的消息推送,也是可以借助云开发实现的。 由于源码里涉及到一些私密信息,这里就不单独贴出源码下载链接了,大家感兴趣的话,可以私信我,或者在底部留言。单独找我要源码也行(微信2501902696) 视频讲解地址:https://edu.csdn.net/course/detail/24770
2019-06-11