文章目录
一、讲解视频
教学视频地址: 视频地址
二、小程序前端代码
javascript
// pages/profile/profile.js
import api from "../../utils/api";
import { myRequest } from "../../utils/request";
import Notify from "@vant/weapp/notify/notify";
import Cache from "../../utils/cache";
import Tool from "../../utils/tool";
Page({
/**
* 页面的初始数据
*/
data: {
isLogin: false,
userInfo: {
username: "还未登录,请先登录!",
headPic: api.BASE_URL + "/photo/view?filename=common/mine_normal.jpg"
},
basePhotoUrl: api.BASE_URL + "/photo/view?filename=",
editUser: {},
profileDialogVisible: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.validateLoginState();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
this.validateLoginState();
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
// 预览图片
previewHead: function () {
let userInfo = this.data.userInfo;
let basePhotoUrl = this.data.basePhotoUrl;
wx.previewImage({
current: userInfo.headPic === userInfo.wxHeadPic ? userInfo.wxHeadPic : basePhotoUrl + userInfo.headPic,
urls: [userInfo.headPic === userInfo.wxHeadPic ? userInfo.wxHeadPic : basePhotoUrl + userInfo.headPic]
})
},
// 验证登录状态
validateLoginState: async function() {
wx.showLoading({
title: "获取登录信息...",
mask: true
})
const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
if(Tool.isEmpty(loginUser)) {
wx.hideLoading();
return;
}
const res = await myRequest({
url: api.BASE_URL + "/app/user/get_login_user",
method: "POST",
data: {
token: loginUser
}
});
if(res.data.code === 0) {
this.setData({
userInfo: res.data.data,
isLogin: true,
editUser: res.data.data
})
}
wx.hideLoading();
wx.stopPullDownRefresh();
},
// 登录操作
getLoginUser: function() {
wx.showLoading({
title: "正在登录...",
mask: true
})
wx.getUserProfile({
desc: "获取用户相关信息",
success: res => {
if(res.errMsg === "getUserProfile:ok") {
let username = res.userInfo.nickName;
let headPic = res.userInfo.avatarUrl;
wx.login({
success: async res => {
if (res.errMsg === "login:ok") {
// 调用后端接口,验证用户数据
const response = await myRequest({
url: api.BASE_URL + "/app/user/wx_login",
method: "POST",
data: {
wxHeadPic: headPic,
wxUsername: username,
code: res.code
}
});
if(response.data.code === 0) {
Notify({ type: "success", message: response.data.msg, duration: 1000 });
Cache.setCache(getApp().globalData.SESSION_KEY_LOGIN_USER, response.data.data.token, 3600);
this.setData({
userInfo: response.data.data,
editUser: response.data.data,
isLogin: true
});
} else {
Notify({ type: "danger", message: response.data.msg, duration: 2000 });
}
} else {
wx.showToast({
icon: "error",
title: "登录失败"
});
}
wx.hideLoading();
},
fail: res => {
wx.showToast({
icon: "error",
title: "登录失败"
});
wx.hideLoading();
}
})
} else {
wx.showToast({
icon: "error",
title: "获取用户失败"
});
wx.hideLoading();
}
},
fail: res => {
wx.showToast({
icon: "error",
title: "获取用户失败"
});
wx.hideLoading();
}
})
},
// 登录验证
authUser: function() {
const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
if(Tool.isEmpty(loginUser)) {
Notify({ type: "danger", message: "请先登录!", duration: 2000 });
return true;
} else {
return false;
}
},
// 退出登录
logout: async function() {
const loginUser = Cache.getCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
const res = await myRequest({
url: api.BASE_URL + "/app/user/logout",
method: "POST",
data: {
token: loginUser
}
});
if(res.data.code === 0) {
Notify({ type: "success", message: res.data.msg, duration: 1000 });
}
Cache.removeCache(getApp().globalData.SESSION_KEY_LOGIN_USER);
this.setData({isLogin: false, userInfo: {
username: "还未登录,请先登录!",
headPic: api.BASE_URL + "/photo/view?filename=common/mine_normal.jpg"
}});
},
})
三、后端Java代码
<!--引入http连接依赖-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
java
package com.yjq.programmer.service.impl;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yjq.programmer.bean.CodeMsg;
import com.yjq.programmer.dao.UserMapper;
import com.yjq.programmer.domain.User;
import com.yjq.programmer.domain.UserExample;
import com.yjq.programmer.dto.LoginDTO;
import com.yjq.programmer.dto.PageDTO;
import com.yjq.programmer.dto.ResponseDTO;
import com.yjq.programmer.dto.UserDTO;
import com.yjq.programmer.enums.RoleEnum;
import com.yjq.programmer.service.IUserService;
import com.yjq.programmer.utils.CommonUtil;
import com.yjq.programmer.utils.CopyUtil;
import com.yjq.programmer.utils.UuidUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author 杨杨吖
* @QQ 823208782
* @WX yjqi12345678
* @create 2023-09-25 17:08
*/
@Service
@Transactional
public class UserServiceImpl implements IUserService {
@Resource
private UserMapper userMapper;
@Resource
private StringRedisTemplate stringRedisTemplate;
private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
// 填写上你的AppID,如何获取AppID自行百度,这步骤很简单
private final static String APP_ID = "wxc41c88e07f3f1bd7";
// 填写上你的AppSecret,如何获取AppSecret自行百度,这步骤很简单
private final static String APP_SECRET = "99a06dc0d1e21d797a9915baca08c872";
// 微信小程序登录校验请求地址
private final static String LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
/**
* 小程序授权登录验证
* @param userDTO
* @return
*/
@Override
public ResponseDTO<UserDTO> appWxLogin(UserDTO userDTO) {
String url = LOGIN_URL + "?appid=" + APP_ID + "&secret="+ APP_SECRET + "&grant_type=authorization_code&js_code=" + userDTO.getCode();
HttpClient client = HttpClients.createDefault(); // 创建默认http连接
HttpGet getRequest = new HttpGet(url);// 创建一个post请求
LoginDTO loginDTO = new LoginDTO();
try {
// 用http连接去执行get请求并且获得http响应
HttpResponse response = client.execute(getRequest);
// 从response中取到响实体
HttpEntity entity = response.getEntity();
// 把响应实体转成文本
String html = EntityUtils.toString(entity);
loginDTO = JSON.parseObject(html, LoginDTO.class);
if(null == loginDTO.getErrcode()) {
userDTO.setWxId(loginDTO.getOpenid());
} else {
return ResponseDTO.errorByMsg(CodeMsg.USER_WX_LOGIN_ERROR);
}
} catch (Exception e) {
e.printStackTrace();
return ResponseDTO.errorByMsg(CodeMsg.USER_WX_LOGIN_ERROR);
}
// 使用微信openId查询是否有此用户
UserExample userExample = new UserExample();
userExample.createCriteria().andWxIdEqualTo(userDTO.getWxId());
List<User> userList = userMapper.selectByExample(userExample);
if(null != userList && userList.size() > 0) {
// 已经存在用户信息,读取数据库中用户信息
User user = userList.get(0);
userDTO = CopyUtil.copy(user, UserDTO.class);
} else {
// 数据库中不存在,注册用户信息
User user = CopyUtil.copy(userDTO, User.class);
// 自定义工具类,生成8位uuid
user.setId(UuidUtil.getShortUuid());
user.setUsername(user.getWxUsername());
user.setHeadPic(user.getWxHeadPic());
user.setRoleId(RoleEnum.USER.getCode());
if(userMapper.insertSelective(user) == 0) {
return ResponseDTO.errorByMsg(CodeMsg.USER_REGISTER_ERROR);
}
// domain转dto 这步不是必须的,我项目中需要这步
userDTO = CopyUtil.copy(user, UserDTO.class);
}
userDTO.setToken(UuidUtil.getShortUuid());
stringRedisTemplate.opsForValue().set("USER_" + userDTO.getToken(), JSON.toJSONString(userMapper.selectByPrimaryKey(userDTO.getId())), 3600, TimeUnit.SECONDS);
return ResponseDTO.successByMsg(userDTO, "登录成功!");
}
/**
* 获取当前登录用户
* @param token
* @return
*/
@Override
public ResponseDTO<UserDTO> getLoginUser(String token) {
if(CommonUtil.isEmpty(token)){
return ResponseDTO.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
}
String value = stringRedisTemplate.opsForValue().get("USER_" + token);
if(CommonUtil.isEmpty(value)){
return ResponseDTO.errorByMsg(CodeMsg.USER_SESSION_EXPIRED);
}
UserDTO selectedUserDTO = JSON.parseObject(value, UserDTO.class);
return ResponseDTO.success(CopyUtil.copy(userMapper.selectByPrimaryKey(selectedUserDTO.getId()), UserDTO.class));
}
/**
* 退出登录操作
* @param userDTO
* @return
*/
@Override
public ResponseDTO<Boolean> logout(UserDTO userDTO) {
if(!CommonUtil.isEmpty(userDTO.getToken())){
// token不为空 清除redis中数据
stringRedisTemplate.delete("USER_" + userDTO.getToken());
}
return ResponseDTO.successByMsg(true, "退出登录成功!");
}
}
四、备注
大家要跟着我的教学视频去配套着看代码,了解整个登录流程的实现思路最重要! 以上是我列出的主要实现代码,页面实现那些根据自己需求去实现,我这就不贴了,如有其他遗漏代码,博客评论区可以提出,我会及时补充!