|
…
|
||
|---|---|---|
| .. | ||
| asset_like_service.go | ||
| friend_service.go | ||
| random_user_algorithm.md | ||
| README.md | ||
| user_rpc_client.go | ||
Social Service - Service层说明
创建日期:2026-01-06
状态:✅ 已完成核心实现
📁 文件结构
service/
├── friend_service.go # 好友服务核心业务逻辑(约700行)
├── user_rpc_client.go # 跨服务RPC调用客户端(约230行)
└── README.md # 本文件
🎯 核心功能
1. friend_service.go - 好友服务
接口定义:FriendService
实现的功能:
好友请求相关(5个方法)
| 方法 | 功能 | 关键业务逻辑 |
|---|---|---|
SendFriendRequest |
发送好友请求 | 防骚扰检查、用户验证、过期时间计算 |
GetFriendRequests |
获取请求列表 | 分页查询、状态筛选、用户信息填充 |
HandleFriendRequest |
处理请求 | 权限验证、状态检查、事务保证 |
好友关系相关(5个方法)
| 方法 | 功能 | 关键业务逻辑 |
|---|---|---|
GetFriendList |
获取好友列表 | 分页查询、关键词搜索、用户信息填充 |
DeleteFriend |
删除好友 | 关系验证、双向删除 |
SetFriendRemark |
设置备注 | 长度验证、好友关系验证 |
CheckFriendship |
检查关系 | 简单查询 |
GetFriendCount |
统计数量 | 简单统计 |
2. user_rpc_client.go - RPC客户端
接口定义:UserServiceClient
实现的功能:
| 方法 | 功能 | 说明 |
|---|---|---|
ValidateUser |
验证用户存在 | 调用userService的GetUser接口 |
ValidateFanProfile |
验证粉丝档案 | 调用userService的GetFanProfile接口 |
GetUsersByIDs |
批量查询用户 | 批量获取用户信息和粉丝档案 |
UpdateFanProfileSocial |
更新好友数量 | 更新fan_profiles表的social字段(待实现) |
Mock实现:
- 提供了
MockUserServiceClient用于测试 - 可以添加Mock数据,模拟RPC调用
🔑 关键业务逻辑
1. 防骚扰机制 ⭐
实现位置:SendFriendRequest 方法
逻辑:
- 查询最近的请求记录(所有状态)
- 如果有待处理的请求 → 返回错误"已有待处理的好友请求"
- 如果最近被拒绝:
- 检查是否在7天冷却期内
- 在冷却期内 → 返回错误"请X天后再试"
- 已过冷却期 → 允许发送新请求
代码示例:
if latestRequest.Status == models.FriendRequestStatusRejected {
if s.config.IsInCooldownPeriod(*latestRequest.ProcessedAt) {
remainingDays := s.config.CalculateRemainingCooldownDays(*latestRequest.ProcessedAt);
return nil, fmt.Errorf("请求已被拒绝,请 %d 天后再试", remainingDays);
}
}
2. 过期检查 ⭐
实现位置:HandleFriendRequest 方法
逻辑:
- 创建请求时,设置
expires_at = created_at + 30天 - 处理请求前,检查是否已过期
- 已过期 → 自动更新状态为
expired,并返回错误
代码示例:
if friendRequest.ExpiresAt != nil && s.config.IsExpired(*friendRequest.ExpiresAt) {
processedAt := time.Now().UnixMilli();
_ = s.socialRepo.UpdateRequestStatus(req.RequestId, models.FriendRequestStatusExpired, &processedAt);
return nil, fmt.Errorf("该请求已过期");
}
3. 用户验证 ⭐
实现位置:SendFriendRequest 方法
逻辑:
- 验证对方用户是否存在(调用userService)
- 验证对方是否是同一明星的粉丝(必须条件)
- 验证通过才能发送好友请求
代码示例:
// 验证用户存在
exists, err := s.userClient.ValidateUser(ctx, req.FriendUserId);
if !exists {
return nil, fmt.Errorf("对方用户不存在");
}
// 验证粉丝档案存在
exists, err = s.userClient.ValidateFanProfile(ctx, req.FriendUserId, starID);
if !exists {
return nil, fmt.Errorf("对方不是该明星的粉丝");
}
4. 事务保证 ⭐
实现位置:HandleFriendRequest 方法(接受请求)
逻辑: 使用数据库事务保证以下操作的原子性:
- 更新请求状态为
accepted - 创建双向好友关系(A→B 和 B→A)
- 更新双方的social字段(好友数量)
代码示例:
err = s.db.Transaction(func(tx *gorm.DB) error {
// 1. 更新请求状态
if err := s.socialRepo.UpdateRequestStatus(req.RequestId, newStatus, &processedAt); err != nil {
return err;
}
// 2. 创建双向好友关系
if err := s.socialRepo.CreateFriendshipPair(friendRequest.FromUserID, friendRequest.ToUserID, starID); err != nil {
return err;
}
// 3. 更新social字段
// TODO: 实现
return nil;
});
5. 批量查询优化 ⭐
实现位置:fillRequestUserInfo 和 fillFriendshipUserInfo 方法
逻辑:
- 收集所有需要查询的用户ID
- 批量调用RPC接口查询用户信息
- 填充到响应对象中
代码示例:
// 收集用户ID
userIDs := make([]int64, 0, len(requests)*2);
for _, req := range requests {
userIDs = append(userIDs, req.FromUserID, req.ToUserID);
}
// 批量查询
userInfoMap, err := s.userClient.GetUsersByIDs(ctx, userIDs, starID);
// 填充信息
for _, req := range requests {
if fromUser, ok := userInfoMap[req.FromUserID]; ok {
item.FromUserNickname = fromUser.Nickname;
item.FromUserAvatar = fromUser.Avatar;
item.FromUserFanLevel = fromUser.FanLevel;
}
}
📦 依赖关系
FriendService
├── SocialRepository # 数据访问层
├── UserServiceClient # RPC客户端(调用userService)
├── gorm.DB # 数据库事务
└── SocialConfig # 配置(时间限制等)
🔧 配置说明
配置文件位于:services/socialService/config/social_config.go
时间配置
- 冷却期:7天(
RejectionCooldownDays) - 过期时间:30天(
RequestExpiryDays)
好友数量限制(预留)
- 启用状态:
false(默认不启用) - 默认限制:0(不限制)
- 最大限制:10000(预留)
📝 待实现功能
1. 更新social字段(高优先级)
需要在userService中添加接口:
// UpdateSocial 更新粉丝档案的social字段
rpc UpdateSocial(UpdateSocialRequest) returns (UpdateSocialResponse);
调用时机:
- 接受好友请求:双方
social += 1 - 删除好友:双方
social -= 1
2. 批量查询优化(中优先级)
需要在userService中添加接口:
// BatchGetFanProfiles 批量获取粉丝档案
rpc BatchGetFanProfiles(BatchGetFanProfilesRequest) returns (BatchGetFanProfilesResponse);
当前实现:逐个查询(性能较差)
优化后:一次RPC调用获取所有用户信息
3. 定时任务:清理过期请求(低优先级)
功能:定时扫描过期的好友请求,更新状态为expired
实现方式:
- 创建定时任务(cron job)
- 每天凌晨扫描一次
- 批量更新过期请求状态
✅ 已验证的功能
- 参数验证(空值、格式、长度等)
- 用户验证(用户存在、粉丝档案存在)
- 防骚扰机制(7天冷却期)
- 过期检查(30天过期)
- 好友关系检查(避免重复添加)
- 权限验证(只有接收者可以处理请求)
- 事务保证(接受请求时的原子性)
- 分页查询(好友列表、请求列表)
- 关键词搜索(搜索昵称或备注)
- 日志记录(所有关键操作)
🧪 测试建议
单元测试
测试文件:friend_service_test.go(待创建)
测试用例:
- 发送好友请求
- 正常流程
- 用户不存在
- 不是同一明星的粉丝
- 已经是好友
- 有待处理的请求
- 在冷却期内
- 获取请求列表
- 发出的请求
- 收到的请求
- 状态筛选
- 分页
- 处理请求
- 接受请求
- 拒绝请求
- 无权限
- 已过期
- 获取好友列表
- 正常查询
- 关键词搜索
- 分页
- 删除好友
- 正常删除
- 不是好友
- 设置备注
- 正常设置
- 备注过长
- 不是好友
集成测试
测试场景:
- 完整业务流程:发送请求 → 接受 → 成为好友 → 设置备注 → 删除好友
- 防骚扰机制:发送 → 拒绝 → 尝试再次发送(冷却期内) → 等待7天 → 再次发送成功
- 过期机制:发送 → 等待30天 → 尝试接受(已过期)
📚 相关文档
- 设计文档:
docs/好友功能设计方案.md - 设计决策:
docs/好友功能设计决策汇总.md - Repository层:
services/socialService/repository/social_repository.go - Proto定义:
proto/social.proto - 配置文件:
services/socialService/config/social_config.go
创建人:AI Assistant
创建日期:2026-01-06
状态:✅ 核心功能已实现,待测试和优化