【慧游鲁博】【10】全端优化用户信息存储+网页端user模块与后端对接
文章目录
- (小程序端)
 - 本次更新
 - 1. 数据库与实体类调整
 - 1.1 数据库表修改
 - 1.2 Java 实体类 `User` 调整
 
- 2. 后端接口修改
 - 2.1 更新 `UserVO`(视图对象)
 - 2.2 修改 `getUserInfo` 方法
 
- 3. 小程序端存储优化(Pinia 状态管理)
 - 3.1 重构 `member.js`
 - 3.2 持久化配置
 
- 4. 登录逻辑优化
 - 4.1 修改 `handleLogin` 方法
 - 4.2 获取用户信息的策略
 
- (网页端)
 - 本次更新
 - 网页端调整
 
- 网页端关键实现
 - 1. API服务 (user.js)
 - 1. 模块结构
 - 2. 依赖分析
 - 3. API 方法详解
 - 3.1 用户登录 (`login`)
 - 3.2 获取用户信息 (`getUserInfo`)
 - 3.3 更新用户信息 (`updateUserInfo`)
 - 3.4 更新用户头像 (`updateAvatar`)
 - 3.5 更新用户密码 (`updatePassword`)
 - 3.6 获取用户列表 (`getUserList`)
 
- 2. Token管理 (token.js)
 - setToken
 - clearToken
 
- 3. 用户信息组件 (UserInfo.vue)
 - 字段与后端 UserVO 匹配
 - 编辑逻辑优化
 - 可编辑字段控制
 - 编辑状态管理
 - 数据恢复机制
 - 保存逻辑
 
- 与API的交互
 
- 4. 登录组件 (Login.vue)
 - 表单验证修改
 - 验证规则配置
 - 自定义验证方法
 
- 登录逻辑实现
 - 与API的交互
 
(小程序端)
本次更新
在开发微信小程序等移动应用时,用户信息的存储和安全性是需要重点考虑的问题。本次优化通过最小化客户端存储的用户数据,仅保留必要的 id 和 role,既保证了功能完整性,又提升了安全性。

本文将围绕本次修改,详细介绍:
- 数据库与实体类调整(添加 
role字段) - 后端接口修改(
UserVO和getUserInfo方法) - 小程序端存储优化(
Pinia状态管理调整) - 登录逻辑优化(仅存储 
id和role) 
1. 数据库与实体类调整
1.1 数据库表修改
在 users 表中新增 role 字段,用于区分用户权限:
ALTER TABLE users
ADD COLUMN role INTEGER NOT NULL DEFAULT 1;  -- 默认普通用户(1),0表示管理员
 
1.2 Java 实体类 User 调整
 
在 User.java 中添加 role 字段:
@Data
@TableName("users")
public class User {// 其他字段...@TableField("role")private Integer role; // 0=管理员,1=普通用户
}
 
2. 后端接口修改
2.1 更新 UserVO(视图对象)
 
在 UserVO.java 中添加 role 字段,确保返回给小程序端的数据包含权限信息:
@Data
public class UserVO {// 其他字段...private Integer role; // 0=管理员,1=普通用户
}
 
2.2 修改 getUserInfo 方法
 
确保 getUserInfo 返回的数据包含 role:
@Override
public Result<UserVO> getUserInfo() {// 查询用户...UserVO userVO = new UserVO();userVO.setId(user.getId());// 其他字段...userVO.setRole(user.getRole()); // 新增 role 字段return Result.success(userVO);
}
 
3. 小程序端存储优化(Pinia 状态管理)
3.1 重构 member.js
 
优化 useMemberStore,仅存储 userId 和 userRole:
export const useMemberStore = defineStore('member', () => {const profile = ref({token: '',      // 登录令牌userId: null,   // 仅存储用户IDuserRole: null  // 仅存储用户角色});const setUserBasicInfo = (userInfo) => {profile.value.userId = userInfo?.id || null;profile.value.userRole = userInfo?.role ?? null;};// 其他方法...
});
 
3.2 持久化配置
仍然使用 uni-app 的本地存储,但数据量更小:
persist: {storage: {getItem(key) { return uni.getStorageSync(key); },setItem(key, value) { uni.setStorageSync(key, value); },},
}
 
4. 登录逻辑优化
4.1 修改 handleLogin 方法
 
登录成功后,仅存储 id 和 role:
async handleLogin() {try {const res = await post('/user/login', { ... });const memberStore = useMemberStore();memberStore.setToken(res);// 仅存储 id 和 roleconst userInfoRes = await get('/user/getUserInfo');memberStore.setUserBasicInfo({id: userInfoRes.id,role: userInfoRes.role});// 跳转逻辑...} catch (error) {// 错误处理...}
}
 
4.2 获取用户信息的策略
- 需要完整信息时(如个人中心页面),再通过 
userId调用接口获取。 - 权限检查 直接使用 
getUserRole()判断:if (memberStore.getUserRole() === 0) {// 管理员逻辑 } 
(网页端)
本次更新
- ✅ 用户登录/退出流程完整
 - ✅ 个人信息显示与编辑功能完善
 - ✅ 前后端数据无缝对接
 - ✅ 存储管理安全可靠
 




网页端调整
(1) API 请求 (user.js)
- 标准化请求方式(与 
story.js保持一致):- 使用 
instance替代request - 改为 函数式导出(如 
export function login(data)) 
 - 使用 
 - 接口调整: 
getUserInfo()不再需要userId(从 Token 获取当前用户)updateUserInfo()仅允许修改nickname和email
 
(2) Token 管理 (token.js)
- 新增 
clearToken():- 清空 Pinia 的 
token状态 - 移除 
localStorage中的 token - 额外清除 Pinia 持久化存储(避免插件自动恢复)
 
 - 清空 Pinia 的 
 
(3) 登录页 (Login.vue)
- 表单验证同步后端规则: 
- 用户名/密码长度:5-16位
 - 禁止空白字符(通过 
validateNoWhitespace自定义校验) 
 - 真实登录逻辑: 
- 调用 
login()API - 成功后将 token 存入 Pinia 和 
localStorage 
 - 调用 
 
(4) 用户信息页 (UserInfo.vue)
- 字段匹配后端 
UserVO:- 显示 
nickname而非realName - 新增 
avatarUrl头像预览 - 角色显示为 “管理员” 或 “普通用户”(根据 
role: 0 | 1) 
 - 显示 
 - 编辑逻辑优化: 
- 仅允许修改 
nickname和email - 取消编辑时恢复原始数据
 
 - 仅允许修改 
 
(5) 退出登录
- 彻底清除所有存储:
tokenStore.clearToken(); // 清空 Pinia + localStorage userInfoStore.$reset(); // 重置用户信息 router.push('/login'); // 跳转登录页 
网页端关键实现
1. API服务 (user.js)
user.js 是一个用户相关的 API 封装模块,它基于 request.js 提供的 axios 实例封装了一系列与用户相关的接口。
1. 模块结构
user.js 导出了 6 个函数,分别对应不同的用户操作:
login- 用户登录getUserInfo- 获取用户详细信息updateUserInfo- 更新用户基本信息updateAvatar- 更新用户头像updatePassword- 更新用户密码getUserList- 获取用户列表(分页)
2. 依赖分析
模块顶部导入了 request.js 中创建的 axios 实例:
import instance from '@/utils/request';
 
3. API 方法详解
3.1 用户登录 (login)
 
export function login(data) {return instance({url: '/user/login',method: 'post',data});
}
 
- 功能:用户登录接口
 - 方法:POST
 - 参数:通过 
data传递登录表单数据(如用户名和密码) - 特点:不需要 token,是获取 token 的入口
 
3.2 获取用户信息 (getUserInfo)
 
export function getUserInfo() {return instance({url: '/user/getUserInfo',method: 'get'});
}
 
- 功能:获取当前登录用户的详细信息
 - 方法:GET
 - 特点:需要 token(通过请求拦截器自动添加)
 
3.3 更新用户信息 (updateUserInfo)
 
export function updateUserInfo(data) {return instance({url: '/user/updateUserInfo',method: 'put',data});
}
 
- 功能:更新用户基本信息
 - 方法:PUT
 - 参数:通过 
data传递更新后的用户信息 - 特点:需要 token,使用 PUT 方法表示更新操作
 
3.4 更新用户头像 (updateAvatar)
 
export function updateAvatar(avatarUrl) {return instance({url: '/user/avatar',method: 'patch',params: { avatarUrl }});
}
 
- 功能:更新用户头像
 - 方法:PATCH(部分更新)
 - 参数:通过 
params传递头像 URL - 特点:使用 PATCH 方法表示部分更新,参数通过 URL 查询字符串传递
 
3.5 更新用户密码 (updatePassword)
 
export function updatePassword(data) {return instance({url: '/user/password',method: 'patch',data});
}
 
- 功能:更新用户密码
 - 方法:PATCH
 - 参数:通过 
data传递新旧密码 - 特点:敏感操作,通常需要额外验证
 
3.6 获取用户列表 (getUserList)
 
export function getUserList(params) {return instance({url: '/user/page',method: 'get',params});
}
 
- 功能:分页获取用户列表(管理员功能)
 - 方法:GET
 - 参数:通过 
params传递分页参数(如 pageNum, pageSize) - 特点:需要管理员权限,参数通过 URL 查询字符串传递
 
2. Token管理 (token.js)
token.js 是一个使用 Pinia 实现的状态管理模块,专门用于管理用户的认证 token。本次完善如下:
setToken
setToken(token) {this.token = token;localStorage.setItem('token', token); // 同步到 localStorage
},
 
- 功能:设置 token
 - 同时更新内存状态和 localStorage
 - 确保 token 在页面刷新后仍然可用
 
clearToken
clearToken() {this.token = ''; // 清空 statelocalStorage.removeItem('token'); // 清除 localStorage// 关键:清除 Pinia 持久化插件的存储if (this.$hydrate) {this.$hydrate({ reset: true }); // 重置持久化状态}// 或者直接清除特定的持久化 keyconst PERSIST_KEY = `pinia-${this.$id}`;localStorage.removeItem(PERSIST_KEY);sessionStorage.removeItem(PERSIST_KEY);
}
 
- 功能:清除 token
 - 清空内存状态
 - 从 localStorage 移除 token
 - 特别处理了 Pinia 持久化插件的存储(两种方式): 
- 使用插件的 
$hydrate方法(如果存在) - 直接移除插件使用的存储 key
 
 - 使用插件的 
 
3. 用户信息组件 (UserInfo.vue)
字段与后端 UserVO 匹配
组件中的 userForm 对象字段与后端数据结构对齐:
const userForm = reactive({id: '',           // 用户IDusername: '',     // 用户名nickname: '',     // 昵称 (替代了原来的realName)email: '',        // 电子邮箱avatarUrl: '',    // 新增-头像URLrole: 0,          // 用户角色 (0-管理员,1-普通用户)createTime: '',   // 创建时间updateTime: ''    // 更新时间
});
 
关键字段变更:
nickname替代realName:更符合常见用户系统的命名习惯- 新增 
avatarUrl:支持头像显示和预览功能 - 角色显示优化:将数字角色转换为易读文本
<el-input :value="userForm.role === 0 ? '管理员' : '普通用户'" disabled /> 
编辑逻辑优化
可编辑字段控制
- 允许编辑的字段:仅 
nickname和email<el-form-item label="昵称"><el-input v-model="userForm.nickname" /> </el-form-item><el-form-item label="电子邮箱"><el-input v-model="userForm.email" /> </el-form-item> - 禁用字段:其他所有字段都设置为 
disabled 
编辑状态管理
- 使用 
isEditingref 控制编辑状态 - 编辑按钮条件渲染:
<el-button type="primary" @click="handleEdit" v-if="!isEditing">编辑</el-button> <div v-else class="action-buttons"><el-button type="success" @click="handleSave">保存</el-button><el-button @click="cancelEdit">取消</el-button> </div> 
数据恢复机制
- 使用 
originalUserData保存原始数据:const originalUserData = reactive({});// 获取用户信息时保存原始数据 Object.assign(originalUserData, res.data); - 取消编辑时恢复数据:
const cancelEdit = () => {isEditing.value = false;Object.assign(userForm, originalUserData); }; 
保存逻辑
- 仅提交可修改的字段:
const res = await updateUserInfo({nickname: userForm.nickname,email: userForm.email }); - 成功保存后刷新数据:
if (res.code === 200) {ElMessage.success('用户信息更新成功');isEditing.value = false;fetchUserInfo(); // 刷新数据 } 
与API的交互
组件使用了 user.js 中的两个API方法:
-  
获取用户信息:
import { getUserInfo } from '@/api/user';const res = await getUserInfo(); -  
更新用户信息:
import { updateUserInfo } from '@/api/user';const res = await updateUserInfo({ nickname, email }); 
4. 登录组件 (Login.vue)
表单验证修改
验证规则配置
组件中定义了严格的表单验证规则,与后端要求保持一致:
const loginRules = {username: [{ required: true, message: "请输入用户名", trigger: "blur" },{ min: 5, max: 16, message: "用户名长度应为5-16个字符", trigger: "blur" },{ validator: validateNoWhitespace, trigger: "blur" },],password: [{ required: true, message: "请输入密码", trigger: "blur" },{ min: 5, max: 16, message: "密码长度应为5-16个字符", trigger: "blur" },{ validator: validateNoWhitespace, trigger: "blur" },],
};
 
自定义验证方法
实现了禁止空白字符的自定义验证:
const validateNoWhitespace = (rule, value, callback) => {if (/\s/.test(value)) {callback(new Error("不能包含空白字符"));} else {callback();}
};
 
登录逻辑实现
const handleLogin = async () => {try {// 1. 表单验证await loginFormRef.value.validate();loading.value = true;// 2. 调用登录APIconst response = await login({username: loginForm.username,password: loginForm.password,});if (response.code === 200) {// 3. 存储tokentokenStore.setToken(response.data);// 4. 获取用户信息const userInfoResponse = await getUserInfo();if (userInfoResponse.code === 200) {userInfoStore.setUserInfo(userInfoResponse.data);}ElMessage.success("登录成功");// 5. 跳转到首页router.push("/dashboard");} else {ElMessage.error(response.message || "登录失败");}} catch (error) {ElMessage.error(error.message || "登录失败");} finally {loading.value = false;}
};
 
- 表单验证:先验证表单数据是否符合规则
 - API调用:使用 
login()方法发送登录请求 - Token存储:登录成功后,通过 
tokenStore.setToken()存储token- 同时保存到Pinia状态和localStorage
 
 - 用户信息获取:获取并存储用户详细信息
 - 页面跳转:登录成功后跳转到仪表盘页面
 
使用了两个Pinia store:
- tokenStore:管理认证token
const tokenStore = useTokenStore(); tokenStore.setToken(response.data); - userInfoStore:管理用户信息
const userInfoStore = useUserInfoStore(); userInfoStore.setUserInfo(userInfoResponse.data); 
与API的交互
组件使用了 user.js 中的两个API方法:
- 登录接口:
import { login } from "@/api/user"; const response = await login({ username, password }); - 获取用户信息:
import { getUserInfo } from "@/api/user"; const userInfoResponse = await getUserInfo(); 
