feat(通知服务): 实现通知服务基础功能并添加负载均衡依赖
All checks were successful
test/timeline-server/pipeline/head This commit looks good
All checks were successful
test/timeline-server/pipeline/head This commit looks good
- 添加Spring Cloud LoadBalancer依赖以支持服务间调用 - 实现NotificationService接口基础功能,包括通知创建、查询、标记已读等 - 使用内存存储实现通知管理,支持分页查询和按类型统计未读数
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
package com.timeline.story.service.impl;
|
||||
|
||||
import com.timeline.story.entity.Notification;
|
||||
import com.timeline.story.service.NotificationService;
|
||||
import com.timeline.story.vo.NotificationVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* NotificationServiceImpl - 消息通知服务实现类
|
||||
*
|
||||
* 功能描述:
|
||||
* 提供消息通知的管理和推送功能的内存实现。
|
||||
*
|
||||
* @author Timeline Team
|
||||
* @date 2024
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class NotificationServiceImpl implements NotificationService {
|
||||
|
||||
// 内存存储,实际生产环境应使用数据库
|
||||
private final Map<String, List<Notification>> userNotifications = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void createCommentNotification(String storyItemId, String commentId, String senderId) {
|
||||
log.info("创建评论通知: storyItemId={}, commentId={}, senderId={}", storyItemId, commentId, senderId);
|
||||
// TODO: 实现评论通知创建逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLikeNotification(String storyItemId, String senderId) {
|
||||
log.info("创建点赞通知: storyItemId={}, senderId={}", storyItemId, senderId);
|
||||
// TODO: 实现点赞通知创建逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createMentionNotification(String toUserId, String relatedType, String relatedId, String senderId) {
|
||||
log.info("创建@提及通知: toUserId={}, relatedType={}, relatedId={}, senderId={}",
|
||||
toUserId, relatedType, relatedId, senderId);
|
||||
// TODO: 实现@提及通知创建逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createInviteNotification(String storyId, String toUserId, String senderId) {
|
||||
log.info("创建邀请通知: storyId={}, toUserId={}, senderId={}", storyId, toUserId, senderId);
|
||||
// TODO: 实现邀请通知创建逻辑
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSystemNotification(String userId, String title, String content) {
|
||||
log.info("创建系统通知: userId={}, title={}", userId, title);
|
||||
|
||||
Notification notification = new Notification();
|
||||
notification.setInstanceId(UUID.randomUUID().toString());
|
||||
notification.setUserId(userId);
|
||||
notification.setType("SYSTEM");
|
||||
notification.setTitle(title);
|
||||
notification.setContent(content);
|
||||
notification.setIsRead(0);
|
||||
notification.setCreateTime(LocalDateTime.now());
|
||||
|
||||
userNotifications.computeIfAbsent(userId, k -> new ArrayList<>()).add(notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NotificationVo> getNotifications(String userId, String type, int pageNum, int pageSize) {
|
||||
log.info("获取通知列表: userId={}, type={}, pageNum={}, pageSize={}", userId, type, pageNum, pageSize);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
|
||||
if (type != null && !type.isEmpty()) {
|
||||
notifications = notifications.stream()
|
||||
.filter(n -> type.equals(n.getType()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 按时间倒序排序
|
||||
notifications.sort((a, b) -> b.getCreateTime().compareTo(a.getCreateTime()));
|
||||
|
||||
// 分页
|
||||
int start = (pageNum - 1) * pageSize;
|
||||
int end = Math.min(start + pageSize, notifications.size());
|
||||
|
||||
if (start >= notifications.size()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return notifications.subList(start, end).stream()
|
||||
.map(this::convertToVo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NotificationVo> getUnreadNotifications(String userId, int pageNum, int pageSize) {
|
||||
log.info("获取未读通知: userId={}, pageNum={}, pageSize={}", userId, pageNum, pageSize);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
|
||||
List<Notification> unreadList = notifications.stream()
|
||||
.filter(n -> n.getIsRead() != null && n.getIsRead() == 0)
|
||||
.sorted((a, b) -> b.getCreateTime().compareTo(a.getCreateTime()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int start = (pageNum - 1) * pageSize;
|
||||
int end = Math.min(start + pageSize, unreadList.size());
|
||||
|
||||
if (start >= unreadList.size()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return unreadList.subList(start, end).stream()
|
||||
.map(this::convertToVo)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnreadCount(String userId) {
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
return (int) notifications.stream()
|
||||
.filter(n -> n.getIsRead() != null && n.getIsRead() == 0)
|
||||
.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Integer> getUnreadCountByType(String userId) {
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
|
||||
Map<String, Integer> countByType = new HashMap<>();
|
||||
countByType.put("COMMENT", 0);
|
||||
countByType.put("LIKE", 0);
|
||||
countByType.put("MENTION", 0);
|
||||
countByType.put("INVITE", 0);
|
||||
countByType.put("SYSTEM", 0);
|
||||
|
||||
for (Notification n : notifications) {
|
||||
if (n.getIsRead() != null && n.getIsRead() == 0) {
|
||||
countByType.merge(n.getType(), 1, Integer::sum);
|
||||
}
|
||||
}
|
||||
|
||||
return countByType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsRead(String notificationInstanceId, String userId) {
|
||||
log.info("标记通知已读: notificationInstanceId={}, userId={}", notificationInstanceId, userId);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
for (Notification n : notifications) {
|
||||
if (notificationInstanceId.equals(n.getInstanceId())) {
|
||||
n.setIsRead(1);
|
||||
n.setReadTime(LocalDateTime.now());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAllAsRead(String userId) {
|
||||
log.info("标记所有通知已读: userId={}", userId);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
for (Notification n : notifications) {
|
||||
if (n.getIsRead() != null && n.getIsRead() == 0) {
|
||||
n.setIsRead(1);
|
||||
n.setReadTime(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAllAsReadByType(String userId, String type) {
|
||||
log.info("按类型标记所有通知已读: userId={}, type={}", userId, type);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
for (Notification n : notifications) {
|
||||
if (type.equals(n.getType()) && n.getIsRead() != null && n.getIsRead() == 0) {
|
||||
n.setIsRead(1);
|
||||
n.setReadTime(LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteNotification(String notificationInstanceId, String userId) {
|
||||
log.info("删除通知: notificationInstanceId={}, userId={}", notificationInstanceId, userId);
|
||||
|
||||
List<Notification> notifications = userNotifications.getOrDefault(userId, new ArrayList<>());
|
||||
notifications.removeIf(n -> notificationInstanceId.equals(n.getInstanceId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllNotifications(String userId) {
|
||||
log.info("清空所有通知: userId={}", userId);
|
||||
userNotifications.remove(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushNotification(String userId, Notification notification) {
|
||||
log.info("推送实时通知: userId={}, notification={}", userId, notification);
|
||||
// TODO: 实现 WebSocket 推送逻辑
|
||||
}
|
||||
|
||||
/**
|
||||
* 将实体转换为 VO
|
||||
*/
|
||||
private NotificationVo convertToVo(Notification notification) {
|
||||
NotificationVo vo = new NotificationVo();
|
||||
vo.setInstanceId(notification.getInstanceId());
|
||||
vo.setType(notification.getType());
|
||||
vo.setTypeDesc(getTypeDesc(notification.getType()));
|
||||
vo.setTitle(notification.getTitle());
|
||||
vo.setContent(notification.getContent());
|
||||
vo.setRelatedId(notification.getRelatedId());
|
||||
vo.setRelatedType(notification.getRelatedType());
|
||||
vo.setSenderId(notification.getSenderId());
|
||||
vo.setSenderName(notification.getSenderName());
|
||||
vo.setSenderAvatar(notification.getSenderAvatar());
|
||||
vo.setIsRead(notification.getIsRead() != null && notification.getIsRead() == 1);
|
||||
vo.setReadTime(notification.getReadTime());
|
||||
vo.setCreateTime(notification.getCreateTime());
|
||||
vo.setTimeAgo(calculateTimeAgo(notification.getCreateTime()));
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型描述
|
||||
*/
|
||||
private String getTypeDesc(String type) {
|
||||
return switch (type) {
|
||||
case "COMMENT" -> "评论";
|
||||
case "LIKE" -> "点赞";
|
||||
case "MENTION" -> "提及";
|
||||
case "INVITE" -> "邀请";
|
||||
case "SYSTEM" -> "系统";
|
||||
default -> "其他";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算相对时间
|
||||
*/
|
||||
private String calculateTimeAgo(LocalDateTime createTime) {
|
||||
if (createTime == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
long minutes = java.time.Duration.between(createTime, now).toMinutes();
|
||||
|
||||
if (minutes < 1) {
|
||||
return "刚刚";
|
||||
} else if (minutes < 60) {
|
||||
return minutes + "分钟前";
|
||||
} else if (minutes < 1440) {
|
||||
return (minutes / 60) + "小时前";
|
||||
} else {
|
||||
return (minutes / 1440) + "天前";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,12 @@
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud LoadBalancer -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Cloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
|
||||
Reference in New Issue
Block a user