Files
whale-town-end/src/core/db/users/base_users.service.ts
moyin e54d5e3939 style(users): 优化Core层users模块代码规范
范围: src/core/db/users/
- base_users.service.ts: 为保护方法补充@example示例
- users.constants.ts: 补充职责分离描述

检查人员: moyin
检查日期: 2026-01-15
2026-01-15 13:38:36 +08:00

203 lines
5.6 KiB
TypeScript

/**
* 用户服务基类
*
* 功能描述:
* - 提供统一的异常处理机制
* - 定义通用的错误处理方法
* - 统一日志记录格式
* - 敏感信息脱敏处理
*
* 职责分离:
* - 异常处理:统一的错误格式化和异常转换
* - 日志管理:结构化日志记录和敏感信息脱敏
* - 性能监控:操作成功和失败的统计记录
* - 搜索优化:搜索异常的特殊处理机制
*
* 最近修改:
* - 2026-01-15: 代码规范优化 - 为保护方法补充@example示例 (修改者: moyin)
* - 2026-01-07: 代码规范优化 - 完善注释规范,添加完整的文件头和方法注释
* - 2026-01-07: 功能新增 - 添加敏感信息脱敏处理和结构化日志记录
*
* @author moyin
* @version 1.0.2
* @since 2025-01-07
* @lastModified 2026-01-15
*/
import { Logger, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common';
export abstract class BaseUsersService {
protected readonly logger = new Logger(this.constructor.name);
/**
* 统一的错误格式化方法
*
* @param error 原始错误对象
* @returns 格式化后的错误信息字符串
*
* @example
* ```typescript
* const errorMsg = this.formatError(new Error('数据库连接失败'));
* // 返回: "数据库连接失败"
* ```
*/
protected formatError(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
return String(error);
}
/**
* 统一的异常处理方法
*
* @param error 原始错误
* @param operation 操作名称
* @param context 上下文信息
* @throws 处理后的标准异常
*
* @example
* ```typescript
* try {
* // 业务操作
* } catch (error) {
* this.handleServiceError(error, '创建用户', { username: 'test' });
* }
* ```
*/
protected handleServiceError(error: unknown, operation: string, context?: Record<string, any>): never {
const errorMessage = this.formatError(error);
// 记录错误日志
this.logger.error(`${operation}失败`, {
operation,
error: errorMessage,
context: context ? this.sanitizeLogData(context) : undefined,
timestamp: new Date().toISOString()
}, error instanceof Error ? error.stack : undefined);
// 如果是已知的业务异常,直接重新抛出
if (error instanceof ConflictException ||
error instanceof NotFoundException ||
error instanceof BadRequestException) {
throw error;
}
// 系统异常转换为BadRequestException
throw new BadRequestException(`${operation}失败,请稍后重试`);
}
/**
* 搜索异常的特殊处理(返回空结果而不抛出异常)
*
* @param error 原始错误
* @param operation 操作名称
* @param context 上下文信息
* @returns 空数组
*
* @example
* ```typescript
* try {
* // 搜索操作
* } catch (error) {
* return this.handleSearchError(error, '搜索用户', { keyword: 'test' });
* }
* ```
*/
protected handleSearchError(error: unknown, operation: string, context?: Record<string, any>): any[] {
const errorMessage = this.formatError(error);
this.logger.warn(`${operation}失败,返回空结果`, {
operation,
error: errorMessage,
context: context ? this.sanitizeLogData(context) : undefined,
timestamp: new Date().toISOString()
});
return [];
}
/**
* 记录操作成功日志
*
* @param operation 操作名称
* @param context 上下文信息
* @param duration 操作耗时
*
* @example
* ```typescript
* this.logSuccess('创建用户', { userId: '123', username: 'test' }, 50);
* ```
*/
protected logSuccess(operation: string, context?: Record<string, any>, duration?: number): void {
this.logger.log(`${operation}成功`, {
operation,
context: context ? this.sanitizeLogData(context) : undefined,
duration,
timestamp: new Date().toISOString()
});
}
/**
* 记录操作开始日志
*
* @param operation 操作名称
* @param context 上下文信息
*
* @example
* ```typescript
* this.logStart('创建用户', { username: 'test' });
* ```
*/
protected logStart(operation: string, context?: Record<string, any>): void {
this.logger.log(`开始${operation}`, {
operation,
context: context ? this.sanitizeLogData(context) : undefined,
timestamp: new Date().toISOString()
});
}
/**
* 脱敏处理敏感信息
*
* @param data 原始数据
* @returns 脱敏后的数据
*
* @example
* ```typescript
* const sanitized = this.sanitizeLogData({
* email: 'test@example.com',
* phone: '13800138000',
* password_hash: 'secret'
* });
* // 返回: { email: 'te***@example.com', phone: '138****00', password_hash: '[REDACTED]' }
* ```
*/
protected sanitizeLogData(data: Record<string, any>): Record<string, any> {
const sanitized = { ...data };
// 脱敏邮箱
if (sanitized.email) {
const email = sanitized.email;
const [localPart, domain] = email.split('@');
if (localPart && domain) {
sanitized.email = `${localPart.substring(0, 2)}***@${domain}`;
}
}
// 脱敏手机号
if (sanitized.phone) {
const phone = sanitized.phone;
if (phone.length > 4) {
sanitized.phone = `${phone.substring(0, 3)}****${phone.substring(phone.length - 2)}`;
}
}
// 移除密码哈希
if (sanitized.password_hash) {
sanitized.password_hash = '[REDACTED]';
}
return sanitized;
}
}