diff --git a/navigate-8432/pom.xml b/navigate-8432/pom.xml
index bb3eb35..e3aa5f4 100644
--- a/navigate-8432/pom.xml
+++ b/navigate-8432/pom.xml
@@ -18,11 +18,6 @@
-
- com.baomidou
- mybatis-plus-boot-starter
- 3.5.7
-
org.springframework.boot
spring-boot-starter-web
@@ -31,10 +26,11 @@
org.springframework.boot
spring-boot-starter-actuator
-
-
-
-
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ 3.5.7
+
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
@@ -108,5 +104,10 @@
tencentcloud-sdk-java-tts
3.1.1076
+
+ com.tencentcloudapi
+ tencentcloud-sdk-java-asr
+ 3.1.1083
+
\ No newline at end of file
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/AssistantController.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/AssistantController.java
index afef15d..8cd9a8d 100644
--- a/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/AssistantController.java
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/AssistantController.java
@@ -17,18 +17,12 @@ public class AssistantController {
private AssistantService assistantService;
@GetMapping("/response")
- public Object getResponse(@RequestParam String input) {
- Map map = assistantService.getResponse(input);
+ public Object getResponse(@RequestParam String input, @RequestParam int size, @RequestParam String language) {
+ String userInput = assistantService.speechRecognition(input, size, language);
+ Map map = assistantService.getResponse(userInput, language);
if (map == null) {
return Result.error("请求出错");
}
return Result.ok(map);
}
-
- @GetMapping("/tts")
- public Object textToSpeech(@RequestParam String input) {
- Map map = new HashMap<>();
- map.put("content", assistantService.textToSpeech(input));
- return Result.ok(map);
- }
}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/Guidance.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/Guidance.java
new file mode 100644
index 0000000..9b16ab0
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/Guidance.java
@@ -0,0 +1,14 @@
+package com.ivmiku.tutorial.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@TableName("guidance")
+@Data
+public class Guidance {
+ @TableId
+ private String id;
+ private String tag;
+ private String content;
+}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/mapper/GuidanceMapper.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/mapper/GuidanceMapper.java
new file mode 100644
index 0000000..4bdea0f
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/mapper/GuidanceMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.Guidance;
+
+public interface GuidanceMapper extends BaseMapper {
+
+}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/service/AssistantService.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/service/AssistantService.java
index f060c58..da0e312 100644
--- a/navigate-8432/src/main/java/com/ivmiku/tutorial/service/AssistantService.java
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/service/AssistantService.java
@@ -2,11 +2,15 @@ package com.ivmiku.tutorial.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
-import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ivmiku.tutorial.entity.Guidance;
+import com.ivmiku.tutorial.mapper.GuidanceMapper;
import com.ivmiku.tutorial.utils.SnowflakeUtil;
-import com.tencentcloudapi.common.AbstractModel;
+import com.tencentcloudapi.asr.v20190614.AsrClient;
+import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionRequest;
+import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionResponse;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
@@ -14,21 +18,32 @@ import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tts.v20190823.TtsClient;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceRequest;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceResponse;
+import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
@Service
public class AssistantService {
+ @Resource
+ private GuidanceMapper guidanceMapper;
+
private final String auth = "bad1f6cad39a4c26aa9fe9e4324e096f:ZDczMDIwOTg3NjlhODdmYWVjYTY0YjM1";
private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50";
private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil";
- public Map getResponse(String userInput) {
+ public String getAiResponse(String userInput, String language) {
Map message1 = new HashMap<>();
message1.put("role", "system");
- message1.put("content", "模仿语音助手,对用户的问题给出简短的回答");
+ String prompt = "模仿语音助手,对用户的问题给出简短的回答";
+ if ("Chinese".equals(language)) {
+ prompt += ",用中文回答";
+ } else if ("English".equals(language)) {
+ prompt += ",用英文回答";
+ }
+ message1.put("content", prompt);
Map message2 = new HashMap<>();
message2.put("role", "user");
message2.put("content", userInput);
@@ -50,10 +65,7 @@ public class AssistantService {
}
JSONArray choices = result.getJSONArray("choices");
JSONObject message = choices.getJSONObject(0);
- JSONObject content = message.getJSONObject("message");
- Map map = new HashMap<>();
- map.put("content", content.get("content"));
- return map;
+ return message.getString("message");
}
public String textToSpeech(String content) {
@@ -74,4 +86,80 @@ public class AssistantService {
throw new RuntimeException(e);
}
}
+
+ public String speechRecognition(String content, Integer length, String language) {
+ try{
+ Credential cred = new Credential(secretId, secretKey);
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setEndpoint("asr.tencentcloudapi.com");
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+ AsrClient client = new AsrClient(cred, "", clientProfile);
+ SentenceRecognitionRequest req = new SentenceRecognitionRequest();
+ if ("Chinese".equals(language)) {
+ req.setEngSerViceType("16k_zh");
+ } else if ("English".equals(language)) {
+ req.setEngSerViceType("16k_en");
+ }
+ req.setSourceType(1L);
+ req.setVoiceFormat("wav");
+ req.setData(content);
+ req.setDataLen(Long.valueOf(length));
+ SentenceRecognitionResponse resp = client.SentenceRecognition(req);
+ return resp.getResult();
+ } catch (TencentCloudSDKException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String searchGuidance(String tag) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.like("tag", tag);
+ List list = guidanceMapper.selectList(queryWrapper);
+ if (list.isEmpty()) {
+ return null;
+ }
+ return list.getFirst().getContent();
+ }
+
+ public String extractTag(String query) {
+ Map message1 = new HashMap<>();
+ message1.put("role", "system");
+ message1.put("content", "根据给出的句子的意思,从以下标签中返回最匹配的一个:安全带、安检、飞机");
+ Map message2 = new HashMap<>();
+ message2.put("role", "user");
+ message2.put("content", query);
+ JSONArray array = new JSONArray();
+ array.add(message1);
+ array.add(message2);
+ JSONObject params = new JSONObject();
+ params.put("model", "general");
+ params.put("messages", array);
+ HttpResponse response = HttpRequest.post("https://spark-api-open.xf-yun.com/v1/chat/completions")
+ .header("Content-Type", "application/json")
+ .header("Authorization", "Bearer " + auth)
+ .body(params.toJSONString())
+ .execute();
+ JSONObject result = JSONObject.parseObject(response.body());
+ response.close();
+ if (result.getInteger("code") != 0) {
+ return null;
+ }
+ JSONArray choices = result.getJSONArray("choices");
+ JSONObject message = choices.getJSONObject(0);
+ return String.valueOf(message.getJSONObject("message"));
+ }
+
+ public Map getResponse(String query, String language) {
+ Map result = new HashMap<>();
+ String tag = extractTag(query);
+ String content;
+ content = searchGuidance(tag);
+ if (content == null) {
+ content = getAiResponse(query, language);
+ }
+ Map map = new HashMap<>();
+ map.put("content", textToSpeech(content));
+ return map;
+ }
}
diff --git a/user-8072/pom.xml b/user-8072/pom.xml
index 7b5121b..5ca0ed8 100644
--- a/user-8072/pom.xml
+++ b/user-8072/pom.xml
@@ -117,6 +117,14 @@
commons
1.0-SNAPSHOT
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/MybatisPlusConfig.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..71ed480
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/MybatisPlusConfig.java
@@ -0,0 +1,24 @@
+package com.ivmiku.tutorial.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.ivmiku.tutorial.mapper")
+public class MybatisPlusConfig {
+
+ /**
+ * 添加分页插件
+ */
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
+ return interceptor;
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/RabbitMqConfig.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/RabbitMqConfig.java
new file mode 100644
index 0000000..d9ee381
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/RabbitMqConfig.java
@@ -0,0 +1,27 @@
+package com.ivmiku.tutorial.config;
+
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.BindingBuilder;
+import org.springframework.amqp.core.FanoutExchange;
+import org.springframework.amqp.core.Queue;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RabbitMqConfig {
+ @Bean
+ public Queue queue1() {
+ return new Queue("queue1",true);
+ }
+
+ @Bean
+ public FanoutExchange exchange1() {
+ return new FanoutExchange("exchange1",true, false);
+ }
+
+ @Bean
+ public Binding binding1() {
+ return BindingBuilder.bind(queue1()).to(exchange1());
+ }
+}
+
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java
new file mode 100644
index 0000000..85ca18f
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/SaTokenConfigure.java
@@ -0,0 +1,15 @@
+package com.ivmiku.tutorial.config;
+
+import cn.dev33.satoken.interceptor.SaInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class SaTokenConfigure implements WebMvcConfigurer {
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ // 注册 Sa-Token 拦截器,打开注解式鉴权功能
+ registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/config/WebSocketConfig.java b/user-8072/src/main/java/com/ivmiku/tutorial/config/WebSocketConfig.java
new file mode 100644
index 0000000..b36ddc7
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/config/WebSocketConfig.java
@@ -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;
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/controller/MessageController.java b/user-8072/src/main/java/com/ivmiku/tutorial/controller/MessageController.java
new file mode 100644
index 0000000..326b872
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/controller/MessageController.java
@@ -0,0 +1,39 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.dev33.satoken.annotation.SaCheckLogin;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.entity.HistoryQuery;
+import com.ivmiku.tutorial.response.Result;
+import com.ivmiku.tutorial.service.MessageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+
+@SaCheckLogin
+@RestController
+@RequestMapping("/api/message")
+public class MessageController {
+ @Autowired
+ private MessageService messageService;
+
+ @PostMapping("/history")
+ public Object getChatHistory(@RequestBody HistoryQuery input) throws ParseException {
+ Result result = Result.ok();
+ if (input.getStartDate() != null && input.getEndDate() != null) {
+ result.setData(messageService.getChatHistoryByDate(input.getUser1Id(), input.getUser2Id(), input.getStartDate(), input.getEndDate(), input.getPage(), input.getSize()));
+ } else {
+ if (input.getPage() <= 0 || input.getSize() <=0) {
+ return Result.error("请输入合法分页参数");
+ } else {
+ result.setData(messageService.getChatHistory(input.getUser1Id(), input.getUser2Id(), input.getPage(), input.getSize()));
+ }
+ }
+ return JSON.toJSON(result);
+ }
+
+ @GetMapping("/list")
+ public Object getChatList(@RequestParam String user_id, @RequestParam int page, @RequestParam int size) {
+ return Result.ok(messageService.getChatList(user_id, page, size));
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/controller/RelationController.java b/user-8072/src/main/java/com/ivmiku/tutorial/controller/RelationController.java
new file mode 100644
index 0000000..d7dcc88
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/controller/RelationController.java
@@ -0,0 +1,42 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.dev33.satoken.annotation.SaCheckLogin;
+import cn.dev33.satoken.stp.StpUtil;
+import com.ivmiku.tutorial.entity.IgnoreUser;
+import com.ivmiku.tutorial.response.Result;
+import com.ivmiku.tutorial.service.RelationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@SaCheckLogin
+@RestController
+@RequestMapping("/api/relation")
+public class RelationController {
+ @Autowired
+ private RelationService relationService;
+
+ @PostMapping("/ignore")
+ public Object ignoreUser(@RequestBody IgnoreUser input) {
+ relationService.IgnoreUser(input.getUserId(), input.getToIgnore());
+ return Result.ok();
+ }
+
+ @GetMapping("subscribe")
+ public Object subscribe(@RequestParam String subId) {
+ String userId = (String) StpUtil.getLoginId();
+ relationService.subscribe(userId, subId);
+ return Result.ok();
+ }
+
+ @GetMapping("fan")
+ public Object getFanList(@RequestParam int page, @RequestParam int size) {
+ String userId = (String) StpUtil.getLoginId();
+ return Result.ok(relationService.getFanList(userId, page, size));
+ }
+
+ @GetMapping("follow")
+ public Object getFollowList(@RequestParam int page, @RequestParam int size) {
+ String userId = (String) StpUtil.getLoginId();
+ return Result.ok(relationService.getSubList(userId, page, size));
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java b/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
index f9aedfd..712db1f 100644
--- a/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/controller/UserController.java
@@ -2,6 +2,7 @@ package com.ivmiku.tutorial.controller;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSONObject;
@@ -12,7 +13,10 @@ import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.utils.RedisUtil;
import jakarta.annotation.Resource;
import me.chanjar.weixin.common.error.WxErrorException;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@@ -29,11 +33,16 @@ public class UserController {
private RedisUtil redisUtil;
@GetMapping("/login")
- public Object login(@RequestParam(name = "code") String code, @RequestParam(name = "rawdata") String rawData, @RequestParam(name = "signature") String signature
-) {
+ public Object login(@RequestParam(name = "code") String code,
+ @RequestParam(name = "rawdata") String rawData,
+ @RequestParam(name = "signature") String signature,
+ @RequestParam(name = "encryptedData") String encryptedData,
+ @RequestParam(name = "iv") String iv) {
WxMaJscode2SessionResult session;
+ WxMaUserInfo userInfo;
try {
session = wxMaService.getUserService().getSessionInfo(code);
+ userInfo = wxMaService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
} catch (WxErrorException e) {
return JSON.toJSON(Result.error(e.getMessage()));
}
@@ -49,6 +58,8 @@ public class UserController {
user.setOpenid(session.getOpenid());
user.setNickname(raw.getString("nickname"));
user.setAvatarUrl(raw.getString("avatarUrl"));
+ user.setGender(raw.getString("gender"));
+ user.setAdmin(false);
userMapper.insert(user);
}
map.put("token", StpUtil.getTokenValue());
@@ -56,4 +67,14 @@ public class UserController {
WxMaConfigHolder.remove();
return JSON.toJSON(Result.ok(map));
}
+
+ @GetMapping("/validate")
+ public Object validate() {
+ try {
+ StpUtil.checkLogin();
+ } catch (Exception e) {
+ return Result.error(e.getMessage());
+ }
+ return Result.ok();
+ }
}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java b/user-8072/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java
new file mode 100644
index 0000000..3f27ac6
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/controller/WebSocketServer.java
@@ -0,0 +1,139 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.entity.Message;
+import com.ivmiku.tutorial.service.MessageService;
+import com.ivmiku.tutorial.service.RelationService;
+import com.ivmiku.tutorial.utils.DateUtil;
+import com.ivmiku.tutorial.utils.MessageUtil;
+import jakarta.websocket.*;
+import jakarta.websocket.server.PathParam;
+import jakarta.websocket.server.ServerEndpoint;
+import org.springframework.amqp.core.ExchangeTypes;
+import org.springframework.amqp.rabbit.annotation.*;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Controller;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static jakarta.websocket.CloseReason.CloseCodes.CLOSED_ABNORMALLY;
+
+@Controller
+@ServerEndpoint(value = "/chat/{satoken}")
+public class WebSocketServer implements ApplicationContextAware {
+ public static Map sessionMap = new ConcurrentHashMap<>();
+
+ public static Map controlMap = new HashMap<>();
+
+ private static ApplicationContext applicationContext;
+
+ @Autowired
+ private MessageService messageService;
+
+ private RabbitTemplate rabbitTemplate;
+
+ private RelationService relationService;
+
+ @OnMessage
+ public void onMessage(String message, Session session) throws IOException {
+ Message msg = JSON.parseObject(message, Message.class);
+ msg.setDate(DateUtil.getCurrentTime());
+ if (MessageUtil.checkMessage(msg.getMessage())) {
+ session.getBasicRemote().sendText("发送的信息含有敏感词,请进行调整");
+ if (!controlMap.containsKey(msg.getFromId())){
+ controlMap.put(msg.getFromId(), 0);
+ }
+ if (controlMap.get(msg.getFromId()) == 4){
+ session.getBasicRemote().sendText("由于多次违反社区规则,您已被封禁1小时");
+ session.close(new CloseReason(CLOSED_ABNORMALLY, "账号被封禁"));
+ StpUtil.kickout(msg.getFromId());
+ StpUtil.disable(msg.getFromId(), 3600);
+ controlMap.put(msg.getFromId(), 0);
+ }
+ controlMap.put(msg.getFromId(), controlMap.get(msg.getFromId())+1);
+ } else
+ if (relationService.ifIgnored(msg.getToId(), msg.getFromId())) {
+ session.getBasicRemote().sendText("您已被对方屏蔽");
+ } else {
+ messageService.insertMessage(msg);
+ rabbitTemplate.convertAndSend("exchange1", "", JSON.toJSONString(msg));
+ }
+ }
+
+
+ @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();
+ }
+ this.messageService = WebSocketServer.applicationContext.getBean(MessageService.class);
+ this.rabbitTemplate = WebSocketServer.applicationContext.getBean(RabbitTemplate.class);
+ this.relationService = WebSocketServer.applicationContext.getBean(RelationService.class);
+ sessionMap.put(userId, session);
+ List unreadList = messageService.getUnreadMsg(userId);
+ for(Message msg : unreadList) {
+ session.getBasicRemote().sendText(JSON.toJSONString(msg));
+ }
+ }
+
+ @OnClose
+ public void onClose(CloseReason closeReason, Session session){
+ sessionMap.remove(session.getId());
+ }
+
+ @OnError
+ public void onError(Throwable throwable) throws IOException {
+ throwable.printStackTrace();
+ }
+
+ public void sendToUser(Message msg) throws IOException, ParseException {
+ if (sessionMap.containsKey(msg.getToId())){
+ sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
+ }
+ else {
+ messageService.insertUnreadMsg(msg.getToId(), msg);
+ }
+ msg.setChatId(messageService.getChatId(msg.getFromId(), msg.getToId()));
+ messageService.insertToMysql(msg);
+ messageService.insertToRedis(msg);
+ }
+
+ public void sendToPublic(Message msg) throws IOException, ParseException {
+ for (Session session : sessionMap.values()) {
+ session.getBasicRemote().sendText(JSON.toJSONString(msg));
+ }
+ msg.setChatId(messageService.getChatId(msg.getFromId(), msg.getToId()));
+ messageService.insertToMysql(msg);
+ messageService.insertToRedis(msg);
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ WebSocketServer.applicationContext = applicationContext;
+ }
+
+ @RabbitHandler
+ @RabbitListener(bindings = @QueueBinding(
+ value = @Queue(),
+ exchange = @Exchange(value = "exchange1",type = ExchangeTypes.FANOUT)
+ ))
+ public void sendMsg(String message) throws IOException {
+ Message msg = JSON.parseObject(message, Message.class);
+ if (sessionMap.containsKey(msg.getToId())) {
+ sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
+ messageService.deleteMessage(msg);
+ }
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/ChatId.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/ChatId.java
new file mode 100644
index 0000000..7da0f60
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/ChatId.java
@@ -0,0 +1,18 @@
+package com.ivmiku.tutorial.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @author Aurora
+ */
+@Data
+@TableName("chatid")
+public class ChatId {
+ @TableId(type = IdType.ASSIGN_ID)
+ private String id;
+ private String user1Id;
+ private String user2Id;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/Friend.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/Friend.java
new file mode 100644
index 0000000..11cb2e4
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/Friend.java
@@ -0,0 +1,18 @@
+package com.ivmiku.tutorial.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Aurora
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("friend")
+public class Friend {
+ private String user1Id;
+ private String user2Id;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/FriendQuery.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/FriendQuery.java
new file mode 100644
index 0000000..b31d876
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/FriendQuery.java
@@ -0,0 +1,12 @@
+package com.ivmiku.tutorial.entity;
+
+import lombok.Data;
+
+/**
+ * @author Aurora
+ */
+@Data
+public class FriendQuery {
+ private String user1Id;
+ private String user2Id;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/HistoryQuery.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/HistoryQuery.java
new file mode 100644
index 0000000..8b6149e
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/HistoryQuery.java
@@ -0,0 +1,16 @@
+package com.ivmiku.tutorial.entity;
+
+import lombok.Data;
+
+/**
+ * @author Aurora
+ */
+@Data
+public class HistoryQuery {
+ private String user1Id;
+ private String user2Id;
+ private int page;
+ private int size;
+ private String startDate;
+ private String endDate;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/IgnoreUser.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/IgnoreUser.java
new file mode 100644
index 0000000..d3c592f
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/IgnoreUser.java
@@ -0,0 +1,21 @@
+package com.ivmiku.tutorial.entity;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author Aurora
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@TableName("blacklist")
+public class IgnoreUser {
+ @JSONField(ordinal = 1)
+ private String userId;
+ @JSONField(ordinal = 2)
+ private String toIgnore;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/Message.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/Message.java
new file mode 100644
index 0000000..e96f45a
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/Message.java
@@ -0,0 +1,25 @@
+package com.ivmiku.tutorial.entity;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author Aurora
+ */
+@Data
+@TableName("message")
+public class Message implements Serializable {
+ @JSONField(ordinal = 1)
+ private String chatId;
+ @JSONField(ordinal = 2)
+ private String fromId;
+ @JSONField(ordinal = 3)
+ private String toId;
+ @JSONField(ordinal = 4)
+ private String message;
+ @JSONField(ordinal = 5)
+ private String date;
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/SubUser.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/SubUser.java
new file mode 100644
index 0000000..60bccb5
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/SubUser.java
@@ -0,0 +1,18 @@
+package com.ivmiku.tutorial.entity;
+
+import lombok.Data;
+
+@Data
+public class SubUser {
+ private String id;
+ private String username;
+ private String avatarUrl;
+
+ public static SubUser setUser(User user) {
+ SubUser subUser = new SubUser();
+ subUser.setId(user.getOpenid());
+ subUser.setUsername(user.getNickname());
+ subUser.setAvatarUrl(user.getAvatarUrl());
+ return subUser;
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/Subscribe.java
new file mode 100644
index 0000000..054070f
--- /dev/null
+++ b/user-8072/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/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java b/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
index 35dbcc2..ab3b4e3 100644
--- a/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/entity/User.java
@@ -11,4 +11,8 @@ public class User {
private String openid;
private String nickname;
private String avatarUrl;
+ private boolean isAdmin;
+ private String phoneNum;
+ private String birthday;
+ private String gender;
}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/BlackListMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/BlackListMapper.java
new file mode 100644
index 0000000..7d99648
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/BlackListMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.IgnoreUser;
+
+public interface BlackListMapper extends BaseMapper {
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/ChatIdMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/ChatIdMapper.java
new file mode 100644
index 0000000..ec9ddaa
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/ChatIdMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.ChatId;
+
+public interface ChatIdMapper extends BaseMapper {
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/FriendMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/FriendMapper.java
new file mode 100644
index 0000000..32ea471
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/FriendMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.Friend;
+
+public interface FriendMapper extends BaseMapper {
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/MessageMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/MessageMapper.java
new file mode 100644
index 0000000..b6d5ee1
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/MessageMapper.java
@@ -0,0 +1,8 @@
+package com.ivmiku.tutorial.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ivmiku.tutorial.entity.Message;
+
+public interface MessageMapper extends BaseMapper {
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java b/user-8072/src/main/java/com/ivmiku/tutorial/mapper/SubscribeMapper.java
new file mode 100644
index 0000000..53d67c9
--- /dev/null
+++ b/user-8072/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/user-8072/src/main/java/com/ivmiku/tutorial/service/MessageService.java b/user-8072/src/main/java/com/ivmiku/tutorial/service/MessageService.java
new file mode 100644
index 0000000..779c1d5
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/service/MessageService.java
@@ -0,0 +1,248 @@
+package com.ivmiku.tutorial.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ivmiku.tutorial.entity.ChatId;
+import com.ivmiku.tutorial.entity.Message;
+import com.ivmiku.tutorial.mapper.ChatIdMapper;
+import com.ivmiku.tutorial.mapper.MessageMapper;
+import com.ivmiku.tutorial.utils.RedisUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Aurora
+ */
+@Service
+public class MessageService {
+ @Autowired
+ private MessageMapper messageMapper;
+
+ @Autowired
+ private ChatIdMapper chatIdMapper;
+
+ @Autowired
+ private RedisUtil redisUtil;
+
+ /**
+ * 获取会话id
+ * @param user1Id 用户1id
+ * @param user2Id 用户2id
+ * @return 查询结果
+ */
+ public String getChatId(String user1Id, String user2Id) {
+ if (Objects.equals(user1Id, "public") || Objects.equals(user2Id, "public")) {
+ return "0";
+ }
+ String id1, id2;
+ if (user1Id.compareTo(user2Id) < 0) {
+ id1 = user1Id;
+ id2 = user2Id;
+ } else {
+ id1 = user2Id;
+ id2 = user1Id;
+ }
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("user1_id", id1);
+ queryWrapper.eq("user2_id", id2);
+ ChatId chatId = chatIdMapper.selectOne(queryWrapper);
+ if (chatId == null) {
+ chatId = new ChatId();
+ chatId.setUser1Id(id1);
+ chatId.setUser2Id(id2);
+ chatIdMapper.insert(chatId);
+ }
+ return chatIdMapper.selectOne(queryWrapper).getId();
+ }
+
+ /**
+ * 聊天记录写redis
+ * @param msg 要写入的信息
+ * @throws ParseException
+ */
+ @Async
+ public void insertToRedis(Message msg) throws ParseException {
+ if (!(msg.getMessage().length() >1000)) {
+ if (redisUtil.getZsetSize("history:" + msg.getChatId()) >= 50) {
+ redisUtil.zsetRightPop("history:" + msg.getChatId());
+ }
+ redisUtil.zsetAdd("history:" + msg.getChatId(), msg);
+ redisUtil.setExpireTime("history:" + msg.getChatId());
+ }
+ }
+
+ /**
+ * 聊天记录写入mysql
+ * @param msg 要写入的消息
+ */
+ @Async
+ public void insertToMysql(Message msg) {
+ if (!(msg.getMessage().length() >1000)) {
+ messageMapper.insert(msg);
+ }
+ }
+
+ /**
+ * 未读消息写入redis
+ * @param userId 用户id
+ * @param msg 未读消息
+ */
+ @Async
+ public void insertUnreadMsg(String userId, Message msg) {
+ redisUtil.listAdd("unread:" + userId, msg);
+ }
+
+ /**
+ * 获取未读消息列表
+ * @param userId 用户id
+ * @return 查询结果
+ */
+ public List getUnreadMsg(String userId) {
+ if (redisUtil.ifExist("unread:" + userId)) {
+ List result = redisUtil.listGet("unread:" + userId, 0, -1);
+ redisUtil.listClear("unread:" + userId);
+ return result;
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * 从数据库获取聊天记录
+ * @param chatId 会话id
+ * @param current 分页参数
+ * @param size 分页参数
+ * @return 返回的查询结果
+ */
+ public List getChatHistoryFromDB(String chatId, int current, int size) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ Page page = new Page<>(current, size);
+ queryWrapper.eq("chat_id", chatId);
+ queryWrapper.orderByDesc("date");
+ return messageMapper.selectPage(page, queryWrapper).getRecords();
+ }
+
+ /**
+ * 从数据库获取聊天记录,查询一定范围内
+ * @param chatId 会话id
+ * @param current 分页参数
+ * @param size 分页参数
+ * @param startDate 开始日期
+ * @param endDate 结束日期
+ * @return 返回的查询结果
+ */
+ public List getChatHistoryFromDBByDate(String chatId, int current, int size, String startDate, String endDate) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.between("date", startDate, endDate);
+ Page page = new Page<>(current, size);
+ queryWrapper.eq("chat_id", chatId);
+ queryWrapper.orderByDesc("date");
+ return messageMapper.selectPage(page, queryWrapper).getRecords();
+ }
+
+ /**
+ * redis获取聊天记录
+ * @param chatId 会话id
+ * @param s 开始
+ * @param e 结束
+ * @return 查询结果
+ */
+ public List getChatHistoryFromRedis(String chatId, int s, int e) {
+ return redisUtil.zsetGet("history:" + chatId, s, e);
+ }
+
+ /**
+ * 查询聊天记录
+ * @param user1Id 用户1id
+ * @param user2Id 用户2id
+ * @param page 分页参数
+ * @param size 分页参数
+ * @return 查询结果
+ * @throws ParseException
+ */
+ public List getChatHistory(String user1Id, String user2Id, int page, int size) throws ParseException {
+ int start = page * size - size;
+ int end = page * size - 1;
+ String chatId = getChatId(user1Id, user2Id);
+ loadCache(chatId);
+ List result = new ArrayList<>(redisUtil.zsetGet("history:" + chatId, start, end));
+ if ((end -start + 1) == result.size()) {
+ return result;
+ }
+ int redisSize = result.size();
+ List dbList = getChatHistoryFromDB(chatId, ((end - result.size()) / size) + 1, size);
+ result.addAll(dbList.subList(redisSize, dbList.size()));
+ redisUtil.refreshExpire("history:" + chatId);
+ return result;
+ }
+
+ /**
+ * 在一定时间范围内查询聊天记录
+ * @param user1Id 用户1id
+ * @param user2Id 用户2id
+ * @param startDate 开始日期
+ * @param endDate 结束日期
+ * @param page 分页参数
+ * @param size 分页参数
+ * @return 查询结果
+ * @throws ParseException
+ */
+ public List getChatHistoryByDate(String user1Id, String user2Id, String startDate, String endDate, int page, int size) throws ParseException {
+ int start = page * size - size;
+ int end = page * size - 1;
+ String chatId = getChatId(user1Id, user2Id);
+ loadCache(chatId);
+ List result = new ArrayList<>(redisUtil.zsetGetByDate("history:" + chatId, startDate, endDate, start, size));
+ redisUtil.refreshExpire("history:" + chatId);
+ if (result.size() == (end - start + 1)) {
+ return result;
+ }
+ int redisSize = result.size();
+ List dbList = getChatHistoryFromDBByDate(chatId, ((end - result.size()) / size) + 1, size, startDate, endDate).subList(result.size(), size);
+ result.addAll(dbList.subList(redisSize, dbList.size()));
+ return result;
+ }
+
+ /**
+ * 获取会话列表
+ * @param userId 用户id
+ * @param current 分页参数
+ * @param size 分页参数
+ * @return 查询结果
+ */
+ public List getChatList(String userId, int current, int size) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("user1_id", userId).or().eq("user2_id", userId);
+ queryWrapper.orderByDesc("id");
+ Page page = new Page<>(current, size);
+ return chatIdMapper.selectPage(page, queryWrapper).getRecords();
+ }
+
+ /**
+ * 加载聊天记录到redis
+ * @param chatId 会话id
+ * @throws ParseException
+ */
+ public void loadCache(String chatId) throws ParseException {
+ if (!redisUtil.ifExist("history:" + chatId)) {
+ List list = getChatHistoryFromDB(chatId, 1, 20);
+ for (Message message : list) {
+ insertToRedis(message);
+ }
+ }
+ }
+
+ public void insertMessage(Message message) {
+ String id = message.getToId();
+ redisUtil.listAdd("unread:" + id, message);
+ }
+
+ public void deleteMessage(Message message) {
+ redisUtil.deleteFromList(message);
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/service/RelationService.java b/user-8072/src/main/java/com/ivmiku/tutorial/service/RelationService.java
new file mode 100644
index 0000000..8dc4bd3
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/service/RelationService.java
@@ -0,0 +1,120 @@
+package com.ivmiku.tutorial.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import com.ivmiku.tutorial.entity.*;
+import com.ivmiku.tutorial.mapper.BlackListMapper;
+import com.ivmiku.tutorial.mapper.FriendMapper;
+import com.ivmiku.tutorial.mapper.SubscribeMapper;
+import com.ivmiku.tutorial.utils.RedisUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Aurora
+ */
+@Service
+public class RelationService {
+ @Autowired
+ private BlackListMapper blackListMapper;
+
+ @Autowired
+ private FriendMapper friendMapper;
+
+ @Autowired
+ private RedisUtil redisUtil;
+
+ @Autowired
+ private SubscribeMapper subscribeMapper;
+
+ @Autowired
+ private UserService userService;
+
+ /**
+ * 屏蔽用户
+ * @param userId 用户id
+ * @param toIgnore 要屏蔽的用户id
+ */
+ public void IgnoreUser(String userId, String toIgnore) {
+ blackListMapper.insert(new IgnoreUser(userId, toIgnore));
+ if (redisUtil.ifExist("blacklist:" + userId)) {
+ redisUtil.listAdd("blacklist:" + userId, toIgnore);
+ }
+ }
+
+ /**
+ * 查询用户是否屏蔽了该用户
+ * @param userId 用户id
+ * @param ignoreId 要查询的id
+ * @return 查询结果
+ */
+ public boolean ifIgnored(String userId, String ignoreId) {
+ loadCache(userId);
+ List blackList = redisUtil.getStringList("blacklist:" + userId, 0, -1);
+ redisUtil.refreshExpire("blacklist:" + userId);
+ return blackList.contains(ignoreId);
+ }
+
+ /**
+ * 加载缓存
+ * @param userId 用户id
+ */
+ public void loadCache(String userId) {
+ if (!redisUtil.ifExist("blacklist:" + userId)) {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("user_id", userId);
+ List list = blackListMapper.selectList(queryWrapper);
+ List result = new ArrayList<>();
+ if (list != null) {
+ for (IgnoreUser object : list) {
+ result.add(object.getToIgnore());
+ }
+ }
+ for (String toIgnore : result) {
+ redisUtil.listAdd("blacklist:" + userId, toIgnore);
+ }
+ redisUtil.setExpireTime("blacklist:" + userId);
+ }
+ }
+
+ public void subscribe(String id, String toId) {
+ Subscribe subscribe = new Subscribe();
+ subscribe.setId(Long.valueOf(id));
+ subscribe.setSubId(Long.valueOf(toId));
+ subscribeMapper.insert(subscribe);
+ }
+
+ public List getFanList(String userId, int page, int size) {
+ List list = new ArrayList<>();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ Page pager = new Page<>(page, size);
+ queryWrapper.eq("sub_id", userId);
+ List array = subscribeMapper.selectPage(pager, queryWrapper).getRecords();
+ for (Subscribe subscribe : array) {
+ String queryId = String.valueOf(subscribe.getId());
+ User user = userService.selectUserById(queryId);
+ SubUser subUser = SubUser.setUser(user);
+ list.add(subUser);
+ }
+ return list;
+ }
+
+ public List getSubList(String userId, int page, int size) {
+ List list = new ArrayList<>();
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ Page pager = new Page<>(page, size);
+ queryWrapper.eq("id", userId);
+ List array = subscribeMapper.selectPage(pager, queryWrapper).getRecords();
+ for (Subscribe subscribe : array) {
+ String queryId = String.valueOf(subscribe.getSubId());
+ User user = userService.selectUserById(queryId);
+ SubUser subUser = SubUser.setUser(user);
+ list.add(subUser);
+ }
+ return list;
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/service/UserService.java b/user-8072/src/main/java/com/ivmiku/tutorial/service/UserService.java
new file mode 100644
index 0000000..86c6c77
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/service/UserService.java
@@ -0,0 +1,16 @@
+package com.ivmiku.tutorial.service;
+
+import com.ivmiku.tutorial.entity.User;
+import com.ivmiku.tutorial.mapper.UserMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserService {
+ @Resource
+ private UserMapper userMapper;
+
+ public User selectUserById(String id) {
+ return userMapper.selectById(id);
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/utils/DateUtil.java b/user-8072/src/main/java/com/ivmiku/tutorial/utils/DateUtil.java
new file mode 100644
index 0000000..8430632
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/utils/DateUtil.java
@@ -0,0 +1,43 @@
+package com.ivmiku.tutorial.utils;
+
+import jakarta.annotation.PostConstruct;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @author Aurora
+ */
+public class DateUtil {
+ /**
+ * 获取当前时间
+ * @return 当前时间字符串
+ */
+ public static String getCurrentTime() {
+ Date date = new Date();
+ SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return ft.format(date);
+ }
+
+ /**
+ * 转换为时间戳
+ * @param time 时间字符串
+ * @return 时间戳
+ * @throws ParseException
+ */
+ public static long toTimeSig(String time) throws ParseException {
+ SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date date = ft.parse(time);
+ return date.getTime();
+ }
+
+ /**
+ * 设置当前时区GMT+8
+ */
+ @PostConstruct
+ public void setTimeZone() {
+ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
+ }
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/utils/MessageUtil.java b/user-8072/src/main/java/com/ivmiku/tutorial/utils/MessageUtil.java
new file mode 100644
index 0000000..da73040
--- /dev/null
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/utils/MessageUtil.java
@@ -0,0 +1,36 @@
+package com.ivmiku.tutorial.utils;
+
+import com.ivmiku.tutorial.service.RelationService;
+import org.springframework.stereotype.Component;
+
+/**
+ * 敏感词检测
+ * @author Aurora
+ */
+@Component
+public class MessageUtil {
+ private static final String[] SENSITIVE = {"你妈", "你妈逼的"};
+
+ private static RelationService relationService = null;
+
+ public MessageUtil(RelationService relationService) {
+ MessageUtil.relationService = relationService;
+ }
+
+ /**
+ * 查看发送的信息是否含有敏感词
+ * @param message 要发送的信息
+ * @return 检查结果
+ */
+ public static boolean checkMessage(String message) {
+ if (message != null) {
+ for(String keyword : SENSITIVE) {
+ if (message.contains(keyword)){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java b/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
index 8ff2877..fb0c172 100644
--- a/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
+++ b/user-8072/src/main/java/com/ivmiku/tutorial/utils/RedisUtil.java
@@ -1,9 +1,18 @@
package com.ivmiku.tutorial.utils;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.entity.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
/**
* @author Aurora
*/
@@ -12,11 +21,110 @@ public class RedisUtil {
@Autowired
private RedisTemplate redisTemplate;
- public void insertKey(String userId, String sessionKey) {
- redisTemplate.opsForValue().set("sessionkey:" + userId, sessionKey);
+ public void listAdd(String key, Object value) {
+ redisTemplate.opsForList().leftPush(key, value);
+ }
+
+ public List listGet(String key, int s, int e) {
+ List