微信小程序学习(一):开发准备、授权与验证
今天学习了下小程序,感觉与web开发差别不大,如果学过vue react angluar等mvvm框架的话,基本无门槛,只需要熟悉一下微信小程序的开发模式和api即可;
路由有点区别,需要注意下看看API。
本地测试时是没有https的,需要在开发工具右上角详情里勾选不校验..以及HTTPS证书。有时候需要真机测试,但是自己把后台上传到公网太麻烦,这里安利一个内外网穿透工具,直接将本地ip:port映射成一个临时公网地址,虽然这个临时公网地址比较慢,但是足够了,很方便
效果图:
今天学习的demo结构如下
1、app.js
//app.js
App({onLaunch: function () {// 展示本地存储能力var logs = wx.getStorageSync('logs') || []logs.unshift(Date.now())wx.setStorageSync('logs', logs)},globalData: {userInfo: null,//用于存储用户信息token: null//后台用户凭证,一般就是openId或openId+unionId},onPageNotFound(res) {wx.redirectTo({url: 'pages/notFound/notFound'}) // 如果是 tabbar 页面,请使用 wx.switchTab},serverUrl: 'http://3s.dkys.org:16912/wxapp'
})
2、index
index.wxml
<!--index.wxml-->
<view class="container"><view wx:if="{{userInfo==null}}"><button wx:if="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授权登录</button><view wx:else>请升级微信版本</view></view><view wx:if="{{userInfo!=null&&token==null}}"><button bindtap='regist'>请先注册</button> </view><view wx:if="{{userInfo!=null&&token!=null}}" class="userinfo"><image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image><text class="userinfo-nickname">{{userInfo.nickName}}</text><text class="userinfo-nickname">性别:{{userInfo.gender === 1 ? '男':'女'}}</text><text class="userinfo-nickname">城市:{{userInfo.city}}</text><text class="userinfo-nickname">省份:{{userInfo.province}}</text><text class="userinfo-nickname">国家:{{userInfo.country}}</text><text class="userinfo-nickname">使用语言:{{userInfo.language}}</text></view>
</view>
index.wxss
/**index.wxss**/
.userinfo {display: flex;flex-direction: column;align-items: center;
}.userinfo-avatar {width: 128rpx;height: 128rpx;margin: 20rpx;border-radius: 50%;
}.userinfo-nickname {color: #aaa;
}
index.js
//index.js
//获取应用实例
const app = getApp()Page({data: {userInfo: app.globalData.userInfo,token: app.globalData.token,//判断小程序的API,回调,参数,组件等是否在当前版本可用。canIUse: wx.canIUse('button.open-type.getUserInfo')},bindGetUserInfo: function(){var index = this;wx.getUserInfo({success: function (res) {app.globalData.userInfo = res.userInfo;index.setData({userInfo: res.userInfo,});index.checkToken();}});},onLoad: function () {console.log("index onLoad");// 查看是否授权this.checkAuth(); },regist: function(){wx.navigateTo({url: '../regist/regist'})},checkAuth: function(){console.log("index checkAuth");var index = this;wx.getSetting({success: function (res) {if (res.authSetting['scope.userInfo']) {wx.getUserInfo({success: function (res) {//用户已经授权过app.globalData.userInfo = res.userInfo;index.setData({userInfo: res.userInfo,});index.checkToken();}})}}})},checkToken: function(){var index = this;console.log("index checkToken");//初次登录需要验证token,即后台查不到这个openId的用户,就表示没有这个用户,跳到注册页面if (app.globalData.token == "" || app.globalData.token == null) {//验证用户信息wx.login({success: res => {// 发送 res.code 到后台换取 openId, sessionKey, unionIdif (res.code) {app.globalData.code = res.code;// 发送请求,服务端能获取到openid和unionid,之前登录过则可以获取到之前的用户信息。wx.request({url: app.serverUrl + '/login?code=' + res.code, //请求路径method: "GET",success: function (res) {//转到注册if (res.data == "") {wx.navigateTo({url: '../regist/regist'})} else {app.globalData.token = res.data;index.setData({token: app.globalData.token});}}})}}})} else {//有token就不管了console.log("用户验证通过");this.setData({token: app.globalData.token,userInfo: app.globalData.userInfo});console.log(app.globalData.token);console.log(app.globalData.userInfo);}},onShow:function(){console.log("show index");}
})
2、regist
regist.wxml
<view wx:if="{{!success}}"><view class='row'><view class='center'>您还未注册,请先注册!</view><view class='info'><input class= 'info-input1' bindinput="handleInputPhone" placeholder="请输入你的手机号" /></view><button class='button' bindtap='doGetCode' disabled='{{disabled}}' style="background-color:{{color}}" >{{text}}</button></view><view class='row'><view class='info'><input class= 'info-input' bindinput="handleVerificationCode" placeholder="请输入你的验证码" /></view></view><view class='row'><view class='info'><input type='password' class= 'info-input' bindinput="handleNewChanges" placeholder="请输入你的密码" /></view></view><view class='row'><view class='info'><input type='password' class= 'info-input' bindinput="handleNewChangesAgain" placeholder="请重新输入你的密码" /></view></view><button class='submit' bindtap='submit'>提交</button></view><view class = 'success' wx:if="{{success}}"><view class='cheer'><icon type="success" size="24"/> 恭喜您注册成功!</view><button type = "default" class = 'return' bindtap='return_home'>返回首页</button></view>
regist.wxss
page{background: #F0F0F0 ;
}
.row{margin-top: 20rpx;overflow: hidden;line-height: 100rpx;border-bottom: 1rpx solid #ccc;margin-left: 20rpx;margin-right: 20rpx;color: #777;background: #fff;}
.center{text-align: center;background-color: gainsboro
}
.info-input{height: 100rpx;margin-left: 50rpx;color: #777;float: left;
}
.info-input1{height: 100rpx;margin-left: 50rpx;color: #777;float: left;width: 420rpx;
}
.button{width: 200rpx;height: 70rpx;line-height: 70rpx;font-size: 28rpx;background: #33FF99;float: left;margin-left: 10rpx;margin-top: 15rpx;color: #FFFFFF;
}
.submit{margin-top: 50rpx;margin-left: 20rpx;margin-right: 20rpx;background: #00CCFF;color: #FFFFFF;
}
.success{background: #ffffff;}
.cheer{text-align: center;line-height: 400rpx;font-size: 60rpx;position: relative;
}
.return{margin: 20rpx;}
regist.js
var app = getApp();
Page({/*** 页面的初始数据*/data: {text: '获取验证码', //按钮文字currentTime: 61, //倒计时disabled: false, //按钮是否禁用phone: '', //获取到的手机栏中的值VerificationCode: '',Code: '',NewChanges: '',NewChangesAgain: '',success: false,state: ''},/*** 获取验证码*/return_home: function (e) {wx.navigateTo({url: '../index/index',})},handleInputPhone: function (e) {this.setData({phone: e.detail.value})},handleVerificationCode: function (e) {console.log(e);this.setData({Code: e.detail.value})},handleNewChanges: function (e) {console.log(e);this.setData({NewChanges: e.detail.value})},handleNewChangesAgain: function (e) {console.log(e);this.setData({NewChangesAgain: e.detail.value})},doGetCode: function () {var that = this;that.setData({disabled: true, //只要点击了按钮就让按钮禁用 (避免正常情况下多次触发定时器事件)color: '#ccc',})var phone = that.data.phone;var currentTime = that.data.currentTime //把手机号跟倒计时值变例成js值var warn = null; //warn为当手机号为空或格式不正确时提示用户的文字,默认为空var phone = that.data.phone;var currentTime = that.data.currentTime //把手机号跟倒计时值变例成js值var warn = null; //warn为当手机号为空或格式不正确时提示用户的文字,默认为空wx.request({url: app.serverUrl + '/checkPhoneRegist?phone=' + phone, //后端判断是否已被注册, 已被注册返回1 ,未被注册返回0method: "GET",header: {'content-type': 'application/x-www-form-urlencoded'},success: function (res) {that.setData({state: res.data})if (phone == '') {warn = "号码不能为空";} else if (phone.trim().length != 11 || !/^1[3|4|5|6|7|8|9]\d{9}$/.test(phone)) {warn = "手机号格式不正确";} //手机号已被注册提示信息else if (that.data.state == 1) { //判断是否被注册warn = "手机号已被注册";}else {wx.request({url: app.serverUrl + '/sendCodeMsg?phone=' + phone, //填写发送验证码接口method: "POST",data: {coachid: that.data.phone},header: {'content-type': 'application/x-www-form-urlencoded'},success: function (res) {console.log(res.data)that.setData({VerificationCode: res.data})//当手机号正确的时候提示用户短信验证码已经发送wx.showToast({title: '短信验证码已发送',icon: 'none',duration: 2000});//设置一分钟的倒计时var interval = setInterval(function () {currentTime--; //每执行一次让倒计时秒数减一that.setData({text: currentTime + 's', //按钮文字变成倒计时对应秒数})//如果当秒数小于等于0时 停止计时器 且按钮文字变成重新发送 且按钮变成可用状态 倒计时的秒数也要恢复成默认秒数 即让获取验证码的按钮恢复到初始化状态只改变按钮文字if (currentTime <= 0) {clearInterval(interval)that.setData({text: '重新发送',currentTime: 61,disabled: false,color: '#33FF99'})}}, 100);}})};//判断 当提示错误信息文字不为空 即手机号输入有问题时提示用户错误信息 并且提示完之后一定要让按钮为可用状态 因为点击按钮时设置了只要点击了按钮就让按钮禁用的情况if (warn != null) {wx.showModal({title: '提示',content: warn})that.setData({disabled: false,color: '#33FF99'})return;}}})},submit: function (e) {var that = thisif (this.data.Code == '') {wx.showToast({title: '请输入验证码',image: '/images/error.png',duration: 2000})return} else if (this.data.Code != this.data.VerificationCode) {wx.showToast({title: '验证码错误',image: '/images/error.png',duration: 2000})return}else if (this.data.NewChanges == '') {wx.showToast({title: '请输入密码',image: '/images/error.png',duration: 2000})return} else if (this.data.NewChangesAgain != this.data.NewChanges) {wx.showToast({title: '两次密码不一致',image: '/images/error.png',duration: 2000})return} else {var that = thisvar phone = that.data.phone;wx.login({success: res => {// 发送 res.code 到后台换取 openId, sessionKey, unionIdif (res.code) {wx.request({url: app.serverUrl + '/regist',method: "POST",data: {phone: phone,passwd: that.data.NewChanges,avatarUrl: app.globalData.userInfo.avatarUrl,nickName: app.globalData.userInfo.nickName,gender: app.globalData.userInfo.gender,city: app.globalData.userInfo.city,province: app.globalData.userInfo.province,country: app.globalData.userInfo.country,language: app.globalData.userInfo.language,code: res.code},header: {"content-type": "application/x-www-form-urlencoded"},success: function (res) {app.globalData.token = res.data;wx.showToast({title: '提交成功~',icon: 'loading',duration: 2000});that.setData({success: true})}})}}});}},/*** 用户点击右上角分享*/onShareAppMessage: function () {}
})
后台controller代码
@Slf4j
@RestController
@RequestMapping("/wxapp")
public class WxLoginController extends BaseController {/*** 假数据*/private static Map<String, WxUser> users = new HashMap<>();@Value("${weixin.secret.appid}")private String appid;@Value("${weixin.secret.key}")private String key;/*** 登录,验证数据库用户信息* <p>Title: login</p> * <p>Description: </p> * @param code* @return*/@RequestMapping("/login")@ResponseBodypublic String login(String code){String url = "https://api.weixin.qq.com/sns/jscode2session?" +"appid=" + appid +"&secret=" + key +"&js_code=" + code +"&grant_type=authorization_code";JSONObject object = JSONObject.parseObject(HttpClientUtils.sendGet(url));log.info(object.toJSONString());// 请求,获取openid或unionid// 从数据库中查询是否存储// 成功获取String unionid = (String) object.get("unionid");String openid = (String) object.get("openid");//用户唯一标识String token = openid+"-" + unionid;//通过token查找user,找到说明已注册,否则提示请注册boolean findUser = false;if(users.get(token)!=null) {findUser = true;}if(findUser) {return token;}else {return "";}}/*** 判断号码是否已被注册, 已被注册返回1 ,未被注册返回0* <p>Title: checkPhoneRegist</p> * <p>Description: </p> * @param phone* @return*/@RequestMapping("/checkPhoneRegist")@ResponseBodypublic Integer checkPhoneRegist(String phone){Integer result = 0;log.info("判断号码是否已被注册:"+phone+",结果:"+result);return result;}/*** 发送验证码* <p>Title: sendCodeMsg</p> * <p>Description: </p> * @param phone*/@RequestMapping("/sendCodeMsg")@ResponseBodypublic String sendCodeMsg(String phone){String result = "123456";log.info("发送验证码到:"+phone+",验证码:"+result);return result;}@RequestMapping("/regist")@ResponseBodypublic String regist(WxUser user){String url = "https://api.weixin.qq.com/sns/jscode2session?" +"appid=" + appid +"&secret=" + key +"&js_code=" + user.getCode() +"&grant_type=authorization_code";JSONObject object = JSONObject.parseObject(HttpClientUtils.sendGet(url));// 请求,获取openid或unionid// 从数据库中查询是否存储// 成功获取String unionid = (String) object.get("unionid");String openid = (String) object.get("openid");//用户唯一标识String token = openid+"-" + unionid;user.setToken(token);log.info("注册用户:"+user.toString());users.put(token, user);return token;}
}
遇到的问题:
验证用户所发送的code需要实时获取,不然会出现code been used的错误
微信小程序学习(一):开发准备、授权与验证相关推荐
- 微信小程序学习:开发注意点
11月2日更新: 微信小程序支持内嵌网页,新增 <web-view /> 组件调试支持: 传送门 <!-- wxml --> <!-- 指向微信公众平台首页的web-vi ...
- 微信小程序学习(1)-基础开发
学习微信小程序 微信小程序学习(1) 微信小程序学习(2) 文章目录 学习微信小程序 注册和初始化 小程序配置 tabbar导航栏 模板插样与WXML 循环渲染 条件渲染 模板 微信小程序脚本WXS ...
- 小程序 pagescrollto_微信小程序学习笔记(三)-- 首页及详情页开发
一.常用组件 在上一个章节中讲解了封装请求数据的模块,在此处请求轮播图的数据 1.首页轮播图数据的请求以及渲染 1.1 轮播图数据的请求 pages/home/home.js import 2 使用组 ...
- 微信小程序实现lot开发01 学习微信小程序 helloworld
最近走进一个新项目的任务里,主要的任务是实现用微信小程序利用websocket使用mqtt协议走网络控制继电器(其实在生活中这个技术已经普及了,我们用的充电桩扫码充电,我们学校里的饮水机扫码接水以及我 ...
- 微信小程序学习2:开发工具快速创建页面(pages)的四个文件(.js,.json,.wxml, .wxss)
微信小程序学习2:开发工具快速创建页面(pages)的四个文件(.js,.json,.wxml, .wxss) [1]首先在pages文件夹下创建一个页面文件夹,比如我打算创建个人中心,我创建一个ho ...
- 微信小程序学习(2)-云开发
微信小程序-云开发 微信小程序学习(1) 微信小程序学习(2) 文章目录 微信小程序-云开发 初始化+云函数的坑 云函数使用 老陈段子 小程序云存储 小程序云数据库 初始化插入 简单查询 更新数据 删 ...
- 上拉加载更多后台数据_6-7【微信小程序全栈开发课程】记录页面(七)--分页加载记录数据...
现在是一次性加载所有的记录数据,数据多的时候,会加载比较慢,所以我们改成分页加载,一次最多加载15条数据 每次拉倒底部都会自动加载下一页的数据,知道所有的数据加载完成 1.添加data变量 编辑rec ...
- 3.2【微信小程序全栈开发课程】登录功能(一)--实现登录功能
在本地搭建好后端环境之后,我们来实现登录功能 1.安装SDK插件 SDK插件用来获取用户的openId SDK是server端(也就是后端)的插件,帮助我们很容易的获取openId.openId是微信 ...
- 微信小程序学习笔记(1)
微信小程序学习笔记 1.小程序代码结构 2.逻辑层和视图层 3. 小程序的宿主环境(通信模型.运行机制.组件.API) 4. 数据绑定和事件绑定 1.小程序代码结构 当开发者新建一个工程时,项目文件包 ...
- 微信小程序学习之路(一)
微信小程序学习之路(一) 1.前言 2.准备工作 (1).IDE的选择 (2).微信小程序的文件说明 (3)开发者用户注册 3.编写 (1).新建项目 (2).代码的编写 3.代码的发布以及审核 1. ...
最新文章
- 知道了05后的隐藏技能之后,我酸了…​
- 2017级面向对象程序设计——团队作业1
- javascript学习系列(16):数组中的every方法
- document.write() 和writeln()方法注意事项
- Selenium WebDriver架构
- SSMS 2005 连接 SQL SERVER 2008问题
- 每周荐书:Web扫描、HTML 5、Python(评论送书)
- flink的jar包和服务器的包冲突解决方案
- 遭遇nat.exe,socks.exe,USP10.dll,BOSC.dll,kb080387.CNT,~ctwxw.txt等1
- DEDE源码分析与学习--index.php文件解读
- C语言中的取绝对值函数
- C++ qt实现打开关闭状态按钮
- iia期是第几期_IIa期和IIb期的定义,区别
- java宠物医院,基于SSM框架的JAVA宠物医院管理信息系统,源码分享
- echarts最新版做中国地图(详细版+避雷版)
- 计算机组成原理(王道精讲课 + 天勤高分笔记) note
- 用户故事地图学习笔记(四):如何创建用户故事地图
- 什么情况,听说网络安全工程师已经没落?
- android是否支持 ipv6,判断你的网络是否支持IPv6
- 抢占智能制造“制高点” 个性化生产不可或缺
热门文章
- 健康程序员:五分钟与鼠标手说再见
- 手机照片局部放大镜_想让旅行照与众不同?堪比PS的手机修图神器了解一下!...
- 国产deepin深度操作系统20.2.3 发布
- AndroidStudio运行app,会装上多个app
- MySQL编码致使varchar类型不区分大小写
- qt show widget_Qt Widget不显示
- Python实现发送邮件(实现单发/群发邮件验证码)
- ​PBlaze6上新!Memblaze发布首款基于长存颗粒的企业级SSD
- 【36C++STL-常用容器----5、stack容器详解】
- dnf手游服务器维护时效,DNF手游延期到2021年2月11日是真的吗 延期日期详细说明...