HarmonyOS应用<趣答>开发第5篇:UserService用户服务实现详解——用户数据管理的核心引擎
·

📖 引言
在知识问答学习应用中,用户服务(UserService)是管理用户数据的核心组件。它负责处理用户的登录、注册、数据存储、统计更新等关键操作,是连接用户与应用的桥梁。
本文将详细讲解 UserService 的完整实现,包括用户认证、数据管理、统计更新等核心功能。通过本文,你将掌握:
- 如何设计用户服务的核心接口
- 如何实现用户登录和注册流程
- 如何管理用户数据和统计
- 如何在实际项目中保证用户数据的安全性
🎯 学习目标
完成本文后,你将能够:
- ✅ 理解 UserService 的核心职责和功能
- ✅ 实现用户登录、注册和注销功能
- ✅ 管理用户数据的增删改查
- ✅ 更新用户统计和进度
- ✅ 处理用户设置和偏好
💡 需求分析
功能模块设计
| 模块 | 功能描述 | 技术要点 |
|---|---|---|
| 用户认证 | 处理用户登录、注册、注销 | 密码加密、token管理 |
| 用户数据管理 | CRUD操作用户数据 | 数据持久化、缓存 |
| 用户统计 | 更新用户学习统计数据 | 答题数、正确率、积分 |
| 用户设置 | 管理用户偏好设置 | 主题、通知、语言 |
| 进度同步 | 同步用户学习进度 | 云端同步、本地存储 |
🛠️ 核心实现
步骤1: UserService 接口设计
功能说明
定义 UserService 的核心接口,规范服务的方法签名和返回类型。
完整代码
// services/interfaces/UserServiceInterface.ts
import { User, UserSettings, UserStatistics } from '../models/User';
import { ServiceResponse } from './ServiceInterface';
/**
* 用户服务接口
*/
export interface UserServiceInterface {
/**
* 用户登录
* @param username - 用户名
* @param password - 密码
* @returns 用户信息
*/
login(username: string, password: string): Promise<ServiceResponse<User>>;
/**
* 用户注册
* @param username - 用户名
* @param password - 密码
* @param nickname - 用户昵称
* @returns 用户信息
*/
register(username: string, password: string, nickname: string): Promise<ServiceResponse<User>>;
/**
* 用户注销
* @returns 操作结果
*/
logout(): Promise<ServiceResponse<void>>;
/**
* 获取当前用户
* @returns 当前用户信息
*/
getCurrentUser(): Promise<ServiceResponse<User | null>>;
/**
* 根据ID获取用户
* @param userId - 用户ID
* @returns 用户信息
*/
getUserById(userId: string): Promise<ServiceResponse<User | null>>;
/**
* 更新用户信息
* @param userId - 用户ID
* @param updates - 更新内容
* @returns 更新后的用户信息
*/
updateUser(userId: string, updates: Partial<User>): Promise<ServiceResponse<User>>;
/**
* 更新用户设置
* @param userId - 用户ID
* @param settings - 设置内容
* @returns 更新后的设置
*/
updateSettings(userId: string, settings: Partial<UserSettings>): Promise<ServiceResponse<UserSettings>>;
/**
* 更新用户统计
* @param userId - 用户ID
* @param statistics - 统计数据
* @returns 更新后的统计
*/
updateStatistics(userId: string, statistics: Partial<UserStatistics>): Promise<ServiceResponse<UserStatistics>>;
/**
* 增加用户积分
* @param userId - 用户ID
* @param amount - 积分数量
* @returns 更新后的用户信息
*/
addScore(userId: string, amount: number): Promise<ServiceResponse<User>>;
/**
* 增加用户经验值
* @param userId - 用户ID
* @param amount - 经验值数量
* @returns 更新后的用户信息
*/
addExperience(userId: string, amount: number): Promise<ServiceResponse<User>>;
/**
* 检查用户名是否存在
* @param username - 用户名
* @returns 是否存在
*/
checkUsernameExists(username: string): Promise<ServiceResponse<boolean>>;
/**
* 重置密码
* @param username - 用户名
* @param newPassword - 新密码
* @returns 操作结果
*/
resetPassword(username: string, newPassword: string): Promise<ServiceResponse<void>>;
/**
* 更新用户头像
* @param userId - 用户ID
* @param avatarUrl - 头像URL
* @returns 更新后的用户信息
*/
updateAvatar(userId: string, avatarUrl: string): Promise<ServiceResponse<User>>;
/**
* 更新用户昵称
* @param userId - 用户ID
* @param nickname - 新昵称
* @returns 更新后的用户信息
*/
updateNickname(userId: string, nickname: string): Promise<ServiceResponse<User>>;
}
代码解析
1. 接口方法分类
| 分类 | 方法 | 功能说明 |
|---|---|---|
| 认证 | login(), register(), logout() |
用户登录、注册、注销 |
| 查询 | getCurrentUser(), getUserById() |
获取用户信息 |
| 更新 | updateUser(), updateSettings(), updateStatistics() |
更新用户数据 |
| 奖励 | addScore(), addExperience() |
添加积分和经验 |
| 辅助 | checkUsernameExists(), resetPassword() |
辅助操作 |
2. 返回类型说明
export interface ServiceResponse<T> {
success: boolean;
data?: T;
error?: ServiceError;
message?: string;
timestamp: number;
}
步骤2: UserService 实现
功能说明
实现 UserService 的核心逻辑,包括用户认证、数据管理、统计更新等功能。
完整代码
// services/UserService.ts
import { Singleton } from './base/BaseService';
import { BaseService } from './base/BaseService';
import { ServiceResponse, ServiceError, createSuccessResponse, createErrorResponse } from './interfaces/ServiceInterface';
import { UserServiceInterface } from './interfaces/UserServiceInterface';
import { User, UserSettings, UserStatistics, UserTools } from '../models/User';
import { StorageService } from './StorageService';
import { LevelService } from './LevelService';
import { AchievementService } from './AchievementService';
/**
* 用户服务实现
*/
@Singleton
export class UserService extends BaseService implements UserServiceInterface {
private storageService: StorageService;
private levelService: LevelService;
private achievementService: AchievementService;
private currentUser: User | null = null;
constructor() {
super();
this.storageService = StorageService.getInstance();
this.levelService = LevelService.getInstance();
this.achievementService = AchievementService.getInstance();
}
/**
* 初始化服务
*/
async initialize(): Promise<void> {
// 尝试从本地存储恢复用户会话
await this.restoreSession();
}
/**
* 从本地存储恢复会话
*/
private async restoreSession(): Promise<void> {
const storedUser = await this.storageService.getUserData();
if (storedUser) {
this.currentUser = storedUser;
}
}
/**
* 用户登录
*/
async login(username: string, password: string): Promise<ServiceResponse<User>> {
try {
// 验证参数
if (!username || !password) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '用户名和密码不能为空');
}
// 查询用户
const users = await this.storageService.getUsers();
const user = users.find(u => u.username === username);
if (!user) {
return createErrorResponse<User>(ServiceError.NOT_FOUND, '用户不存在');
}
// 验证密码(实际项目中使用加密验证)
if (user.password !== password) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '密码错误');
}
// 记录登录日期
user.lastLoginDate = new Date().toISOString();
// 更新连续登录天数
await this.updateConsecutiveDays(user);
// 保存用户数据
await this.storageService.saveUserData(user);
this.currentUser = user;
// 检查成就
await this.achievementService.checkAndUnlockAchievements(user);
return createSuccessResponse<User>(user);
} catch (error) {
return createErrorResponse<User>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 用户注册
*/
async register(username: string, password: string, nickname: string): Promise<ServiceResponse<User>> {
try {
// 验证参数
if (!username || !password || !nickname) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '用户名、密码和昵称不能为空');
}
// 检查用户名是否已存在
const exists = await this.checkUsernameExists(username);
if (exists.data) {
return createErrorResponse<User>(ServiceError.CONFLICT, '用户名已存在');
}
// 创建新用户
const now = new Date().toISOString();
const newUser: User = {
id: this.generateUserId(),
username,
password, // 实际项目中应加密存储
nickname,
avatar: this.generateDefaultAvatar(),
level: 1,
totalScore: 0,
totalExperience: 0,
rank: 0,
consecutiveDays: 1,
lastLoginDate: now,
createdAt: now,
settings: this.createDefaultSettings(),
statistics: this.createDefaultStatistics(),
unlockedLevels: ['math_level_1'], // 默认解锁第一个关卡
completedLevels: [],
levelStars: new Map(),
achievements: [],
wrongQuestions: [],
favorites: [],
tools: this.createDefaultTools(),
quizHistory: [],
dailyRecords: [],
ownedItems: []
};
// 保存用户
await this.storageService.saveUser(newUser);
await this.storageService.saveUserData(newUser);
this.currentUser = newUser;
return createSuccessResponse<User>(newUser);
} catch (error) {
return createErrorResponse<User>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 用户注销
*/
async logout(): Promise<ServiceResponse<void>> {
try {
// 清除本地存储
await this.storageService.clearUserData();
this.currentUser = null;
return createSuccessResponse<void>(undefined);
} catch (error) {
return createErrorResponse<void>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 获取当前用户
*/
async getCurrentUser(): Promise<ServiceResponse<User | null>> {
try {
if (!this.currentUser) {
await this.restoreSession();
}
return createSuccessResponse<User | null>(this.currentUser);
} catch (error) {
return createErrorResponse<User | null>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 根据ID获取用户
*/
async getUserById(userId: string): Promise<ServiceResponse<User | null>> {
try {
const users = await this.storageService.getUsers();
const user = users.find(u => u.id === userId);
return createSuccessResponse<User | null>(user || null);
} catch (error) {
return createErrorResponse<User | null>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 更新用户信息
*/
async updateUser(userId: string, updates: Partial<User>): Promise<ServiceResponse<User>> {
try {
const users = await this.storageService.getUsers();
const index = users.findIndex(u => u.id === userId);
if (index === -1) {
return createErrorResponse<User>(ServiceError.NOT_FOUND, '用户不存在');
}
// 更新用户信息
users[index] = { ...users[index], ...updates };
await this.storageService.saveUsers(users);
// 如果是当前用户,更新本地缓存
if (this.currentUser?.id === userId) {
this.currentUser = users[index];
await this.storageService.saveUserData(this.currentUser);
}
return createSuccessResponse<User>(users[index]);
} catch (error) {
return createErrorResponse<User>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 更新用户设置
*/
async updateSettings(userId: string, settings: Partial<UserSettings>): Promise<ServiceResponse<UserSettings>> {
try {
const users = await this.storageService.getUsers();
const user = users.find(u => u.id === userId);
if (!user) {
return createErrorResponse<UserSettings>(ServiceError.NOT_FOUND, '用户不存在');
}
// 更新设置
user.settings = { ...user.settings, ...settings };
await this.storageService.saveUsers(users);
// 更新当前用户缓存
if (this.currentUser?.id === userId) {
this.currentUser.settings = user.settings;
await this.storageService.saveUserData(this.currentUser);
}
return createSuccessResponse<UserSettings>(user.settings);
} catch (error) {
return createErrorResponse<UserSettings>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 更新用户统计
*/
async updateStatistics(userId: string, statistics: Partial<UserStatistics>): Promise<ServiceResponse<UserStatistics>> {
try {
const users = await this.storageService.getUsers();
const user = users.find(u => u.id === userId);
if (!user) {
return createErrorResponse<UserStatistics>(ServiceError.NOT_FOUND, '用户不存在');
}
// 更新统计数据
user.statistics = { ...user.statistics, ...statistics };
await this.storageService.saveUsers(users);
// 更新当前用户缓存
if (this.currentUser?.id === userId) {
this.currentUser.statistics = user.statistics;
await this.storageService.saveUserData(this.currentUser);
}
return createSuccessResponse<UserStatistics>(user.statistics);
} catch (error) {
return createErrorResponse<UserStatistics>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 增加用户积分
*/
async addScore(userId: string, amount: number): Promise<ServiceResponse<User>> {
try {
const users = await this.storageService.getUsers();
const index = users.findIndex(u => u.id === userId);
if (index === -1) {
return createErrorResponse<User>(ServiceError.NOT_FOUND, '用户不存在');
}
// 增加积分
users[index].totalScore += amount;
await this.storageService.saveUsers(users);
// 更新当前用户缓存
if (this.currentUser?.id === userId) {
this.currentUser.totalScore = users[index].totalScore;
await this.storageService.saveUserData(this.currentUser);
}
return createSuccessResponse<User>(users[index]);
} catch (error) {
return createErrorResponse<User>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 增加用户经验值
*/
async addExperience(userId: string, amount: number): Promise<ServiceResponse<User>> {
try {
const users = await this.storageService.getUsers();
const index = users.findIndex(u => u.id === userId);
if (index === -1) {
return createErrorResponse<User>(ServiceError.NOT_FOUND, '用户不存在');
}
// 增加经验值
users[index].totalExperience += amount;
// 检查是否升级
await this.checkLevelUp(users[index]);
await this.storageService.saveUsers(users);
// 更新当前用户缓存
if (this.currentUser?.id === userId) {
this.currentUser = users[index];
await this.storageService.saveUserData(this.currentUser);
}
return createSuccessResponse<User>(users[index]);
} catch (error) {
return createErrorResponse<User>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 检查用户名是否存在
*/
async checkUsernameExists(username: string): Promise<ServiceResponse<boolean>> {
try {
const users = await this.storageService.getUsers();
const exists = users.some(u => u.username === username);
return createSuccessResponse<boolean>(exists);
} catch (error) {
return createErrorResponse<boolean>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 重置密码
*/
async resetPassword(username: string, newPassword: string): Promise<ServiceResponse<void>> {
try {
const users = await this.storageService.getUsers();
const index = users.findIndex(u => u.username === username);
if (index === -1) {
return createErrorResponse<void>(ServiceError.NOT_FOUND, '用户不存在');
}
// 更新密码(实际项目中应加密)
users[index].password = newPassword;
await this.storageService.saveUsers(users);
return createSuccessResponse<void>(undefined);
} catch (error) {
return createErrorResponse<void>(ServiceError.ERROR, (error as Error).message);
}
}
/**
* 更新用户头像
*/
async updateAvatar(userId: string, avatarUrl: string): Promise<ServiceResponse<User>> {
return this.updateUser(userId, { avatar: avatarUrl });
}
/**
* 更新用户昵称
*/
async updateNickname(userId: string, nickname: string): Promise<ServiceResponse<User>> {
return this.updateUser(userId, { nickname });
}
/**
* 检查升级
*/
private async checkLevelUp(user: User): Promise<void> {
const expForNextLevel = user.level * 100;
if (user.totalExperience >= expForNextLevel) {
user.level++;
// 升级奖励
user.totalScore += user.level * 50;
}
}
/**
* 更新连续登录天数
*/
private async updateConsecutiveDays(user: User): Promise<void> {
const today = new Date().toDateString();
const lastLogin = new Date(user.lastLoginDate).toDateString();
// 检查是否连续登录
const oneDay = 24 * 60 * 60 * 1000;
const daysDiff = Math.round((new Date(today).getTime() - new Date(lastLogin).getTime()) / oneDay);
if (daysDiff === 1) {
// 连续登录,天数+1
user.consecutiveDays++;
} else if (daysDiff > 1) {
// 中断登录,重置为1
user.consecutiveDays = 1;
}
// 同一天登录,天数不变
}
/**
* 生成用户ID
*/
private generateUserId(): string {
return `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
/**
* 生成默认头像
*/
private generateDefaultAvatar(): string {
const colors = ['#4CAF50', '#2196F3', '#FF9800', '#9C27B0', '#F44336'];
const color = colors[Math.floor(Math.random() * colors.length)];
return `https://ui-avatars.com/api/?background=${color.replace('#', '')}&color=fff&name=User`;
}
/**
* 创建默认设置
*/
private createDefaultSettings(): UserSettings {
return {
theme: 'light',
notification: true,
sound: true,
autoSave: true,
dailyReminder: true,
difficulty: 1,
language: 'zh-CN',
fontSize: 16,
showExplanation: true,
shuffleQuestions: true
};
}
/**
* 创建默认统计
*/
private createDefaultStatistics(): UserStatistics {
return {
totalQuestions: 0,
correctQuestions: 0,
wrongQuestions: 0,
averageAccuracy: 0,
totalTime: 0,
averageTimePerQuestion: 0,
streakDays: 0,
bestStreak: 0,
completedLevels: 0,
perfectLevels: 0,
achievementsUnlocked: 0,
totalScore: 0,
rank: 0
};
}
/**
* 创建默认工具
*/
private createDefaultTools(): UserTools {
return {
hintCount: 3,
skipCount: 1,
refreshCount: 1,
doubleScoreCount: 1
};
}
}
代码解析
1. 用户登录流程
async login(username: string, password: string): Promise<ServiceResponse<User>> {
// 1. 验证参数
if (!username || !password) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '用户名和密码不能为空');
}
// 2. 查询用户
const users = await this.storageService.getUsers();
const user = users.find(u => u.username === username);
// 3. 验证密码
if (user.password !== password) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '密码错误');
}
// 4. 更新登录信息
user.lastLoginDate = new Date().toISOString();
await this.updateConsecutiveDays(user);
// 5. 保存会话
await this.storageService.saveUserData(user);
this.currentUser = user;
// 6. 检查成就
await this.achievementService.checkAndUnlockAchievements(user);
return createSuccessResponse<User>(user);
}
流程说明:
- 参数验证
- 查询用户
- 密码验证
- 更新登录日期和连续登录天数
- 保存会话
- 检查成就解锁
2. 用户注册流程
async register(username: string, password: string, nickname: string): Promise<ServiceResponse<User>> {
// 1. 验证参数
// 2. 检查用户名是否存在
// 3. 创建新用户(包含默认设置、统计、初始关卡)
// 4. 保存用户
// 5. 返回用户信息
}
3. 连续登录天数计算
private async updateConsecutiveDays(user: User): Promise<void> {
const today = new Date().toDateString();
const lastLogin = new Date(user.lastLoginDate).toDateString();
const oneDay = 24 * 60 * 60 * 1000;
const daysDiff = Math.round((new Date(today).getTime() - new Date(lastLogin).getTime()) / oneDay);
if (daysDiff === 1) {
user.consecutiveDays++; // 连续登录
} else if (daysDiff > 1) {
user.consecutiveDays = 1; // 中断登录
}
}
原理:
- 计算上次登录与今天的天数差
- 差为1:连续登录,天数+1
- 差>1:中断登录,重置为1
- 差=0:同一天,不变
步骤3: 用户数据持久化
功能说明
使用 StorageService 实现用户数据的本地存储和读取。
完整代码
// services/StorageService.ts
import { Singleton } from './base/BaseService';
import { BaseService } from './base/BaseService';
import { User } from '../models/User';
/**
* 存储服务
*/
@Singleton
export class StorageService extends BaseService {
private readonly USER_DATA_KEY = 'quiz_user_data';
private readonly USERS_KEY = 'quiz_users';
/**
* 获取用户数据
*/
async getUserData(): Promise<User | null> {
try {
const data = localStorage.getItem(this.USER_DATA_KEY);
return data ? JSON.parse(data) : null;
} catch {
return null;
}
}
/**
* 保存用户数据
*/
async saveUserData(user: User): Promise<void> {
try {
localStorage.setItem(this.USER_DATA_KEY, JSON.stringify(user));
} catch (error) {
console.error('Failed to save user data:', error);
}
}
/**
* 清除用户数据
*/
async clearUserData(): Promise<void> {
try {
localStorage.removeItem(this.USER_DATA_KEY);
} catch (error) {
console.error('Failed to clear user data:', error);
}
}
/**
* 获取所有用户
*/
async getUsers(): Promise<User[]> {
try {
const data = localStorage.getItem(this.USERS_KEY);
return data ? JSON.parse(data) : [];
} catch {
return [];
}
}
/**
* 保存所有用户
*/
async saveUsers(users: User[]): Promise<void> {
try {
localStorage.setItem(this.USERS_KEY, JSON.stringify(users));
} catch (error) {
console.error('Failed to save users:', error);
}
}
/**
* 保存单个用户
*/
async saveUser(user: User): Promise<void> {
const users = await this.getUsers();
const index = users.findIndex(u => u.id === user.id);
if (index === -1) {
users.push(user);
} else {
users[index] = user;
}
await this.saveUsers(users);
}
/**
* 删除用户
*/
async deleteUser(userId: string): Promise<void> {
const users = await this.getUsers();
const filtered = users.filter(u => u.id !== userId);
await this.saveUsers(filtered);
}
}
代码解析
1. 存储键设计
private readonly USER_DATA_KEY = 'quiz_user_data'; // 当前用户会话
private readonly USERS_KEY = 'quiz_users'; // 所有用户列表
2. 数据存储流程
// 登录时保存会话
await this.storageService.saveUserData(user);
// 获取当前用户
const user = await this.storageService.getUserData();
// 注销时清除会话
await this.storageService.clearUserData();
⚠️ 常见问题与解决方案
问题1: 密码明文存储
现象:
密码以明文形式存储,存在安全风险。
错误代码:
// ❌ 错误:明文存储密码
newUser.password = password;
正确代码:
// ✅ 正确:加密存储密码
import * as bcrypt from 'bcrypt';
async function hashPassword(password: string): Promise<string> {
const saltRounds = 10;
return bcrypt.hash(password, saltRounds);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// 注册时加密
newUser.password = await hashPassword(password);
// 登录时验证
const isValid = await verifyPassword(password, user.password);
规则/建议:
- 使用 bcrypt 或类似算法加密密码
- 永远不要明文存储密码
- 登录时验证哈希值而非明文比较
问题2: 用户会话管理缺失
现象:
应用重启后用户需要重新登录。
错误代码:
// ❌ 错误:没有会话持久化
this.currentUser = null;
正确代码:
// ✅ 正确:持久化会话
async initialize(): Promise<void> {
await this.restoreSession();
}
private async restoreSession(): Promise<void> {
const storedUser = await this.storageService.getUserData();
if (storedUser) {
this.currentUser = storedUser;
}
}
规则/建议:
- 在服务初始化时恢复会话
- 使用 localStorage 或 secure storage 存储会话
- 设置合理的会话过期时间
问题3: 并发更新导致数据不一致
现象:
多个操作同时更新用户数据,导致数据覆盖丢失。
错误代码:
// ❌ 错误:没有并发控制
async addScore(userId: string, amount: number) {
const user = await this.getUserById(userId);
user.totalScore += amount; // 可能被其他操作覆盖
await this.saveUser(user);
}
正确代码:
// ✅ 正确:使用乐观锁或事务
async addScore(userId: string, amount: number) {
const users = await this.storageService.getUsers(); // 获取最新数据
const index = users.findIndex(u => u.id === userId);
if (index === -1) {
return createErrorResponse<User>(ServiceError.NOT_FOUND, '用户不存在');
}
users[index].totalScore += amount;
await this.storageService.saveUsers(users); // 原子操作
}
规则/建议:
- 使用原子操作更新数据
- 每次更新前获取最新数据
- 考虑使用版本号实现乐观锁
问题4: 用户数据验证缺失
现象:
没有验证用户输入的数据,可能导致数据异常。
错误代码:
// ❌ 错误:没有数据验证
async updateNickname(userId: string, nickname: string) {
await this.updateUser(userId, { nickname });
}
正确代码:
// ✅ 正确:添加数据验证
async updateNickname(userId: string, nickname: string): Promise<ServiceResponse<User>> {
// 验证昵称长度
if (!nickname || nickname.length < 2 || nickname.length > 20) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '昵称长度必须在2-20之间');
}
// 验证昵称格式(只允许中文、英文、数字和下划线)
const regex = /^[\u4e00-\u9fa5a-zA-Z0-9_]+$/;
if (!regex.test(nickname)) {
return createErrorResponse<User>(ServiceError.INVALID_PARAMS, '昵称只能包含中文、英文、数字和下划线');
}
return this.updateUser(userId, { nickname });
}
规则/建议:
- 对用户输入进行验证
- 使用正则表达式验证格式
- 检查数据长度和类型
问题5: 连续登录天数计算错误
现象:
连续登录天数计算不准确,导致成就无法正确解锁。
错误代码:
// ❌ 错误:没有考虑时区和日期边界
user.consecutiveDays++; // 简单递增
正确代码:
// ✅ 正确:考虑日期边界
private async updateConsecutiveDays(user: User): Promise<void> {
const today = new Date().toDateString();
const lastLogin = new Date(user.lastLoginDate).toDateString();
const oneDay = 24 * 60 * 60 * 1000;
const daysDiff = Math.round((new Date(today).getTime() - new Date(lastLogin).getTime()) / oneDay);
if (daysDiff === 1) {
user.consecutiveDays++;
} else if (daysDiff > 1) {
user.consecutiveDays = 1;
}
}
规则/建议:
- 使用日期字符串比较,避免时区问题
- 计算实际天数差而非简单递增
- 同一天登录不增加天数
📝 本章小结
核心知识点
本文详细讲解了 UserService 用户服务的实现,主要包括:
1. 用户认证
- 登录、注册、注销流程
- 密码验证和会话管理
2. 用户数据管理
- CRUD操作
- 数据持久化
3. 用户统计更新
- 积分和经验值管理
- 等级升级逻辑
4. 辅助功能
- 连续登录天数计算
- 头像和昵称更新
最佳实践总结
✅ 密码安全
// 使用 bcrypt 加密
const hash = await bcrypt.hash(password, 10);
const isValid = await bcrypt.compare(password, hash);
✅ 会话管理
// 初始化时恢复会话
async initialize(): Promise<void> {
const stored = await this.storageService.getUserData();
if (stored) this.currentUser = stored;
}
✅ 并发安全
// 使用原子操作
const users = await this.storageService.getUsers();
users[index].totalScore += amount;
await this.storageService.saveUsers(users);
✅ 数据验证
// 验证输入数据
if (!nickname || nickname.length < 2 || nickname.length > 20) {
return createErrorResponse(ServiceError.INVALID_PARAMS, '无效昵称');
}
下一步预告
在下一篇文章中,我们将:
- 🎨 讲解 QuizService 测验服务实现详解
- 📚 介绍测验流程管理和答题逻辑
- 🏷️ 探索测验结果计算和统计更新
🔗 相关链接
- 项目源码: Atomgit仓库
💡 提示: 建议结合项目源码阅读,动手实践效果更好!
更多推荐



所有评论(0)