消息通知系统
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -282,6 +282,12 @@
|
|||||||
<artifactId>itextpdf</artifactId>
|
<artifactId>itextpdf</artifactId>
|
||||||
<version>5.5.13.2</version>
|
<version>5.5.13.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
"/api/third/party/existNoLoginRequired","/api/third/party/getRedirectUrl",
|
||||||
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
"/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify",
|
||||||
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
"/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease",
|
||||||
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify"
|
"/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify",
|
||||||
|
"/notification"
|
||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.ai.da.common.websocket;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.websocket.*;
|
||||||
|
import javax.websocket.server.ServerEndpoint;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@ServerEndpoint(value = "/notification")
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class NotificationConnection {
|
||||||
|
|
||||||
|
static Map<String,Session> sessionMap = new ConcurrentHashMap<>();
|
||||||
|
//连接建立时执行的操作
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session){
|
||||||
|
sessionMap.put(session.getId(),session);
|
||||||
|
log.info("websocket is open");
|
||||||
|
}
|
||||||
|
//收到了客户端消息执行的操作
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(String text){
|
||||||
|
log.info("收到了一条消息:"+text);
|
||||||
|
// return "已收到你的消息";
|
||||||
|
}
|
||||||
|
//连接关闭的时候执行的操作
|
||||||
|
@OnClose
|
||||||
|
public void onClose(Session session){
|
||||||
|
sessionMap.remove(session.getId());
|
||||||
|
log.info("websocket is close");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMsg(String message) throws IOException {
|
||||||
|
for(String key:sessionMap.keySet()){
|
||||||
|
sessionMap.get(key).getBasicRemote().sendText(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.ai.da.common.websocket.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of WebSocket
|
||||||
|
*
|
||||||
|
* @author db1995
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketConfig {
|
||||||
|
@Bean
|
||||||
|
public ServerEndpointExporter serverEndpointExporter() {
|
||||||
|
return new ServerEndpointExporter();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.ai.da.controller;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.PageBaseResponse;
|
||||||
|
import com.ai.da.common.response.Response;
|
||||||
|
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.MessageCenterService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Api(tags = "消息中心模块")
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/message")
|
||||||
|
public class MessageCenterController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MessageCenterService messageCenterService;
|
||||||
|
|
||||||
|
// 获取未读消息总数
|
||||||
|
@ApiOperation(value = "获取未读消息数")
|
||||||
|
@GetMapping("/getUnreadCount")
|
||||||
|
public Response<Map<String, Long>> getUnreadMessage(){
|
||||||
|
return Response.success(messageCenterService.getAllTypeMessageUnreadCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取历史消息
|
||||||
|
@ApiOperation(value = "获取历史消息")
|
||||||
|
@PostMapping("/getHistoryNotification")
|
||||||
|
public Response<PageBaseResponse<NotificationVO>> getHistoryNotification(@Valid @RequestBody GetNotificationVO getNotificationVO) {
|
||||||
|
return Response.success(messageCenterService.getHistoryNotification(getNotificationVO));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已读消息
|
||||||
|
@ApiOperation(value = "设置消息状态为已读")
|
||||||
|
@PostMapping("/setReadStatus")
|
||||||
|
public Response<Boolean> setReadStatus(@RequestParam("notificationIdList") List<Long> notificationIdList, @RequestParam("type") String type) {
|
||||||
|
return Response.success(messageCenterService.setReadStatus(notificationIdList, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布系统消息
|
||||||
|
@ApiOperation(value = "发布系统消息")
|
||||||
|
@PostMapping("/publishSysMessage")
|
||||||
|
public Response<String> publishSysMessage(@Valid @RequestBody PublishSysNotificationVO message) {
|
||||||
|
messageCenterService.publishSystemNotification(message);
|
||||||
|
return Response.success("success");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ai.da.mapper.primary;
|
||||||
|
|
||||||
|
import com.ai.da.common.config.mybatis.plus.CommonMapper;
|
||||||
|
import com.ai.da.mapper.primary.entity.Notification;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface NotificationMapper extends CommonMapper<Notification> {
|
||||||
|
|
||||||
|
List<Map<String, Object>> getTypeCount(Long receiverId);
|
||||||
|
|
||||||
|
/** 解决mybatis-plus自动过滤 is_deleted为1的数据 问题 */
|
||||||
|
Notification getUniqueLikeAndFollow(String type, Long senderId, Long receiverId, Long portfolioId);
|
||||||
|
|
||||||
|
void updateUniqueLikeAndFollow(Long id, LocalDateTime time);
|
||||||
|
|
||||||
|
void deleteNotification(Long id, LocalDateTime time);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ai.da.mapper.primary;
|
||||||
|
|
||||||
|
import com.ai.da.common.config.mybatis.plus.CommonMapper;
|
||||||
|
import com.ai.da.mapper.primary.entity.SysNotificationReadStatus;
|
||||||
|
|
||||||
|
public interface SysNotificationReadStatusMapper extends CommonMapper<SysNotificationReadStatus> {
|
||||||
|
}
|
||||||
@@ -99,4 +99,9 @@ public class Account implements Serializable {
|
|||||||
* 4 : 参加活动获取30天有效期和6000个积分的用户
|
* 4 : 参加活动获取30天有效期和6000个积分的用户
|
||||||
*/
|
*/
|
||||||
private Integer systemUser;
|
private Integer systemUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.ai.da.mapper.primary.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("t_notification")
|
||||||
|
@Data
|
||||||
|
public class Notification extends BaseEntity{
|
||||||
|
/**
|
||||||
|
* 操作类型 system/like/comment/follow
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 发起操作者用户id
|
||||||
|
*/
|
||||||
|
private Long senderId;
|
||||||
|
/**
|
||||||
|
* 被操作对象用户id
|
||||||
|
*/
|
||||||
|
private Long receiverId;
|
||||||
|
/**
|
||||||
|
* 点赞评论时的作品id
|
||||||
|
*/
|
||||||
|
private Long portfolioId;
|
||||||
|
/**
|
||||||
|
* 消息内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
/**
|
||||||
|
* 评论id
|
||||||
|
*/
|
||||||
|
private Long commentId;
|
||||||
|
/**
|
||||||
|
* 个人消息已读状态
|
||||||
|
*/
|
||||||
|
private Integer isRead;
|
||||||
|
/**
|
||||||
|
* 系统消息发布状态
|
||||||
|
*/
|
||||||
|
private Integer publishFlag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否被删除
|
||||||
|
*/
|
||||||
|
private Integer isDeleted;
|
||||||
|
|
||||||
|
public Notification() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Notification(String type, Long senderId, Long receiverId, Long portfolioId) {
|
||||||
|
this.type = type;
|
||||||
|
this.senderId = senderId;
|
||||||
|
this.receiverId = receiverId;
|
||||||
|
this.portfolioId = portfolioId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Notification(String type, Long senderId, Long receiverId, Long portfolioId, String content, Long commentId) {
|
||||||
|
this.type = type;
|
||||||
|
this.senderId = senderId;
|
||||||
|
this.receiverId = receiverId;
|
||||||
|
this.portfolioId = portfolioId;
|
||||||
|
this.content = content;
|
||||||
|
this.commentId = commentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ai.da.mapper.primary.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("t_sys_notification_read_status")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SysNotificationReadStatus extends BaseEntity{
|
||||||
|
/**
|
||||||
|
* 系统消息id
|
||||||
|
*/
|
||||||
|
private Long system_notification_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已读当前消息的用户id将被存储
|
||||||
|
*/
|
||||||
|
private Long account_id;
|
||||||
|
}
|
||||||
15
src/main/java/com/ai/da/model/vo/GetNotificationVO.java
Normal file
15
src/main/java/com/ai/da/model/vo/GetNotificationVO.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package com.ai.da.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ApiModel
|
||||||
|
@Data
|
||||||
|
public class GetNotificationVO extends PageQueryBaseVo{
|
||||||
|
|
||||||
|
@ApiModelProperty("system/like/comment/follow")
|
||||||
|
private String type;
|
||||||
|
}
|
||||||
17
src/main/java/com/ai/da/model/vo/NotificationVO.java
Normal file
17
src/main/java/com/ai/da/model/vo/NotificationVO.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ai.da.model.vo;
|
||||||
|
|
||||||
|
import com.ai.da.mapper.primary.entity.Notification;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class NotificationVO extends Notification {
|
||||||
|
|
||||||
|
private String senderUserName;
|
||||||
|
|
||||||
|
private String senderUserAvatar;
|
||||||
|
|
||||||
|
private String portfolioName;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.ai.da.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("发布系统消息")
|
||||||
|
public class PublishSysNotificationVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("系统消息标题")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@ApiModelProperty("系统消息内容")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@ApiModelProperty("系统消息 活动链接")
|
||||||
|
private String link;
|
||||||
|
}
|
||||||
@@ -3349,6 +3349,7 @@ public class PythonService {
|
|||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("promptTranslation 用户输入翻译失败; error message => " + e.getMessage());
|
log.error("promptTranslation 用户输入翻译失败; error message => " + e.getMessage());
|
||||||
|
response.close();
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
26
src/main/java/com/ai/da/service/MessageCenterService.java
Normal file
26
src/main/java/com/ai/da/service/MessageCenterService.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package com.ai.da.service;
|
||||||
|
|
||||||
|
import com.ai.da.common.response.PageBaseResponse;
|
||||||
|
import com.ai.da.mapper.primary.entity.Notification;
|
||||||
|
import com.ai.da.model.vo.GetNotificationVO;
|
||||||
|
import com.ai.da.model.vo.NotificationVO;
|
||||||
|
import com.ai.da.model.vo.PublishSysNotificationVO;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface MessageCenterService extends IService<Notification> {
|
||||||
|
|
||||||
|
Map<String, Long> getAllTypeMessageUnreadCount();
|
||||||
|
|
||||||
|
PageBaseResponse<NotificationVO> getHistoryNotification(GetNotificationVO getNotificationVO);
|
||||||
|
|
||||||
|
void prePushMessage(Notification notification);
|
||||||
|
|
||||||
|
void cancelPushMessage(String type, Long senderId, Long receiverId, Long portfolioId, Long commentId);
|
||||||
|
|
||||||
|
Boolean setReadStatus(List<Long> notificationIdList, String type);
|
||||||
|
|
||||||
|
void publishSystemNotification(PublishSysNotificationVO message);
|
||||||
|
}
|
||||||
@@ -1024,7 +1024,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
|||||||
account.setIsTrial(1);
|
account.setIsTrial(1);
|
||||||
account.setIsBeginner(1);
|
account.setIsBeginner(1);
|
||||||
account.setCreateDate(new Date());
|
account.setCreateDate(new Date());
|
||||||
account.setCredits(BigDecimal.valueOf(500));
|
account.setCredits(BigDecimal.valueOf(100));
|
||||||
accountMapper.insert(account);
|
accountMapper.insert(account);
|
||||||
AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
|
AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class);
|
||||||
response.setEmail(account.getUserEmail());
|
response.setEmail(account.getUserEmail());
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import sun.security.krb5.internal.crypto.Des;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -795,10 +794,16 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MessageCenterService messageCenterService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean like(Long id) {
|
public Boolean like(Long id) {
|
||||||
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
||||||
redisUtil.likePost(id, userHolder.getId());
|
redisUtil.likePost(id, userHolder.getId());
|
||||||
|
Portfolio byIdAll = baseMapper.getByIdAll(id);
|
||||||
|
messageCenterService.prePushMessage(new Notification("like", userHolder.getId(), byIdAll.getAccountId(), id));
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,6 +816,8 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
|
|||||||
comment.setCreateTime(LocalDateTime.now());
|
comment.setCreateTime(LocalDateTime.now());
|
||||||
comment.setAccountId(userHolder.getId());
|
comment.setAccountId(userHolder.getId());
|
||||||
commentMapper.insert(comment);
|
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;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,6 +844,8 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
|
|||||||
public Boolean unlike(Long id) {
|
public Boolean unlike(Long id) {
|
||||||
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
||||||
redisUtil.unLikePost(id, userHolder.getId());
|
redisUtil.unLikePost(id, userHolder.getId());
|
||||||
|
Portfolio portfolio = baseMapper.selectById(id);
|
||||||
|
messageCenterService.cancelPushMessage("like", userHolder.getId(), portfolio.getAccountId(), portfolio.getId(), null);
|
||||||
return Boolean.TRUE;
|
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");
|
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);
|
commentMapper.deleteById(id);
|
||||||
|
|
||||||
@@ -879,6 +897,7 @@ public class PortfolioServiceImpl extends ServiceImpl<PortfolioMapper, Portfolio
|
|||||||
.eq(Comment::getParentLevel2Id, id);
|
.eq(Comment::getParentLevel2Id, id);
|
||||||
commentMapper.delete(lambdaQueryWrapper);
|
commentMapper.delete(lambdaQueryWrapper);
|
||||||
|
|
||||||
|
messageCenterService.cancelPushMessage("comment", userHolder.getId(), receiverId, portfolio.getId(), id);
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
src/main/resources/mapper/primary/NotificationMapper.xml
Normal file
43
src/main/resources/mapper/primary/NotificationMapper.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ai.da.mapper.primary.NotificationMapper">
|
||||||
|
|
||||||
|
<select id="getTypeCount" resultType="java.util.Map">
|
||||||
|
SELECT type, count(id) as count
|
||||||
|
FROM `t_notification`
|
||||||
|
WHERE receiver_id = #{receiverId}
|
||||||
|
AND is_read = 0
|
||||||
|
GROUP BY type
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="getUniqueLikeAndFollow" resultType="com.ai.da.mapper.primary.entity.Notification">
|
||||||
|
SELECT *
|
||||||
|
FROM `t_notification`
|
||||||
|
WHERE type = #{type}
|
||||||
|
AND sender_id = #{senderId}
|
||||||
|
AND receiver_id = #{receiverId}
|
||||||
|
<if test="type == 'like'">
|
||||||
|
AND portfolio_id = #{portfolioId}
|
||||||
|
</if>
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateUniqueLikeAndFollow" >
|
||||||
|
UPDATE `t_notification`
|
||||||
|
SET
|
||||||
|
is_read = 0,
|
||||||
|
create_time = #{time},
|
||||||
|
update_time = #{time},
|
||||||
|
is_deleted = 0
|
||||||
|
WHERE id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="deleteNotification" >
|
||||||
|
UPDATE `t_notification`
|
||||||
|
SET
|
||||||
|
update_time = #{time},
|
||||||
|
is_deleted = 1
|
||||||
|
WHERE id = #{id}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user