From 262103e03409d6086565277f20b2a1d2ba96c4f3 Mon Sep 17 00:00:00 2001
From: ivmiku <124345843+ivmiku@users.noreply.github.com>
Date: Fri, 13 Sep 2024 22:13:21 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E7=9B=B8=E5=85=B3?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ivmiku/tutorial/response/AtNotifier.java | 14 +++
community-8073/pom.xml | 8 ++
.../controller/CommentController.java | 28 +++++-
.../tutorial/controller/WebSocketServer.java | 73 ++++++++++++++
.../com/ivmiku/tutorial/entity/Subscribe.java | 13 +++
.../java/com/ivmiku/tutorial/entity/User.java | 6 +-
.../com/ivmiku/tutorial/entity/UserDTO.java | 12 +++
.../tutorial/mapper/SubscribeMapper.java | 8 ++
.../ivmiku/tutorial/mapper/UserMapper.java | 7 ++
.../service/impl/CommentServiceImpl.java | 14 +++
.../tutorial/service/impl/SearchService.java | 58 ++++++++++++
.../com/ivmiku/tutorial/util/MyRedisUtil.java | 94 +++++++++++++++++++
.../main/resources/application-dep.properties | 5 +-
.../main/resources/application-dev.properties | 4 +-
.../tutorial/config/RabbitMqConfig.java | 15 +++
.../tutorial/controller/WebSocketServer.java | 31 +++++-
.../tutorial/service/MessageService.java | 9 ++
.../com/ivmiku/tutorial/utils/RedisUtil.java | 21 +++++
18 files changed, 410 insertions(+), 10 deletions(-)
create mode 100644 commons/src/main/java/com/ivmiku/tutorial/response/AtNotifier.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/entity/UserDTO.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/service/impl/SearchService.java
create mode 100644 community-8073/src/main/java/com/ivmiku/tutorial/util/MyRedisUtil.java
diff --git a/commons/src/main/java/com/ivmiku/tutorial/response/AtNotifier.java b/commons/src/main/java/com/ivmiku/tutorial/response/AtNotifier.java
new file mode 100644
index 0000000..360627e
--- /dev/null
+++ b/commons/src/main/java/com/ivmiku/tutorial/response/AtNotifier.java
@@ -0,0 +1,14 @@
+package com.ivmiku.tutorial.response;
+
+import lombok.Data;
+
+/**
+ * 提醒用户实体
+ * @author Aurora
+ */
+@Data
+public class AtNotifier {
+ private String fromId;
+ private String toId;
+ private String postId;
+}
diff --git a/community-8073/pom.xml b/community-8073/pom.xml
index 6f9a9f6..74ce4eb 100644
--- a/community-8073/pom.xml
+++ b/community-8073/pom.xml
@@ -190,6 +190,14 @@
commons
1.0-SNAPSHOT
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/controller/CommentController.java b/community-8073/src/main/java/com/ivmiku/tutorial/controller/CommentController.java
index af8dc9a..992e47c 100644
--- a/community-8073/src/main/java/com/ivmiku/tutorial/controller/CommentController.java
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/controller/CommentController.java
@@ -2,17 +2,21 @@ package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.entity.Pages;
+import com.ivmiku.tutorial.response.AtNotifier;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommentService;
import com.ivmiku.tutorial.service.FileService;
+import com.ivmiku.tutorial.util.MyRedisUtil;
import io.swagger.v3.oas.annotations.Operation;
import org.apiguardian.api.API;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -36,6 +40,13 @@ public class CommentController {
@Resource
private FileService fileService;
+ @Resource
+ private RabbitTemplate rabbitTemplate;
+
+ @Resource
+ private MyRedisUtil redisUtil;
+
+
/**
* 创建评论接口。
*/
@@ -66,6 +77,14 @@ public class CommentController {
commentService.createComment(comment);
logger.info("评论创建成功,评论ID:{}", comment.getCommentId());
+ if (!mentionedUserId.isEmpty()) {
+ AtNotifier notifier = new AtNotifier();
+ notifier.setFromId(comment.getUserOpenid());
+ notifier.setToId(mentionedUserId);
+ notifier.setPostId(String.valueOf(comment.getCommentId()));
+ rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
+ redisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
+ }
return Result.ok(comment);
}
@@ -106,6 +125,14 @@ public class CommentController {
commentService.createComment(reply);
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
+ if (!mentionedUserId.isEmpty()) {
+ AtNotifier notifier = new AtNotifier();
+ notifier.setFromId(reply.getUserOpenid());
+ notifier.setToId(mentionedUserId);
+ notifier.setPostId(String.valueOf(reply.getCommentId()));
+ rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
+ redisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
+ }
return Result.ok(reply);
}
@@ -115,7 +142,6 @@ public class CommentController {
comment.setUserOpenid(StpUtil.getLoginIdAsString());
comment.setContent(content);
comment.setMentionedUserId(mentionedUserId);
-
if ("post".equals(type)) {
comment.setPostId(postId);
} else if ("tutorial".equals(type)) {
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java b/community-8073/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java
new file mode 100644
index 0000000..2e52100
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java
@@ -0,0 +1,73 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson.JSON;
+import com.ivmiku.tutorial.entity.UserDTO;
+import com.ivmiku.tutorial.response.Result;
+import com.ivmiku.tutorial.service.impl.SearchService;
+import jakarta.websocket.*;
+import jakarta.websocket.server.PathParam;
+import jakarta.websocket.server.ServerEndpoint;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Controller;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Controller
+@ServerEndpoint(value = "/search/{satoken}")
+public class WebSocketServer {
+ public static Map sessionMap = new ConcurrentHashMap<>();
+ private static ApplicationContext applicationContext;
+ private SearchService searchService;
+
+ @OnOpen
+ public void onOpen(Session session, EndpointConfig endpointConfig, @PathParam("satoken") String satoken) throws IOException {
+ String userId = (String) StpUtil.getLoginIdByToken(satoken);
+ if (userId == null) {
+ session.getBasicRemote().sendText("Invalid Token");
+ session.close();
+ }
+ sessionMap.put(userId, session);
+ this.searchService = WebSocketServer.applicationContext.getBean(SearchService.class);
+ }
+
+ @OnClose
+ public void onClose(CloseReason closeReason, Session session){
+ sessionMap.remove(session.getId());
+ }
+
+ @OnError
+ public void onError(Throwable throwable) throws IOException {
+ throwable.printStackTrace();
+ }
+
+ @OnMessage
+ public void onMessage(String message, Session session) throws IOException {
+ char first = message.charAt(0);
+ String userId = null;
+ for (Map.Entry entry : sessionMap.entrySet()) {
+ if (entry.getValue().equals(session)) {
+ userId = entry.getKey();
+ }
+ }
+ switch (first) {
+ case '@' -> {
+ String sub = message.substring(1);
+ List result = searchService.getUserList(sub, userId);
+ session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(result)));
+ }
+ case '#' -> {
+ String sub = message.substring(1);
+ List list = searchService.getTag(message);
+ session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(list)));
+ }
+ //预留给社区搜索
+ default -> {
+
+ }
+ }
+ }
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java b/community-8073/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java
new file mode 100644
index 0000000..054070f
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java
@@ -0,0 +1,13 @@
+package com.ivmiku.tutorial.entity;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @author Aurora
+ */
+@TableName("subscribe")
+@Data
+public class Subscribe {
+ private Long id;
+ private Long subId;
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/entity/User.java b/community-8073/src/main/java/com/ivmiku/tutorial/entity/User.java
index 7dd39f4..ab3b4e3 100644
--- a/community-8073/src/main/java/com/ivmiku/tutorial/entity/User.java
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/entity/User.java
@@ -4,11 +4,15 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
+@TableName("user")
@Data
-@TableName("User")
public class User {
@TableId
private String openid;
private String nickname;
private String avatarUrl;
+ private boolean isAdmin;
+ private String phoneNum;
+ private String birthday;
+ private String gender;
}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/entity/UserDTO.java b/community-8073/src/main/java/com/ivmiku/tutorial/entity/UserDTO.java
new file mode 100644
index 0000000..fb0b383
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/entity/UserDTO.java
@@ -0,0 +1,12 @@
+package com.ivmiku.tutorial.entity;
+
+import lombok.Data;
+
+@Data
+public class UserDTO {
+ private String nickname;
+ private String avatarUrl;
+ private String phoneNum;
+ private String birthday;
+ private String gender;
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java b/community-8073/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java
new file mode 100644
index 0000000..53d67c9
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.Subscribe;
+
+public interface SubscribeMapper extends BaseMapper {
+
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java b/community-8073/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
new file mode 100644
index 0000000..f220728
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/mapper/UserMapper.java
@@ -0,0 +1,7 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.User;
+
+public interface UserMapper extends BaseMapper {
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/CommentServiceImpl.java b/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/CommentServiceImpl.java
index 55d409a..ad8aac6 100644
--- a/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/CommentServiceImpl.java
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/CommentServiceImpl.java
@@ -1,6 +1,7 @@
package com.ivmiku.tutorial.service.impl;
import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -8,10 +9,13 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.mapper.CommentMapper;
+import com.ivmiku.tutorial.response.AtNotifier;
import com.ivmiku.tutorial.service.CommentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -30,6 +34,9 @@ public class CommentServiceImpl extends ServiceImpl impl
@Autowired
protected CommentMapper commentMapper;
+ @Resource
+ private RabbitTemplate rabbitTemplate;
+
/**
* 保存评论。
* 将评论数据保存到数据库。
@@ -186,6 +193,13 @@ public class CommentServiceImpl extends ServiceImpl impl
reply.setMentionedUserId(mentionedUserId);
}
createComment(reply);
+ if (mentionedUserId != null) {
+ AtNotifier notifier = new AtNotifier();
+ notifier.setFromId(reply.getUserOpenid());
+ notifier.setToId(mentionedUserId);
+ notifier.setPostId(String.valueOf(reply.getCommentId()));
+ rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
+ }
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/SearchService.java b/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/SearchService.java
new file mode 100644
index 0000000..0b28037
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/service/impl/SearchService.java
@@ -0,0 +1,58 @@
+package com.ivmiku.tutorial.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ivmiku.tutorial.entity.Subscribe;
+import com.ivmiku.tutorial.entity.Tag;
+import com.ivmiku.tutorial.entity.User;
+import com.ivmiku.tutorial.entity.UserDTO;
+import com.ivmiku.tutorial.mapper.PostTagMapper;
+import com.ivmiku.tutorial.mapper.SubscribeMapper;
+import com.ivmiku.tutorial.mapper.TagMapper;
+import com.ivmiku.tutorial.mapper.UserMapper;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class SearchService {
+ @Resource
+ private UserMapper userMapper;
+
+ @Resource
+ private TagMapper tagMapper;
+
+ @Resource
+ private SubscribeMapper subscribeMapper;
+
+ public List getUserList(String text, String userId) {
+ int len = text.length();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("user1_id", userId);
+ List list = subscribeMapper.selectList(queryWrapper);
+ List result = new ArrayList<>();
+ for (Subscribe subscribe : list) {
+ String user2Id = String.valueOf(subscribe.getSubId());
+ User user = userMapper.selectById(user2Id);
+ if (user.getNickname().substring(0, len).equals(text)) {
+ UserDTO userDTO = new UserDTO();
+ userDTO.setNickname(user.getNickname());
+ userDTO.setAvatarUrl(user.getAvatarUrl());
+ result.add(userDTO);
+ }
+ }
+ return result;
+ }
+
+ public List getTag(String text) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.likeRight("name", text);
+ List list = tagMapper.selectList(queryWrapper);
+ List result = new ArrayList<>();
+ for (Tag tag : list) {
+ result.add(tag.getName());
+ }
+ return result;
+ }
+}
diff --git a/community-8073/src/main/java/com/ivmiku/tutorial/util/MyRedisUtil.java b/community-8073/src/main/java/com/ivmiku/tutorial/util/MyRedisUtil.java
new file mode 100644
index 0000000..a39b99a
--- /dev/null
+++ b/community-8073/src/main/java/com/ivmiku/tutorial/util/MyRedisUtil.java
@@ -0,0 +1,94 @@
+package com.ivmiku.tutorial.util;
+
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.response.AtNotifier;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Aurora
+ */
+@Component
+public class MyRedisUtil {
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ public void listAdd(String key, Object value) {
+ redisTemplate.opsForList().leftPush(key, value);
+ }
+
+ public List listGet(String key, int s, int e) {
+ List