Compare commits
6 Commits
d4c2c87327
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17a52ed471 | ||
|
|
b987c11cd1 | ||
|
|
62a521388d | ||
|
|
bda83a1bfe | ||
|
|
1dc7681ac6 | ||
|
|
262103e034 |
@@ -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;
|
||||||
|
}
|
||||||
@@ -190,6 +190,14 @@
|
|||||||
<artifactId>commons</artifactId>
|
<artifactId>commons</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public class SaTokenConfig implements WebMvcConfigurer {
|
|||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
|
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
|
||||||
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
||||||
.addPathPatterns("/**");
|
.addPathPatterns("/**")
|
||||||
|
.excludePathPatterns("/swagger-ui/**");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.ivmiku.tutorial.config;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletContext;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
|
||||||
|
import org.springframework.web.util.WebAppRootListener;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketConfig implements ServletContextInitializer {
|
||||||
|
@Bean
|
||||||
|
public ServerEndpointExporter serverEndpointExporter (){
|
||||||
|
return new ServerEndpointExporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||||
|
servletContext.addListener(WebAppRootListener.class);
|
||||||
|
servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","102400000");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServletServerContainerFactoryBean createWebSocketContainer() {
|
||||||
|
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
|
||||||
|
// 在此处设置bufferSize
|
||||||
|
container.setMaxTextMessageBufferSize(50*1024*1024);
|
||||||
|
container.setMaxBinaryMessageBufferSize(50*1024*1024);
|
||||||
|
container.setMaxSessionIdleTimeout(15 * 60000L);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,22 +2,23 @@ package com.ivmiku.tutorial.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.ivmiku.tutorial.entity.Comment;
|
import com.ivmiku.tutorial.entity.Comment;
|
||||||
import com.ivmiku.tutorial.entity.Pages;
|
import com.ivmiku.tutorial.entity.Pages;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.response.Result;
|
import com.ivmiku.tutorial.response.Result;
|
||||||
import com.ivmiku.tutorial.service.CommentService;
|
import com.ivmiku.tutorial.service.CommentService;
|
||||||
import com.ivmiku.tutorial.service.FileService;
|
import com.ivmiku.tutorial.service.FileService;
|
||||||
|
import com.ivmiku.tutorial.util.MyRedisUtil;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import org.apiguardian.api.API;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评论控制器,用于处理评论相关的HTTP请求。
|
* 评论控制器,用于处理评论相关的HTTP请求。
|
||||||
@@ -36,6 +37,13 @@ public class CommentController {
|
|||||||
@Resource
|
@Resource
|
||||||
private FileService fileService;
|
private FileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MyRedisUtil myRedisUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建评论接口。
|
* 创建评论接口。
|
||||||
*/
|
*/
|
||||||
@@ -66,6 +74,14 @@ public class CommentController {
|
|||||||
|
|
||||||
commentService.createComment(comment);
|
commentService.createComment(comment);
|
||||||
logger.info("评论创建成功,评论ID:{}", comment.getCommentId());
|
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));
|
||||||
|
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
|
||||||
|
}
|
||||||
return Result.ok(comment);
|
return Result.ok(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +122,14 @@ public class CommentController {
|
|||||||
|
|
||||||
commentService.createComment(reply);
|
commentService.createComment(reply);
|
||||||
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
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));
|
||||||
|
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
|
||||||
|
}
|
||||||
return Result.ok(reply);
|
return Result.ok(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +139,6 @@ public class CommentController {
|
|||||||
comment.setUserOpenid(StpUtil.getLoginIdAsString());
|
comment.setUserOpenid(StpUtil.getLoginIdAsString());
|
||||||
comment.setContent(content);
|
comment.setContent(content);
|
||||||
comment.setMentionedUserId(mentionedUserId);
|
comment.setMentionedUserId(mentionedUserId);
|
||||||
|
|
||||||
if ("post".equals(type)) {
|
if ("post".equals(type)) {
|
||||||
comment.setPostId(postId);
|
comment.setPostId(postId);
|
||||||
} else if ("tutorial".equals(type)) {
|
} else if ("tutorial".equals(type)) {
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
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.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
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 implements ApplicationContextAware {
|
||||||
|
public static Map<String, Session> 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<String, Session> entry : sessionMap.entrySet()) {
|
||||||
|
if (entry.getValue().equals(session)) {
|
||||||
|
userId = entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (first) {
|
||||||
|
case '@' -> {
|
||||||
|
String sub = message.substring(1);
|
||||||
|
List<UserDTO> result = searchService.getUserList(sub, userId);
|
||||||
|
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(result)));
|
||||||
|
}
|
||||||
|
case '#' -> {
|
||||||
|
String sub = message.substring(1);
|
||||||
|
List<String> list = searchService.getTag(sub);
|
||||||
|
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(list)));
|
||||||
|
}
|
||||||
|
//预留给社区搜索
|
||||||
|
default -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
WebSocketServer.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -4,11 +4,15 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
@TableName("user")
|
||||||
@Data
|
@Data
|
||||||
@TableName("User")
|
|
||||||
public class User {
|
public class User {
|
||||||
@TableId
|
@TableId
|
||||||
private String openid;
|
private String openid;
|
||||||
private String nickname;
|
private String nickname;
|
||||||
private String avatarUrl;
|
private String avatarUrl;
|
||||||
|
private boolean isAdmin;
|
||||||
|
private String phoneNum;
|
||||||
|
private String birthday;
|
||||||
|
private String gender;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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<Subscribe> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<User> {
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ivmiku.tutorial.service.impl;
|
package com.ivmiku.tutorial.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@@ -8,10 +9,13 @@ import com.github.pagehelper.PageHelper;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.ivmiku.tutorial.entity.Comment;
|
import com.ivmiku.tutorial.entity.Comment;
|
||||||
import com.ivmiku.tutorial.mapper.CommentMapper;
|
import com.ivmiku.tutorial.mapper.CommentMapper;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.service.CommentService;
|
import com.ivmiku.tutorial.service.CommentService;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -30,6 +34,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected CommentMapper commentMapper;
|
protected CommentMapper commentMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存评论。
|
* 保存评论。
|
||||||
* 将评论数据保存到数据库。
|
* 将评论数据保存到数据库。
|
||||||
@@ -186,6 +193,13 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
|||||||
reply.setMentionedUserId(mentionedUserId);
|
reply.setMentionedUserId(mentionedUserId);
|
||||||
}
|
}
|
||||||
createComment(reply);
|
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());
|
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<UserDTO> getUserList(String text, String userId) {
|
||||||
|
int len = text.length();
|
||||||
|
QueryWrapper<Subscribe> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("user1_id", userId);
|
||||||
|
List<Subscribe> list = subscribeMapper.selectList(queryWrapper);
|
||||||
|
List<UserDTO> 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<String> getTag(String text) {
|
||||||
|
QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.likeRight("name", text);
|
||||||
|
List<Tag> list = tagMapper.selectList(queryWrapper);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
for (Tag tag : list) {
|
||||||
|
result.add(tag.getName());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
public void listAdd(String key, Object value) {
|
||||||
|
redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> listGet(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<AtNotifier> result = new ArrayList<>();
|
||||||
|
if (list != null) {
|
||||||
|
for (Object json : list) {
|
||||||
|
result.add(JSON.parseObject(JSON.toJSONString(json), AtNotifier.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listClear(String key) {
|
||||||
|
redisTemplate.opsForList().trim(key, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getListSize(String key) {
|
||||||
|
return redisTemplate.opsForList().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getKey() {
|
||||||
|
return redisTemplate.keys("history:*");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object rightPop(String key) {
|
||||||
|
return redisTemplate.opsForList().rightPop(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setExpireTime(String key) {
|
||||||
|
if (redisTemplate.opsForValue().getOperations().getExpire(key) > 0) {
|
||||||
|
redisTemplate.expire(key, 3, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshExpire(String key) {
|
||||||
|
redisTemplate.persist(key);
|
||||||
|
redisTemplate.expire(key, 3, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ifExist(String key) {
|
||||||
|
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStringList(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
assert list != null;
|
||||||
|
for (Object object : list) {
|
||||||
|
result.add((String) object);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertKey(String openid, String sessionKey) {
|
||||||
|
redisTemplate.opsForValue().set("sessionkey:" + openid, sessionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey(String userId) {
|
||||||
|
return (String) redisTemplate.opsForValue().get("sessionkey:" + userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteFromList(AtNotifier message) {
|
||||||
|
String id = message.getToId();
|
||||||
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,15 +13,12 @@ server.port=8073
|
|||||||
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=123456
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|
||||||
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
||||||
spring.cloud.nacos.discovery.enabled=true
|
spring.cloud.nacos.discovery.enabled=true
|
||||||
|
|
||||||
management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
|
|
||||||
management.tracing.sampling.probability=1.0
|
|
||||||
|
|
||||||
dubbo.application.qos-enable=false
|
dubbo.application.qos-enable=false
|
||||||
|
|
||||||
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
|
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
@@ -36,5 +33,5 @@ spring.data.redis.lettuce.pool.max-active=32
|
|||||||
spring.data.redis.lettuce.pool.max-idle=16
|
spring.data.redis.lettuce.pool.max-idle=16
|
||||||
spring.data.redis.lettuce.pool.min-idle=8
|
spring.data.redis.lettuce.pool.min-idle=8
|
||||||
|
|
||||||
|
spring.rabbitmq.host=rabbitmq
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ public class SaTokenConfigure {
|
|||||||
"/user/register",
|
"/user/register",
|
||||||
"/swagger-resources/**",
|
"/swagger-resources/**",
|
||||||
"/v3/**",
|
"/v3/**",
|
||||||
"/swagger-ui/**")
|
"/swagger-ui/**",
|
||||||
|
"/ws/**")
|
||||||
// 鉴权方法:每次访问进入
|
// 鉴权方法:每次访问进入
|
||||||
.setAuth(obj -> {
|
.setAuth(obj -> {
|
||||||
// 登录校验 -- 拦截所有路由,并排除指定路由
|
// 登录校验 -- 拦截所有路由,并排除指定路由
|
||||||
|
|||||||
@@ -26,3 +26,7 @@ spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
|
|||||||
spring.cloud.gateway.routes[3].id=websocket
|
spring.cloud.gateway.routes[3].id=websocket
|
||||||
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
||||||
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[4].id=search
|
||||||
|
spring.cloud.gateway.routes[4].uri=lb:ws://community
|
||||||
|
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**
|
||||||
@@ -25,3 +25,7 @@ spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
|
|||||||
spring.cloud.gateway.routes[3].id=websocket
|
spring.cloud.gateway.routes[3].id=websocket
|
||||||
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
||||||
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[4].id=search
|
||||||
|
spring.cloud.gateway.routes[4].uri=lb:ws://community
|
||||||
|
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**
|
||||||
@@ -10,5 +10,5 @@ dubbo.application.qos-enable=false
|
|||||||
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=12345abcde
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
|
spring.datasource.url=jdbc:mysql://154.40.44.199:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|||||||
@@ -14,14 +14,29 @@ public class RabbitMqConfig {
|
|||||||
return new Queue("queue1",true);
|
return new Queue("queue1",true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Queue queue2() {
|
||||||
|
return new Queue("queue2",true);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public FanoutExchange exchange1() {
|
public FanoutExchange exchange1() {
|
||||||
return new FanoutExchange("exchange1",true, false);
|
return new FanoutExchange("exchange1",true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FanoutExchange exchange2() {
|
||||||
|
return new FanoutExchange("exchange2",true, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Binding binding1() {
|
public Binding binding1() {
|
||||||
return BindingBuilder.bind(queue1()).to(exchange1());
|
return BindingBuilder.bind(queue1()).to(exchange1());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Binding binding2() {
|
||||||
|
return BindingBuilder.bind(queue2()).to(exchange2());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.ivmiku.tutorial.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.service.MessageService;
|
import com.ivmiku.tutorial.service.MessageService;
|
||||||
import com.ivmiku.tutorial.service.RelationService;
|
import com.ivmiku.tutorial.service.RelationService;
|
||||||
import com.ivmiku.tutorial.utils.DateUtil;
|
import com.ivmiku.tutorial.utils.DateUtil;
|
||||||
@@ -84,7 +86,15 @@ public class WebSocketServer implements ApplicationContextAware {
|
|||||||
sessionMap.put(userId, session);
|
sessionMap.put(userId, session);
|
||||||
List<Message> unreadList = messageService.getUnreadMsg(userId);
|
List<Message> unreadList = messageService.getUnreadMsg(userId);
|
||||||
for(Message msg : unreadList) {
|
for(Message msg : unreadList) {
|
||||||
session.getBasicRemote().sendText(JSON.toJSONString(msg));
|
JSONObject object = JSONObject.from(msg);
|
||||||
|
object.put("type", 1);
|
||||||
|
session.getBasicRemote().sendText(object.toJSONString());
|
||||||
|
}
|
||||||
|
List<AtNotifier> atList = messageService.getAtList(userId);
|
||||||
|
for (AtNotifier notifier : atList) {
|
||||||
|
JSONObject object = JSONObject.from(notifier);
|
||||||
|
object.put("type", 2);
|
||||||
|
session.getBasicRemote().sendText(object.toJSONString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +142,25 @@ public class WebSocketServer implements ApplicationContextAware {
|
|||||||
public void sendMsg(String message) throws IOException {
|
public void sendMsg(String message) throws IOException {
|
||||||
Message msg = JSON.parseObject(message, Message.class);
|
Message msg = JSON.parseObject(message, Message.class);
|
||||||
if (sessionMap.containsKey(msg.getToId())) {
|
if (sessionMap.containsKey(msg.getToId())) {
|
||||||
sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
|
JSONObject jsonObject = JSONObject.from(msg);
|
||||||
|
jsonObject.put("type", 1);
|
||||||
|
sessionMap.get(msg.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
|
||||||
messageService.deleteMessage(msg);
|
messageService.deleteMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RabbitHandler
|
||||||
|
@RabbitListener(bindings = @QueueBinding(
|
||||||
|
value = @Queue(),
|
||||||
|
exchange = @Exchange(value = "exchange2",type = ExchangeTypes.FANOUT)
|
||||||
|
))
|
||||||
|
public void sendAt(String message) throws IOException {
|
||||||
|
AtNotifier notifier = JSON.parseObject(message, AtNotifier.class);
|
||||||
|
if (sessionMap.containsKey(notifier.getToId())) {
|
||||||
|
JSONObject jsonObject = JSONObject.from(notifier);
|
||||||
|
jsonObject.put("type", 2);
|
||||||
|
sessionMap.get(notifier.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
|
||||||
|
messageService.deleteNotifier(notifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.ivmiku.tutorial.entity.ChatId;
|
|||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
import com.ivmiku.tutorial.mapper.ChatIdMapper;
|
import com.ivmiku.tutorial.mapper.ChatIdMapper;
|
||||||
import com.ivmiku.tutorial.mapper.MessageMapper;
|
import com.ivmiku.tutorial.mapper.MessageMapper;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.utils.RedisUtil;
|
import com.ivmiku.tutorial.utils.RedisUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
@@ -245,4 +246,12 @@ public class MessageService {
|
|||||||
public void deleteMessage(Message message) {
|
public void deleteMessage(Message message) {
|
||||||
redisUtil.deleteFromList(message);
|
redisUtil.deleteFromList(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteNotifier(AtNotifier notifier) {
|
||||||
|
redisUtil.deleteFromList(notifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> getAtList(String userId) {
|
||||||
|
return redisUtil.listGetN("at:" + userId, 0, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ivmiku.tutorial.utils;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -127,4 +128,24 @@ public class RedisUtil {
|
|||||||
String id = message.getToId();
|
String id = message.getToId();
|
||||||
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void listAddN(String key, Object value) {
|
||||||
|
redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> listGetN(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<AtNotifier> result = new ArrayList<>();
|
||||||
|
if (list != null) {
|
||||||
|
for (Object json : list) {
|
||||||
|
result.add(JSON.parseObject(JSON.toJSONString(json), AtNotifier.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteFromList(AtNotifier message) {
|
||||||
|
String id = message.getToId();
|
||||||
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user