440 lines
12 KiB
Markdown
440 lines
12 KiB
Markdown
# Service层实现文档
|
||
|
||
## 一、认证Service(AuthService)
|
||
|
||
### 1.1 功能概述
|
||
|
||
实现了用户认证相关的核心功能,包括:
|
||
- 用户注册
|
||
- 用户登录
|
||
- 用户登出
|
||
- Token刷新
|
||
- Token验证
|
||
|
||
### 1.2 接口定义
|
||
|
||
```go
|
||
type AuthService interface {
|
||
// Register 注册
|
||
Register(req *pb.RegisterRequest) (*pb.RegisterResponse, error)
|
||
|
||
// Login 登录
|
||
Login(req *pb.LoginRequest) (*pb.LoginResponse, error)
|
||
|
||
// Logout 登出
|
||
Logout(req *pb.LogoutRequest) (*pb.LogoutResponse, error)
|
||
|
||
// RefreshToken 刷新Token
|
||
RefreshToken(req *pb.RefreshTokenRequest) (*pb.RefreshTokenResponse, error)
|
||
|
||
// ValidateToken 验证Token(用于中间件)
|
||
ValidateToken(req *pb.ValidateTokenRequest) (*pb.ValidateTokenResponse, error)
|
||
}
|
||
```
|
||
|
||
### 1.3 实现流程
|
||
|
||
#### 1.3.1 注册流程
|
||
|
||
1. 参数验证(手机号、密码、昵称、star_id)
|
||
2. 验证手机号是否已存在
|
||
3. 验证明星是否存在
|
||
4. 使用事务创建用户和粉丝档案
|
||
- 创建用户(加密密码)
|
||
- 创建第一个粉丝档案
|
||
- 生成JWT Token
|
||
- 更新用户Token
|
||
5. 返回Token和用户信息
|
||
|
||
#### 1.3.2 登录流程
|
||
|
||
1. 参数验证(手机号、密码)
|
||
2. 根据手机号查询用户
|
||
3. 验证密码(bcrypt比对)
|
||
4. 验证用户是否激活
|
||
5. 获取用户的粉丝档案列表
|
||
6. 生成JWT Token(包含user_id和当前star_id)
|
||
7. 更新用户Token
|
||
8. 返回Token和用户信息
|
||
|
||
#### 1.3.3 Token刷新流程
|
||
|
||
1. 解析旧Token(即使过期也要解析)
|
||
2. 查询用户
|
||
3. 验证旧Token是否匹配数据库中的Token
|
||
4. 验证updated_at是否匹配(如果用户信息更新,Token失效)
|
||
5. 生成新Token
|
||
6. 更新数据库中的Token
|
||
7. 返回新Token
|
||
|
||
#### 1.3.4 Token验证流程
|
||
|
||
1. 解析和验证Token(检查签名和过期时间)
|
||
2. 查询用户验证Token是否匹配
|
||
3. 验证用户是否激活
|
||
4. 验证Token是否匹配数据库中的Token
|
||
5. 验证updated_at是否匹配
|
||
6. 返回验证结果
|
||
|
||
#### 1.3.5 登出流程
|
||
|
||
1. 从Token中提取user_id
|
||
2. 清除用户Token
|
||
|
||
### 1.4 依赖
|
||
|
||
- `UserRepository` - 用户数据访问
|
||
- `FanProfileRepository` - 粉丝档案数据访问
|
||
- `StarRepository` - 明星信息数据访问
|
||
- `JWT工具` - Token生成和解析
|
||
- `Logger` - 日志记录
|
||
- `Validator` - 参数验证
|
||
|
||
### 1.5 使用示例
|
||
|
||
```go
|
||
// 创建Service实例
|
||
userRepo := repository.NewUserRepository()
|
||
fanProfileRepo := repository.NewFanProfileRepository()
|
||
starRepo := repository.NewStarRepository()
|
||
db := database.GetDB()
|
||
|
||
authService := NewAuthService(userRepo, fanProfileRepo, starRepo, db)
|
||
|
||
// 用户注册
|
||
registerReq := &pb.RegisterRequest{
|
||
Mobile: "13800138000",
|
||
Password: "123456",
|
||
StarId: 1,
|
||
Nickname: "粉丝昵称",
|
||
}
|
||
registerResp, err := authService.Register(registerReq)
|
||
|
||
// 用户登录
|
||
loginReq := &pb.LoginRequest{
|
||
Mobile: "13800138000",
|
||
Password: "123456",
|
||
}
|
||
loginResp, err := authService.Login(loginReq)
|
||
|
||
// 刷新Token
|
||
refreshReq := &pb.RefreshTokenRequest{
|
||
AccessToken: "old_token_here",
|
||
}
|
||
refreshResp, err := authService.RefreshToken(refreshReq)
|
||
|
||
// 验证Token
|
||
validateReq := &pb.ValidateTokenRequest{
|
||
AccessToken: "token_here",
|
||
}
|
||
validateResp, err := authService.ValidateToken(validateReq)
|
||
|
||
// 登出
|
||
logoutReq := &pb.LogoutRequest{
|
||
AccessToken: "token_here",
|
||
}
|
||
logoutResp, err := authService.Logout(logoutReq)
|
||
```
|
||
|
||
### 1.6 错误处理
|
||
|
||
Service层返回的错误类型:
|
||
- `ErrUserNotFound` - 用户不存在
|
||
- `ErrUserAlreadyExists` - 用户已存在
|
||
- `ErrInvalidPassword` - 密码错误
|
||
- `ErrInvalidToken` - Token无效
|
||
- `ErrTokenExpired` - Token过期
|
||
- `ErrTokenMismatch` - Token不匹配
|
||
- `ErrUserInactive` - 用户未激活
|
||
- `ErrInvalidMobile` - 手机号格式错误
|
||
- `ErrPasswordTooShort` - 密码太短
|
||
- `ErrInvalidStarID` - 明星ID无效
|
||
- `ErrStarNotFound` - 明星不存在
|
||
|
||
所有错误都会被记录到日志中,便于调试和监控。
|
||
|
||
### 1.7 注意事项
|
||
|
||
1. **事务处理**:注册流程使用数据库事务,确保用户和粉丝档案的创建原子性
|
||
2. **密码安全**:密码使用bcrypt加密存储,不存储明文
|
||
3. **Token管理**:Token存储在数据库中,支持单设备登录
|
||
4. **Token失效**:当用户信息更新(updated_at改变)时,旧Token会自动失效
|
||
5. **日志记录**:所有关键操作都会记录日志,包括成功和失败场景
|
||
|
||
### 1.8 测试要点
|
||
|
||
- 注册成功和失败场景
|
||
- 登录成功和失败场景
|
||
- Token生成和验证
|
||
- Token刷新
|
||
- 修改密码后Token失效
|
||
- 用户信息更新后Token失效
|
||
|
||
---
|
||
|
||
## 二、用户信息Service(UserService)
|
||
|
||
### 2.1 功能概述
|
||
|
||
实现了用户信息相关的核心功能,包括:
|
||
- 获取用户信息
|
||
- 获取粉丝档案
|
||
- 获取个人信息页数据
|
||
- 修改昵称
|
||
- 修改密码
|
||
|
||
### 2.2 接口定义
|
||
|
||
```go
|
||
type UserService interface {
|
||
// GetUser 获取用户信息
|
||
GetUser(req *pb.GetUserRequest) (*pb.GetUserResponse, error)
|
||
|
||
// GetFanProfile 获取粉丝档案
|
||
GetFanProfile(req *pb.GetFanProfileRequest) (*pb.GetFanProfileResponse, error)
|
||
|
||
// GetMyProfile 获取个人信息页
|
||
GetMyProfile(req *pb.GetMyProfileRequest, userID, starID int64) (*pb.GetMyProfileResponse, error)
|
||
|
||
// UpdateNickname 修改昵称
|
||
UpdateNickname(req *pb.UpdateNicknameRequest, userID, starID int64) (*pb.UpdateNicknameResponse, error)
|
||
|
||
// UpdatePassword 修改密码
|
||
UpdatePassword(req *pb.UpdatePasswordRequest, userID int64) (*pb.UpdatePasswordResponse, error)
|
||
}
|
||
```
|
||
|
||
### 2.3 实现流程
|
||
|
||
#### 2.3.1 获取用户信息流程
|
||
|
||
1. 参数验证(user_id)
|
||
2. 查询用户
|
||
3. 返回用户信息
|
||
|
||
#### 2.3.2 获取粉丝档案流程
|
||
|
||
1. 参数验证(user_id, star_id)
|
||
2. 查询粉丝档案
|
||
3. 返回粉丝档案信息
|
||
|
||
#### 2.3.3 获取个人信息页流程
|
||
|
||
1. 参数验证(user_id, star_id)
|
||
2. 查询用户信息
|
||
3. 查询当前粉丝档案
|
||
4. 查询用户的所有粉丝身份
|
||
5. 聚合返回完整信息
|
||
|
||
#### 2.3.4 修改昵称流程
|
||
|
||
1. 参数验证(user_id, star_id, nickname)
|
||
2. 验证粉丝档案是否存在
|
||
3. 更新昵称
|
||
4. 查询更新后的粉丝档案
|
||
5. 返回更新后的信息
|
||
|
||
#### 2.3.5 修改密码流程
|
||
|
||
1. 参数验证(user_id, old_password, new_password)
|
||
2. 查询用户
|
||
3. 验证旧密码
|
||
4. 加密新密码
|
||
5. 使用事务更新密码和updated_at,清除Token
|
||
6. 返回成功响应
|
||
|
||
**重要**:修改密码时,会更新`updated_at`并清除Token,导致旧Token失效,需要重新登录。
|
||
|
||
### 2.4 依赖
|
||
|
||
- `UserRepository` - 用户数据访问
|
||
- `FanProfileRepository` - 粉丝档案数据访问
|
||
|
||
### 2.5 使用示例
|
||
|
||
```go
|
||
// 创建Service实例
|
||
userRepo := repository.NewUserRepository()
|
||
fanProfileRepo := repository.NewFanProfileRepository()
|
||
db := database.GetDB()
|
||
|
||
userService := NewUserService(userRepo, fanProfileRepo, db)
|
||
|
||
// 获取用户信息
|
||
getUserReq := &pb.GetUserRequest{
|
||
UserId: 10000001,
|
||
}
|
||
getUserResp, err := userService.GetUser(getUserReq)
|
||
|
||
// 获取粉丝档案
|
||
getFanProfileReq := &pb.GetFanProfileRequest{
|
||
UserId: 10000001,
|
||
StarId: 1,
|
||
}
|
||
getFanProfileResp, err := userService.GetFanProfile(getFanProfileReq)
|
||
|
||
// 获取个人信息页
|
||
getMyProfileReq := &pb.GetMyProfileRequest{}
|
||
getMyProfileResp, err := userService.GetMyProfile(getMyProfileReq, 10000001, 1)
|
||
|
||
// 修改昵称
|
||
updateNicknameReq := &pb.UpdateNicknameRequest{
|
||
Nickname: "新昵称",
|
||
}
|
||
updateNicknameResp, err := userService.UpdateNickname(updateNicknameReq, 10000001, 1)
|
||
|
||
// 修改密码
|
||
updatePasswordReq := &pb.UpdatePasswordRequest{
|
||
OldPassword: "旧密码",
|
||
NewPassword: "新密码",
|
||
}
|
||
updatePasswordResp, err := userService.UpdatePassword(updatePasswordReq, 10000001)
|
||
```
|
||
|
||
### 2.6 错误处理
|
||
|
||
Service层返回的错误类型:
|
||
- `ErrUserNotFound` - 用户不存在
|
||
- `ErrFanProfileNotFound` - 粉丝档案不存在
|
||
- `ErrInvalidPassword` - 密码错误
|
||
- `ErrInvalidUserID` - 用户ID无效
|
||
- `ErrInvalidStarID` - 明星ID无效
|
||
- `ErrPasswordTooShort` - 密码太短
|
||
|
||
所有错误都会被记录到日志中,便于调试和监控。
|
||
|
||
### 2.7 注意事项
|
||
|
||
1. **密码安全**:修改密码时使用bcrypt加密存储新密码
|
||
2. **Token失效**:修改密码后,`updated_at`会更新,旧Token会自动失效
|
||
3. **事务处理**:修改密码使用数据库事务,确保密码更新和Token清除的原子性
|
||
4. **数据聚合**:获取个人信息页需要聚合用户信息、当前粉丝档案和所有粉丝身份
|
||
5. **日志记录**:所有关键操作都会记录日志,包括成功和失败场景
|
||
|
||
### 2.8 测试要点
|
||
|
||
- 获取用户信息成功和失败场景
|
||
- 获取粉丝档案成功和失败场景
|
||
- 获取个人信息页(数据聚合)
|
||
- 修改昵称成功和失败场景
|
||
- 修改密码成功和失败场景
|
||
- 修改密码后Token失效验证
|
||
|
||
---
|
||
|
||
## 三、粉丝身份Service(IdentityService)
|
||
|
||
### 3.1 功能概述
|
||
|
||
实现了粉丝身份相关的核心功能,包括:
|
||
- 获取可选粉丝身份列表(支持搜索)
|
||
- 新增粉丝身份(最多2个)
|
||
- 切换粉丝身份(生成新Token)
|
||
|
||
### 3.2 接口定义
|
||
|
||
```go
|
||
type IdentityService interface {
|
||
// GetFanIdentities 获取可选粉丝身份列表
|
||
GetFanIdentities(req *pb.GetFanIdentitiesRequest) (*pb.GetFanIdentitiesResponse, error)
|
||
|
||
// AddIdentity 新增粉丝身份
|
||
AddIdentity(req *pb.AddIdentityRequest, userID int64) (*pb.AddIdentityResponse, error)
|
||
|
||
// SwitchIdentity 切换粉丝身份
|
||
SwitchIdentity(req *pb.SwitchIdentityRequest, userID int64, currentStarID int64) (*pb.SwitchIdentityResponse, error)
|
||
}
|
||
```
|
||
|
||
### 3.3 实现流程
|
||
|
||
#### 3.3.1 获取可选粉丝身份列表流程
|
||
|
||
1. 如果有关键词,调用Search搜索;否则调用GetAllActive获取所有可用明星
|
||
2. 转换为proto类型
|
||
3. 返回明星列表
|
||
|
||
#### 3.3.2 新增粉丝身份流程
|
||
|
||
1. 参数验证(user_id, star_id, nickname)
|
||
2. 检查用户已有的粉丝身份数量(最多2个)
|
||
3. 验证明星是否存在
|
||
4. 检查该用户是否已有该明星的身份
|
||
5. 创建新的粉丝档案
|
||
6. 返回新创建的粉丝档案
|
||
|
||
#### 3.3.3 切换粉丝身份流程
|
||
|
||
1. 参数验证(user_id, new_star_id)
|
||
2. 检查是否切换到相同的身份
|
||
3. 查询用户
|
||
4. 验证新身份是否存在
|
||
5. 生成新Token(包含新的star_id)
|
||
6. 更新用户Token
|
||
7. 返回新Token和粉丝档案
|
||
|
||
### 3.4 依赖
|
||
|
||
- `FanProfileRepository` - 粉丝档案数据访问
|
||
- `StarRepository` - 明星信息数据访问
|
||
- `UserRepository` - 用户数据访问(用于切换身份时更新Token)
|
||
- `JWT工具` - Token生成(切换身份时)
|
||
|
||
### 3.5 使用示例
|
||
|
||
```go
|
||
// 创建Service实例
|
||
fanProfileRepo := repository.NewFanProfileRepository()
|
||
starRepo := repository.NewStarRepository()
|
||
userRepo := repository.NewUserRepository()
|
||
db := database.GetDB()
|
||
|
||
identityService := NewIdentityService(fanProfileRepo, starRepo, userRepo, db)
|
||
|
||
// 获取可选粉丝身份列表
|
||
getFanIdentitiesReq := &pb.GetFanIdentitiesRequest{
|
||
Keyword: "明星", // 可选,为空则返回所有
|
||
}
|
||
getFanIdentitiesResp, err := identityService.GetFanIdentities(getFanIdentitiesReq)
|
||
|
||
// 新增粉丝身份
|
||
addIdentityReq := &pb.AddIdentityRequest{
|
||
StarId: 2,
|
||
Nickname: "新身份昵称",
|
||
}
|
||
addIdentityResp, err := identityService.AddIdentity(addIdentityReq, 10000001)
|
||
|
||
// 切换粉丝身份
|
||
switchIdentityReq := &pb.SwitchIdentityRequest{
|
||
NewStarId: 2,
|
||
}
|
||
switchIdentityResp, err := identityService.SwitchIdentity(switchIdentityReq, 10000001, 1)
|
||
```
|
||
|
||
### 3.6 错误处理
|
||
|
||
Service层返回的错误类型:
|
||
- `ErrFanProfileNotFound` - 粉丝档案不存在
|
||
- `ErrStarNotFound` - 明星不存在
|
||
- `ErrInvalidStarID` - 明星ID无效
|
||
- `ErrMaxIdentitiesReached` - 已达到最大身份数量(最多2个)
|
||
|
||
所有错误都会被记录到日志中,便于调试和监控。
|
||
|
||
### 3.7 注意事项
|
||
|
||
1. **身份数量限制**:一个用户最多可以拥有2个粉丝身份,新增时会检查
|
||
2. **Token更新**:切换身份时会生成新的JWT Token,包含新的star_id
|
||
3. **重复检查**:新增身份时会检查用户是否已有该明星的身份
|
||
4. **日志记录**:所有关键操作都会记录日志,包括成功和失败场景
|
||
|
||
### 3.8 测试要点
|
||
|
||
- 获取可选粉丝身份列表(带关键词和不带关键词)
|
||
- 新增粉丝身份成功和失败场景
|
||
- 新增身份时数量限制检查(最多2个)
|
||
- 切换粉丝身份成功和失败场景
|
||
- 切换到相同身份的处理
|
||
- 切换身份后Token更新验证
|
||
|