feat: 通知公告临时提交
通知公告临时提交
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package com.youlai.boot.common.enums;
|
||||
|
||||
/**
|
||||
* 消息类型枚举
|
||||
* @author Theo
|
||||
* @since 2024-9-2 14:32:58
|
||||
*/
|
||||
public enum MessageTypeEnum {
|
||||
WEBSOCKET("webScoket", "websocket消息");
|
||||
|
||||
private String value;
|
||||
|
||||
private String label;
|
||||
|
||||
MessageTypeEnum(String value, String label) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
@@ -60,4 +60,8 @@ public class CommonUtil {
|
||||
return List.of(str.split(separator));
|
||||
}
|
||||
|
||||
|
||||
public static String delHtmlTags(String htmlStr) {
|
||||
return htmlStr.replaceAll("<[^>]+>", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.youlai.boot.platform.websocket.service;
|
||||
|
||||
import com.youlai.boot.common.enums.MessageTypeEnum;
|
||||
import com.youlai.boot.system.model.dto.MessageDTO;
|
||||
|
||||
/**
|
||||
* 消息服务接口
|
||||
*
|
||||
* @author Theo
|
||||
* @since 2024-9-2 14:32:58
|
||||
*/
|
||||
public interface MessageService {
|
||||
|
||||
|
||||
/**
|
||||
* 检查消息类型
|
||||
*
|
||||
* @param messageType 消息类型
|
||||
* @return 是否支持
|
||||
*/
|
||||
boolean check(MessageTypeEnum messageType);
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param message 消息
|
||||
*/
|
||||
void sendMessage(MessageDTO message);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.youlai.boot.platform.websocket.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface WebsocketService {
|
||||
|
||||
void addUser(String username);
|
||||
|
||||
void removeUser(String username) ;
|
||||
|
||||
Set<String> getUsers();
|
||||
/**
|
||||
* 发送消息到前端
|
||||
* @param message
|
||||
*/
|
||||
void sendStringToFrontend(String sender,String message);
|
||||
}
|
||||
@@ -1,42 +1,47 @@
|
||||
package com.youlai.boot.platform.websocket.service.impl;
|
||||
|
||||
import com.youlai.boot.platform.websocket.service.WebsocketService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.youlai.boot.common.enums.MessageTypeEnum;
|
||||
import com.youlai.boot.platform.websocket.service.MessageService;
|
||||
import com.youlai.boot.system.event.UserConnectionEvent;
|
||||
import com.youlai.boot.system.model.dto.ChatMessage;
|
||||
import com.youlai.boot.system.model.dto.MessageDTO;
|
||||
import com.youlai.boot.system.model.entity.User;
|
||||
import com.youlai.boot.system.service.UserService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.security.SecurityUtil;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* WebSocket消息服务实现类
|
||||
*
|
||||
* @author ray
|
||||
* @since 2024-9-2 14:32:58
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WebsocketServiceImpl implements WebsocketService {
|
||||
public class WebsocketServiceImpl implements MessageService {
|
||||
|
||||
private final SimpMessagingTemplate messagingTemplate;
|
||||
|
||||
private final Set<String> onlineUsers = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void addUser(String username) {
|
||||
onlineUsers.add(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUser(String username) {
|
||||
onlineUsers.remove(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUsers() {
|
||||
return onlineUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户连接事件处理
|
||||
*
|
||||
* @param event 用户连接事件
|
||||
*/
|
||||
@EventListener
|
||||
public void handleUserConnectionEvent(UserConnectionEvent event) {
|
||||
String username = event.getUsername();
|
||||
@@ -51,16 +56,44 @@ public class WebsocketServiceImpl implements WebsocketService {
|
||||
messagingTemplate.convertAndSend("/topic/onlineUserCount", onlineUsers.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时推送在线用户人数
|
||||
*/
|
||||
@Scheduled(fixedRate = 5000)
|
||||
public void sendOnlineUserCount() {
|
||||
messagingTemplate.convertAndSend("/topic/onlineUserCount", onlineUsers.size());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 策略模式检查
|
||||
*
|
||||
* @param messageType 消息类型
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public void sendStringToFrontend(String sender, String message) {
|
||||
ChatMessage chatMessage = new ChatMessage(sender, message);
|
||||
onlineUsers.forEach(receiver -> {
|
||||
messagingTemplate.convertAndSendToUser(receiver, "/topic/chat", chatMessage);
|
||||
public boolean check(MessageTypeEnum messageType) {
|
||||
return messageType.equals(MessageTypeEnum.WEBSOCKET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param message 消息
|
||||
*/
|
||||
@Override
|
||||
public void sendMessage(MessageDTO message) {
|
||||
List<String> users = null;
|
||||
if(message.getReceiver() == null || message.getReceiver().isEmpty()){
|
||||
// 发送给所有在线用户 离线用户不发送,因为离线用户下次登录会直接查询未读消息
|
||||
users = new ArrayList<>(onlineUsers);
|
||||
}else{
|
||||
users = message.getReceiver().stream().filter(onlineUsers::contains).collect(Collectors.toList());
|
||||
}
|
||||
//获取当前用户
|
||||
ChatMessage chatMessage = new ChatMessage(message.getSender(), message.getContent());
|
||||
users.forEach(receiver -> {
|
||||
messagingTemplate.convertAndSendToUser(receiver, "/queue/message", chatMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.youlai.boot.system.handler;
|
||||
|
||||
import com.youlai.boot.platform.websocket.service.MessageService;
|
||||
import com.youlai.boot.system.model.dto.MessageDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息处理器
|
||||
*
|
||||
* @author Theo
|
||||
* @since 2024-9-2 14:32:58
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MessageHandler {
|
||||
|
||||
private final List<MessageService> messageServices;
|
||||
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param messageDTO 消息载体
|
||||
*/
|
||||
public void sendMessage(MessageDTO messageDTO) {
|
||||
messageServices.forEach(messageService -> {
|
||||
if (messageService.check(messageDTO.getMessageType())) {
|
||||
messageService.sendMessage(messageDTO);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.youlai.boot.system.model.dto;
|
||||
|
||||
import com.youlai.boot.common.enums.MessageTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息载体
|
||||
*
|
||||
* @author Theo
|
||||
* @since 2024-9-2 14:32:58
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@Data
|
||||
public class MessageDTO {
|
||||
|
||||
@Schema(description = "消息内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "发送者")
|
||||
private String sender;
|
||||
|
||||
@Schema(description = "接收者")
|
||||
private List<String> receiver;
|
||||
|
||||
@Schema(description = "消息类型")
|
||||
private MessageTypeEnum messageType;
|
||||
}
|
||||
@@ -2,17 +2,20 @@ package com.youlai.boot.system.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
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.*;
|
||||
import com.youlai.boot.common.constant.SymbolConstant;
|
||||
import com.youlai.boot.common.enums.MessageTypeEnum;
|
||||
import com.youlai.boot.common.util.CommonUtil;
|
||||
import com.youlai.boot.core.security.util.SecurityUtils;
|
||||
import com.youlai.boot.platform.websocket.service.WebsocketService;
|
||||
import com.youlai.boot.system.converter.NoticeConverter;
|
||||
import com.youlai.boot.system.handler.MessageHandler;
|
||||
import com.youlai.boot.system.mapper.NoticeMapper;
|
||||
import com.youlai.boot.system.model.bo.NoticeBO;
|
||||
import com.youlai.boot.system.model.dto.MessageDTO;
|
||||
import com.youlai.boot.system.model.entity.Notice;
|
||||
import com.youlai.boot.system.model.entity.NoticeStatus;
|
||||
import com.youlai.boot.system.model.entity.User;
|
||||
@@ -30,6 +33,7 @@ import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 通知公告服务实现类
|
||||
@@ -43,24 +47,12 @@ public class NoticeServiceImpl extends ServiceImpl<NoticeMapper, Notice> impleme
|
||||
|
||||
private final NoticeConverter noticeConverter;
|
||||
|
||||
private final WebsocketService websocketService;
|
||||
private final MessageHandler messageHandler;
|
||||
|
||||
private final NoticeStatusService noticeStatusService;
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
private final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (localDateTime, type, jsonSerializationContext) ->
|
||||
new JsonPrimitive(localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)))
|
||||
.registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (jsonElement, type, jsonDeserializationContext) ->
|
||||
LocalDateTime.parse(jsonElement.getAsString(), DateTimeFormatter.ISO_LOCAL_DATE_TIME))
|
||||
.create();
|
||||
|
||||
private void sendWebSocketMsg(Notice notice) {
|
||||
String jsonNotice = gson.toJson(noticeConverter.toVO(notice));
|
||||
websocketService.sendStringToFrontend(SecurityUtils.getUsername(), jsonNotice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通知公告分页列表
|
||||
*
|
||||
@@ -181,10 +173,37 @@ public class NoticeServiceImpl extends ServiceImpl<NoticeMapper, Notice> impleme
|
||||
noticeStatusService.saveBatch(needSaveList);
|
||||
}
|
||||
//最后,给当前在线的用户发送websocket消息
|
||||
//TODO: 通知公告的websocket消息发送
|
||||
List<String> usernameList = null;
|
||||
if(notice.getTarType() == 1){
|
||||
List<Long> collect = needSaveList.stream().map(NoticeStatus::getUserId).collect(Collectors.toList());
|
||||
List<User> userList = userService.list(new LambdaQueryWrapper<User>().in(User::getId, collect).select(User::getUsername));
|
||||
usernameList = userList.stream().map(User::getUsername).collect(Collectors.toList());
|
||||
}
|
||||
MessageDTO message = new MessageDTO();
|
||||
message.setMessageType(MessageTypeEnum.WEBSOCKET);
|
||||
message.setReceiver(usernameList);
|
||||
message.setContent(getNoticeContent(notice));
|
||||
message.setSender(SecurityUtils.getUsername());
|
||||
messageHandler.sendMessage(message);
|
||||
return this.updateById(notice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义组合公告内容
|
||||
*
|
||||
* @param notice 通知公告
|
||||
* @return 自定义组合通知公告内容
|
||||
*/
|
||||
private String getNoticeContent(Notice notice) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.set("id", notice.getId());
|
||||
jsonObject.set("title", notice.getTitle());
|
||||
jsonObject.set("messageType", notice.getNoticeType());
|
||||
jsonObject.set("releaseTime", notice.getReleaseTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
jsonObject.set("type", "release");
|
||||
return jsonObject.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回通知公告
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user