From caac642120205688012d36f9f3dedb4b8020b7bb Mon Sep 17 00:00:00 2001 From: H1d3rOne Date: Mon, 9 Mar 2026 00:10:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BE=AE=E4=BF=A1=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E5=8A=9F=E8=83=BD=EF=BC=8C=E9=A6=96=E6=AC=A1=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E8=87=AA=E5=8A=A8=E4=BF=9D=E5=AD=98=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端实现: - 修改auth.vue登录逻辑 - 使用getUserProfile获取微信用户信息 - 获取用户昵称和头像URL - 调用uni.login获取code - 将code和用户信息发送到后端 - 登录成功后保存完整用户信息到本地 后端实现: - 修改UserController登录接口 - 接收code参数而不是openId - 调用微信API jscode2session获取openId - 使用RestTemplate调用微信接口 - 支持配置微信appid和secret - 首次登录自动创建用户并保存到数据库 配置文件: - application.properties新增微信配置项 - wechat.appid: 微信小程序AppID - wechat.secret: 微信小程序AppSecret 功能特点: - 首次使用小程序自动获取微信用户信息 - 用户信息保存到user_info表 - 支持游客模式(未配置微信参数时) - 完整的错误处理和日志记录 --- .../java/xuan/controller/UserController.java | 31 ++++++- src/main/resources/application.properties | 4 + xuan-deduct-uniapp/src/pages/auth/auth.vue | 81 ++++++++++++------- 3 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/main/java/xuan/controller/UserController.java b/src/main/java/xuan/controller/UserController.java index 702ae75..31f1155 100644 --- a/src/main/java/xuan/controller/UserController.java +++ b/src/main/java/xuan/controller/UserController.java @@ -1,7 +1,9 @@ package xuan.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; import xuan.entity.UserInfo; import xuan.service.UserInfoService; @@ -16,14 +18,41 @@ public class UserController { @Autowired private UserInfoService userInfoService; + @Value("${wechat.appid:}") + private String appId; + + @Value("${wechat.secret:}") + private String appSecret; + @PostMapping("/login") public Map login(@RequestBody Map params) { Map result = new HashMap<>(); try { - String openId = params.get("openId") != null ? params.get("openId").toString() : null; + String code = params.get("code") != null ? params.get("code").toString() : null; String nickname = params.get("nickname") != null ? params.get("nickname").toString() : "微信用户"; String avatarUrl = params.get("avatarUrl") != null ? params.get("avatarUrl").toString() : ""; + String openId = null; + + if (code != null && !code.isEmpty() && appId != null && !appId.isEmpty() && appSecret != null && !appSecret.isEmpty()) { + String url = String.format( + "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", + appId, appSecret, code + ); + + try { + RestTemplate restTemplate = new RestTemplate(); + @SuppressWarnings("unchecked") + Map wxResult = restTemplate.getForObject(url, Map.class); + + if (wxResult != null && wxResult.containsKey("openid")) { + openId = (String) wxResult.get("openid"); + } + } catch (Exception e) { + System.err.println("调用微信API失败: " + e.getMessage()); + } + } + if (openId == null || openId.isEmpty()) { openId = "guest_" + System.currentTimeMillis(); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 01059ce..b9e0742 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -15,3 +15,7 @@ spring.jpa.properties.hibernate.format_sql=true # Logging logging.level.xuan=DEBUG + +# WeChat Mini Program Configuration +wechat.appid=your_wechat_appid_here +wechat.secret=your_wechat_secret_here diff --git a/xuan-deduct-uniapp/src/pages/auth/auth.vue b/xuan-deduct-uniapp/src/pages/auth/auth.vue index b930004..fe0c666 100644 --- a/xuan-deduct-uniapp/src/pages/auth/auth.vue +++ b/xuan-deduct-uniapp/src/pages/auth/auth.vue @@ -85,37 +85,64 @@ export default { this.loading = true - uni.login({ - success: (loginRes) => { - if (loginRes.code) { - const openId = loginRes.code - - api.userApi.loginOrRegister({ - openId: openId, - nickname: this.nickname || '微信用户', - avatarUrl: this.avatarUrl - }).then(res => { - this.loading = false - if (res.success) { - uni.setStorageSync('userId', res.data.userId) - uni.setStorageSync('userInfo', JSON.stringify(res.data)) + uni.getUserProfile({ + desc: '用于完善用户资料', + success: (profileRes) => { + console.log('获取用户信息成功:', profileRes) + + const userInfo = profileRes.userInfo + const nickname = userInfo.nickName || this.nickname || '微信用户' + const avatarUrl = userInfo.avatarUrl || this.avatarUrl + + uni.login({ + success: (loginRes) => { + if (loginRes.code) { + console.log('获取code成功:', loginRes.code) - uni.showToast({ title: '登录成功', icon: 'success' }) - - setTimeout(() => { - uni.switchTab({ url: '/pages/index/index' }) - }, 1500) + api.userApi.loginOrRegister({ + code: loginRes.code, + nickname: nickname, + avatarUrl: avatarUrl + }).then(res => { + this.loading = false + if (res.success) { + console.log('登录成功:', res.data) + uni.setStorageSync('userId', res.data.userId) + uni.setStorageSync('userInfo', JSON.stringify(res.data)) + uni.setStorageSync('userCoins', res.data.coins || 10) + uni.setStorageSync('vipLevel', res.data.vipLevel || 0) + uni.setStorageSync('username', res.data.username || res.data.nickname) + uni.setStorageSync('userAvatar', res.data.avatarUrl) + + uni.showToast({ title: '登录成功', icon: 'success' }) + + setTimeout(() => { + uni.switchTab({ url: '/pages/index/index' }) + }, 1500) + } else { + uni.showToast({ title: res.error || '登录失败', icon: 'none' }) + } + }).catch((err) => { + this.loading = false + console.error('登录失败:', err) + uni.showToast({ title: '网络错误', icon: 'none' }) + }) } else { - uni.showToast({ title: res.error || '登录失败', icon: 'none' }) + this.loading = false + uni.showToast({ title: '获取授权失败', icon: 'none' }) } - }).catch(() => { + }, + fail: (err) => { this.loading = false - uni.showToast({ title: '网络错误', icon: 'none' }) - }) - } else { - this.loading = false - uni.showToast({ title: '获取授权失败', icon: 'none' }) - } + console.error('uni.login失败:', err) + uni.showToast({ title: '登录失败', icon: 'none' }) + } + }) + }, + fail: (err) => { + this.loading = false + console.error('getUserProfile失败:', err) + uni.showToast({ title: '获取用户信息失败', icon: 'none' }) } }) },