一、需求分析
1、前言
基於微信小程序雲開發之下的新用戶註冊,用戶登錄的概念其實已經不像傳統的網站開發,僅需要幾十行代碼就可以做到新用戶註冊入庫、老用戶信息獲取(登錄)的功能。更加快速的建立小程序內的用戶體系。
2、思路分析
用戶 每次打開小程序,在app.js檢測用戶是否登錄,並且將用戶信息和登錄狀態保存到緩存和app.globalData數據中;
在需要用戶登錄的頁面,在按鈕或者進入頁面時,檢測用戶是否登錄,如果沒有登錄,跳轉到用戶中心,引導用戶登錄。
二、雲開發實現
1、創建用戶表tb_user(已完成)
只需要在雲端創建一個空表(集合)
欄位名 |
數據類型 |
內容模型 |
含義 |
備註 |
_id |
string |
|
主鍵 |
系統生成 |
openId |
string |
#單行字符串 |
用戶微信openId |
|
phone |
string |
#電話號碼 |
手機號碼 |
|
nickName |
string |
#單行字符串 |
微信暱稱 |
'':非授權用戶,不為空:授權用戶 |
gender |
number |
#數字 |
性別 |
|
avatarUrl |
string |
#圖片.HTTPS |
微信頭像 |
|
status |
number |
#布爾 |
狀態 |
0:正常,1:禁止 |
isAdmin |
boolean |
#布爾 |
是否是管理員 |
false:不是,true:是 |
create_time |
number |
#日期與時間.時間戳 |
創建時間 |
|
update_time |
number |
#日期與時間.時間戳 |
修改時間 |
|
last_login_time |
number |
#日期與時間.時間戳 |
最後登錄時間 |
|
last_login_ip |
string |
|
|
|
2、修改集合名配置文件 (已完成)
雲函數 Router目錄中修改文件 config/tableConfig.js,添加USER表輸出
// 集合名 ,表名千萬不要有空格,不然會報錯
module.exports = {
BANNER : 'tb_banner', //輪播表
THEME : 'tb_theme', //主題表
PRODUCT: 'tb_product', //商品信息表
PRODUCT_THEME : 'tb_product_theme', //專題商品表
PRODUCT_CATEGORY : 'tb_product_category', //商品分類表
ORDER:"tb_order", //訂單表
USER:"tb_user" //用戶表
}
3、修改集合欄位配置類(已完成)
在 fields 文件夾新建 userField.js
// tb_user 指定返回結果中記錄需返回的欄位
module.exports = {
USERFIELD: {
_id:false,
nickName: true,
gender: true,
avatarUrl:true,
status:true
}
}
4、業務層實現
1)、service層
用戶登錄方法,如果沒有用戶,添加記錄,如果有記錄,修改用戶登錄ip
在雲函數 service 文件夾創建 userService.js。
const model = require('../models/BaseModel.js')
const { USER } = require('../config/tableConfig.js')
// 返回欄位處理
const { USERFIELD } = require('../fields/userField.js')
/**
* 用戶登錄方法
* @return
*/
const userLogin = async (ip,openId,userInfo) => {
//1、根據openId查找資料庫中的記錄數
let options={}
options.openId= openId
const total=await model.count(USER,options)
let current_time =(new Date()).getTime() //當前時間戳 ,毫秒
if (total) {
//更新用戶信息
let condition={}
condition.openId=openId
let data={}
data.nickName=userInfo.nickName
data.gender=userInfo.gender
data.avatarUrl=userInfo.avatarUrl
data.update_time=current_time
data.last_login_time=current_time
data.last_login_ip=ip
await model.updatebywhere(USER,condition,data)
} else {
//插入用戶數據
let data={}
data.nickName=userInfo.nickName
data.gender=userInfo.gender
data.avatarUrl=userInfo.avatarUrl
data.openId=openId
data.create_time=current_time
data.update_time=current_time
data.last_login_time=current_time
data.last_login_ip=ip
data.status=0
data.isAdmin=0
await model.add(USER,data)
}
//返回用戶信息
const data= await model.query(USER,USERFIELD,options)
return data[0]
}
/**
* 用戶信息初始化方法,將用戶的openid值記錄到用戶表中,並返回用戶信息
* @return
*/
const userInit = async (ip,openId) => {
//1、根據openId查找資料庫中的記錄數
let options={}
options.openId= openId
const total=await model.count(USER,options)
let current_time =(new Date()).getTime() //當前時間戳 ,毫秒
if (total) {
//更新用戶信息
let condition={}
condition.openId=openId
let data={}
data.last_login_time=current_time
data.last_login_ip=ip
await model.updatebywhere(USER,condition,data)
} else {
//插入用戶數據
let data={}
data.openId=openId
data.nickName='' //暱稱設置為空字符串,方便以後查找授權用戶
data.create_time=current_time
data.update_time=current_time
data.last_login_time=current_time
data.last_login_ip=ip
data.status=0
data.isAdmin=false
await model.add(USER,data)
}
//返回用戶信息
const data= await model.query(USER,USERFIELD,options)
return data[0]
}
module.exports = {
userLogin,
userInit
}
2)、controller層
在 controller 文件夾新建 userController.js
// 返回工具類
const returnUtil = require('../utils/ReturnUtil.js')
// 用戶業務層
const userService = require('../service/userService.js')
// 用戶登錄
function userLogin(ip,openId,userInfo){
return async function (ctx, next) {
ctx.data = {}
const data=await userService.userLogin(ip,openId,userInfo) // 取出數據
ctx.data = data
ctx.body = await returnUtil.success(ctx)
await next();
}
}
// 用戶信息初始化
function userInit(ip,openId){
return async function (ctx, next) {
ctx.data = {}
const data=await userService.userInit(ip,openId) // 取出數據
ctx.data = data
ctx.body = await returnUtil.success(ctx)
await next();
}
}
module.exports = {
userLogin,
userInit
}
5、入口文件
注意這裡需要傳遞openId和userInfo參數,
其中的ip來自於雲端 ,
openId來自於雲端,
userInfo來自於event.userInfo
/******************** 用戶登錄 *******************************/
app.router('user/userLogin', userController.userLogin(ip, openId,options.userInfo));
// 雲函數入口文件
const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router');
const indexController = require('./controller/indexController')
const roomController = require('./controller/roomController')
const userController = require('./controller/userController')
cloud.init()
// 雲函數入口函數
exports.main = async (event, context) => {
const app = new TcbRouter({ event });
// app.use 表示該中間件會適用於所有的路由
app.use(async (ctx, next) => {
ctx.data = {};
await next(); // 執行下一中間件
});
let options = {}
options = event.data // event.data包含前台傳過來的參數
//記錄用戶ip地址
const wxContext = cloud.getWXContext();
const ip = wxContext.CLIENTIP ? wxContext.CLIENTIP : wxContext.CLIENTIPV6
//記錄用戶openid
const openId=event.userInfo.openId
/*************************** 首頁 *****************************************/
app.router('index/getBanner', indexController.getBanner()) // 獲取輪播
app.router('index/getRoom', indexController.getRoom()) // 獲取房間信息
/*************************** 房間信息 *************************************/
app.router('room/getRoomById', roomController.getRoomById(options._id)) // 獲取房間詳情信息
/******************** 用戶登錄 *******************************/
app.router('user/userLogin', userController.userLogin(ip, openId,options.userInfo))
app.router('user/userInit', userController.userInit(ip, openId))
/*************************** 訂單 *****************************************/
return app.serve();
}
三、前端使用
1、封裝api_user.js
在前端 service 文件夾新建 api_user.js
import { myCloudrequest } from '../utils/cloudRequest.js'
// 用戶登錄
const userLogin=(userInfo)=>{
let data={userInfo} //傳遞的是一個對象
//返回的是一個promise對象
return myCloudRequest.request("user/userLogin",data)
}
// 用戶信息初始化
const userInit=()=>{
//返回的是一個promise對象
return myCloudRequest.request("user/userInit")
}
module.exports = {
userLogin,
userInit
}
2、在app.js
全局保存用戶信息,和用戶登錄狀態
// app.js
import {userInit} from '/service/api_user'
let userInfo =wx.getStorageSync("userInfo") || {} //用戶信息
let isLogin = JSON.stringify(userInfo) != "{}" //用戶登錄狀態
App({
// 引入`towxml3.0`解析方法
towxml:require('/towxml/index'),
onLaunch: async function () {
if (!wx.cloud) {
console.error('請使用 2.2.3 或以上的基礎庫以使用雲能力');
} else {
wx.cloud.init({
// env 參數說明:
// env 參數決定接下來小程序發起的雲開發調用(wx.cloud.xxx)會默認請求到哪個雲環境的資源
// 此處請填入環境 ID, 環境 ID 可打開雲控制台查看
// 如不填則使用默認環境(第一個創建的環境)
env: 'cloud1-********',
traceUser: true,
});
}
this.globalData = {
userInfo: userInfo,
isLogin: isLogin,
}
//將用戶的openid值記錄到用戶表中,並返回用戶信息
const res = await userInit()
wx.setStorageSync("userInfo", res.data) //將後端返回的用戶信息保存到緩存中
this.globalData.userInfo = res.data //將後端返回的用戶信息保存到app中
}
});
3、在需要判斷用戶登錄的頁面
比如提交訂單頁面的提交表單方法裡面,根據app裡面的isLogin進行判斷用戶是否登錄
let app = getApp()
/**提交訂單 **/
confirm: async function () {
//首先判斷用戶是否登錄
if (!app.globalData.isLogin) {
await showModal({content:'請先登錄',showCancel:false})
wx.switchTab({
url: '../mine/mine',
})
return
}
。。。
}