微信小程序学习(一):开发准备、授权与验证

        今天学习了下小程序,感觉与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, unionId
          if (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 ,未被注册返回0
      method: "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 = this
    if (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 = this
      var phone = that.data.phone;
      wx.login({
        success: res => {
          // 发送 res.code 到后台换取 openId, sessionKey, unionId
          if (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")
    @ResponseBody
    public 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")
    @ResponseBody
    public Integer checkPhoneRegist(String phone)
    {
		Integer result = 0;
		log.info("判断号码是否已被注册:"+phone+",结果:"+result);
        return result;
    }
	
	/**
	 * 发送验证码
	 * <p>Title: sendCodeMsg</p>  
	 * <p>Description: </p>  
	 * @param phone
	 */
	@RequestMapping("/sendCodeMsg")
    @ResponseBody
    public String sendCodeMsg(String phone)
    {
		String result = "123456";
		log.info("发送验证码到:"+phone+",验证码:"+result);
        return result;
    }
	
	@RequestMapping("/regist")
    @ResponseBody
    public 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的错误

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值