消息通知系统

This commit is contained in:
2024-08-15 16:25:44 +08:00
parent 704e3c25bf
commit 085dac0630
20 changed files with 768 additions and 136 deletions

View File

@@ -1024,7 +1024,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
account.setIsTrial(1);
account.setIsBeginner(1);
account.setCreateDate(new Date());
account.setCredits(BigDecimal.valueOf(500));
account.setCredits(BigDecimal.valueOf(100));
accountMapper.insert(account);
AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
response.setEmail(account.getUserEmail());

View File

@@ -744,7 +744,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
redisUtil.addToString(key, new Gson().toJson(generateResultVO), CommonConstant.GENERATE_RESULT_EXPIRE_TIME);
Long accountId = Long.parseLong(taskId.substring(taskId.lastIndexOf("-") + 1));
if (!status.equals("Invalid")){
if (!status.equals("Invalid")) {
// 4、扣除积分
Boolean b = creditsService.taskCreditsDeduction(accountId, taskId);
// 3、记录积分变更

View File

@@ -0,0 +1,243 @@
package com.ai.da.service.impl;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.common.websocket.NotificationConnection;
import com.ai.da.mapper.primary.NotificationMapper;
import com.ai.da.mapper.primary.SysNotificationReadStatusMapper;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.Notification;
import com.ai.da.mapper.primary.entity.SysNotificationReadStatus;
import com.ai.da.model.vo.GetNotificationVO;
import com.ai.da.model.vo.NotificationVO;
import com.ai.da.model.vo.PublishSysNotificationVO;
import com.ai.da.service.AccountService;
import com.ai.da.service.MessageCenterService;
import com.ai.da.service.PortfolioService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class MessageCenterServiceImpl extends ServiceImpl<NotificationMapper, Notification> implements MessageCenterService {
@Resource
private NotificationConnection notificationConnection;
@Resource
private SysNotificationReadStatusMapper sysNotificationReadStatusMapper;
@Resource
private AccountService accountService;
@Resource
private MinioUtil minioUtil;
@Resource
private PortfolioService portfolioService;
@Override
public Map<String, Long> getAllTypeMessageUnreadCount() {
List<Map<String, Object>> typeCount = baseMapper.getTypeCount(UserContext.getUserHolder().getId());
Map<String, Long> msgTypeCount = typeCount.stream()
.collect(Collectors.toMap(
map -> (String) map.get("type"),
map -> Objects.isNull(map.get("count")) ? 0L : (Long) map.get("count")));
msgTypeCount.put("system", getUnreadSystemNotification());
log.info(msgTypeCount.toString());
// 整理数据 加上系统消息未读数
return msgTypeCount;
}
// 获取历史消息 可指定消息类型 分页查询
@Override
public PageBaseResponse<NotificationVO> getHistoryNotification(GetNotificationVO getNotificationVO) {
QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isNullOrEmpty(getNotificationVO.getType())) {
queryWrapper.eq("type", getNotificationVO.getType());
}
queryWrapper.eq("receiver_id", UserContext.getUserHolder().getId());
Page<Notification> notificationPage = baseMapper.selectPage(new Page<>(getNotificationVO.getPage(), getNotificationVO.getSize()), queryWrapper);
IPage<NotificationVO> convert = notificationPage.convert(o -> {
NotificationVO notificationVO = CopyUtil.copyObject(o, NotificationVO.class);
Account account = accountService.getById(notificationVO.getSenderId());
notificationVO.setSenderUserName(account.getUserName());
notificationVO.setSenderUserAvatar(StringUtils.isNullOrEmpty(account.getAvatar()) ? null : minioUtil.getPreSignedUrl(account.getAvatar(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME));
notificationVO.setPortfolioName(portfolioService.getById(notificationVO.getPortfolioId()).getPortfolioName());
return notificationVO;
});
return PageBaseResponse.success(convert);
}
public void prePushMessage(Notification notification){
// 先判断点赞、关注记录是不是唯一
if (!getUniqueLikeAndFollow(notification)){
// 1、将数据存数据库
if (!notification.getType().equals("system")) {
notification.setIsRead(0);
}
notification.setIsDeleted(0);
notification.setCreateTime(LocalDateTime.now());
save(notification);
}
// 推送消息
pushMessage(notification.getType(), notification.getSenderId());
}
/**
* 只记录唯一点赞和关注
* 重复点赞、关注只会记录最新的一次操作
* @param notification
* @return
*/
public Boolean getUniqueLikeAndFollow(Notification notification){
Notification existNotification= null;
// 对单个作品的点赞和对某个人的关注 具有唯一性
if (notification.getType().equals("like") || notification.getType().equals("follow")){
existNotification = baseMapper.getUniqueLikeAndFollow(notification.getType(), notification.getSenderId(),
notification.getReceiverId(), notification.getPortfolioId());
}
if (!Objects.isNull(existNotification)){
// 有记录,则更新 1、删除状态 为0 2、已读状态 为0 3、创建时间 为最新时间 4、更新时间 为最新时间
baseMapper.updateUniqueLikeAndFollow(existNotification.getId(), LocalDateTime.now());
return Boolean.TRUE;
}
return Boolean.FALSE;
}
// 消息推送 只需要返回当前操作类型和该操作未读消息数量
public void pushMessage(String type, Long senderId) {
// 推送消息到前端
ArrayList<Map<String, Object>> resp = new ArrayList<>();
HashMap<String, Object> data = new HashMap<>();
Long count;
if (!type.equals("system")) {
// 个人未读消息
count = getUnreadCountByType(type, senderId);
} else {
// 系统未读消息
count = getUnreadSystemNotification();
}
data.put(type, count);
resp.add(data);
String jsonString = JSON.toJSONString(resp);
log.info("消息推送 {}", jsonString);
try {
notificationConnection.sendMsg(jsonString);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 取消点赞、删除评论、取消关注
public void cancelPushMessage(String type, Long senderId, Long receiverId, Long portfolioId, Long commentId) {
QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", type)
.eq("sender_id", senderId)
.eq("receiver_id", receiverId)
.eq("is_deleted", 0);
if (!type.equals("follow")){
queryWrapper.eq("portfolio_id", portfolioId);
}
if (type.equals("comment")) {
queryWrapper.eq("comment_id", commentId);
}
Notification notification = baseMapper.selectOne(queryWrapper);
if (!Objects.isNull(notification)) {
baseMapper.deleteNotification(notification.getId(), LocalDateTime.now());
}
// 推送消息
pushMessage(type, senderId);
}
// 获取个人指定消息类型未读消息数量
private Long getUnreadCountByType(String type, Long receiverId) {
QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", type)
.eq("is_read", 0)
.eq("receiver_id", receiverId);
return baseMapper.selectCount(queryWrapper);
}
private Long getUnreadSystemNotification() {
// 计算总的系统通知数量
QueryWrapper<Notification> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", "system");
Long totalSysCount = baseMapper.selectCount(queryWrapper);
// 计算单个用户读了多少条系统数据
QueryWrapper<SysNotificationReadStatus> wrapper = new QueryWrapper<>();
wrapper.eq("account_id", UserContext.getUserHolder().getId());
Long readCount = sysNotificationReadStatusMapper.selectCount(wrapper);
// 计算差
return totalSysCount - readCount;
}
// 设置个人消息的已读状态 (允许一次已读多条个人消息)
public Boolean setReadStatus(List<Long> notificationIdList, String type) {
if (type.equals("system")) {
setReadStatusSystem(notificationIdList);
} else {
UpdateWrapper<Notification> updateWrapper = new UpdateWrapper<>();
updateWrapper.in("id", notificationIdList)
// .eq("type", type)
.set("is_read", 1)
.set("update_time", LocalDateTime.now());
baseMapper.update(null, updateWrapper);
}
return Boolean.TRUE;
}
// 设置系统消息的已读状态 (允许一次已读多条系统消息)
public void setReadStatusSystem(List<Long> notificationIdList) {
Long id = UserContext.getUserHolder().getId();
for (Long notificationId : notificationIdList) {
SysNotificationReadStatus sysNotificationReadStatus = new SysNotificationReadStatus(notificationId, id);
sysNotificationReadStatus.setCreateTime(LocalDateTime.now());
sysNotificationReadStatusMapper.insert(sysNotificationReadStatus);
}
}
// todo 全部已读
// 发布系统消息
public void publishSystemNotification(PublishSysNotificationVO message) {
Notification notification = new Notification();
notification.setType("system");
notification.setSenderId(UserContext.getUserHolder().getId());
notification.setContent(new Gson().toJson(message));
// todo 是否需要定时发送系统通知
prePushMessage(notification);
}
}

View File

@@ -25,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.security.krb5.internal.crypto.Des;
import javax.annotation.Resource;
import java.math.BigDecimal;
@@ -795,10 +794,16 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
@Resource
private RedisUtil redisUtil;
@Resource
private MessageCenterService messageCenterService;
@Override
public Boolean like(Long id) {
AuthPrincipalVo userHolder = UserContext.getUserHolder();
redisUtil.likePost(id, userHolder.getId());
Portfolio byIdAll = baseMapper.getByIdAll(id);
messageCenterService.prePushMessage(new Notification("like", userHolder.getId(), byIdAll.getAccountId(), id));
return Boolean.TRUE;
}
@@ -811,6 +816,8 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
comment.setCreateTime(LocalDateTime.now());
comment.setAccountId(userHolder.getId());
commentMapper.insert(comment);
Portfolio portfolio = baseMapper.selectById(comment.getPortfolioId());
messageCenterService.prePushMessage(new Notification("comment", userHolder.getId(), portfolio.getAccountId(), portfolio.getId(), commentDTO.getComment(), comment.getId()));
return Boolean.TRUE;
}
@@ -837,6 +844,8 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
public Boolean unlike(Long id) {
AuthPrincipalVo userHolder = UserContext.getUserHolder();
redisUtil.unLikePost(id, userHolder.getId());
Portfolio portfolio = baseMapper.selectById(id);
messageCenterService.cancelPushMessage("like", userHolder.getId(), portfolio.getAccountId(), portfolio.getId(), null);
return Boolean.TRUE;
}
@@ -869,6 +878,15 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
throw new BusinessException("You do not have the permission to delete this comment");
}
}
// 获取消息接收者id即该操作的接收者)
Long receiverId;
if (!comment.getParentLevel1Id().equals(0L)){
receiverId = commentMapper.selectById(comment.getParentLevel1Id()).getAccountId();
}else {
receiverId = portfolio.getAccountId();
}
// 删除主评论
commentMapper.deleteById(id);
@@ -879,6 +897,7 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
.eq(Comment::getParentLevel2Id, id);
commentMapper.delete(lambdaQueryWrapper);
messageCenterService.cancelPushMessage("comment", userHolder.getId(), receiverId, portfolio.getId(), id);
return Boolean.TRUE;
}