From 668fedc0f5c544bbfd2f6c8c584a675cb84b8b35 Mon Sep 17 00:00:00 2001 From: yennanliu Date: Mon, 27 Nov 2023 17:23:19 +0800 Subject: [PATCH 1/4] fix to send private msg to redis channel --- .../springChatRoom/controller/ChatController.java | 5 +++-- .../yen/springChatRoom/redis/RedisListenerBean.java | 12 +++++++++++- springChatRoom/src/main/resources/static/js/main.js | 7 ++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java index aa6c0bacf..79b598732 100644 --- a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java @@ -15,6 +15,7 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Slf4j @@ -91,8 +92,8 @@ public void addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor } // TODO : check @DestinationVariable ? - @RequestMapping("/app/private/{username}") - public void handlePrivateMessage(@DestinationVariable String username, Message message){ + @MessageMapping("/private/{username}") + public void handlePrivateMessage(@PathVariable String username, Message message){ log.info("handlePrivateMessage : username = " + username + " message = " + message); // save to redis diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/redis/RedisListenerBean.java b/springChatRoom/src/main/java/com/yen/springChatRoom/redis/RedisListenerBean.java index a40840cef..3aba60f03 100644 --- a/springChatRoom/src/main/java/com/yen/springChatRoom/redis/RedisListenerBean.java +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/redis/RedisListenerBean.java @@ -31,6 +31,9 @@ public class RedisListenerBean { @Value("${redis.channel.userStatus}") private String userStatus; + @Value("${redis.channel.private}") + private String privateChannel; + /** Redis channel bean * * 1. listen Redis channel via binding (for example : container.addMessageListener) @@ -44,8 +47,15 @@ RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory // listen msgToAll (Redis channel) container.addMessageListener(listenerAdapter, new PatternTopic(msgToAll)); - container.addMessageListener(listenerAdapter, new PatternTopic(userStatus)); + LOGGER.info("Subscribe Redis channel : " + msgToAll); + container.addMessageListener(listenerAdapter, new PatternTopic(userStatus)); + + LOGGER.info("Subscribe Redis channel : " + userStatus); + + container.addMessageListener(listenerAdapter, new PatternTopic(privateChannel)); + LOGGER.info("Subscribe Redis channel : " + privateChannel); + return container; } diff --git a/springChatRoom/src/main/resources/static/js/main.js b/springChatRoom/src/main/resources/static/js/main.js index 069c605a8..b64009c1c 100644 --- a/springChatRoom/src/main/resources/static/js/main.js +++ b/springChatRoom/src/main/resources/static/js/main.js @@ -44,6 +44,9 @@ function onConnected() { // Subscribe to the "/private" destination // TODO : make it general //stompClient.subscribe('/private/user123', onPrivateMessageReceived); + console.log(">>> subscribe /app/private/"+username ); + stompClient.subscribe('/app/private/'+username); + // Tell your username to the server stompClient.send("/app/chat.addUser", {}, @@ -210,10 +213,12 @@ function startChat(username) { // send msg to BE //stompClient.subscribe('/app/private/' + username, onPrivateMessageReceived); - stompClient.subscribe('/app/private/' + username); + //stompClient.subscribe('/app/private/' + username); console.log(">>> send msg to /app/private/" + username + ", message = " + message); stompClient.send('/app/private/' + username, {}, JSON.stringify({ sender: 'You', content: message, type: 'CHAT' })); + console.log("send private msg end") + // Clear the input field messageInput.value = ''; } From 486c892e71dda77c5446001732d35e10db5c714b Mon Sep 17 00:00:00 2001 From: yennanliu Date: Tue, 28 Nov 2023 19:23:18 +0800 Subject: [PATCH 2/4] fix private stompClient.send model, fix BE save redis channel name --- .../main/java/com/yen/springChatRoom/bean/User.java | 5 +++++ .../springChatRoom/controller/ChatController.java | 7 +++++-- springChatRoom/src/main/resources/static/js/main.js | 13 +++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 springChatRoom/src/main/java/com/yen/springChatRoom/bean/User.java diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/bean/User.java b/springChatRoom/src/main/java/com/yen/springChatRoom/bean/User.java new file mode 100644 index 000000000..951f53675 --- /dev/null +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/bean/User.java @@ -0,0 +1,5 @@ +package com.yen.springChatRoom.bean; + +//public class User { +// private +//} diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java index 79b598732..d32a6c2d5 100644 --- a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java @@ -96,10 +96,13 @@ public void addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor public void handlePrivateMessage(@PathVariable String username, Message message){ log.info("handlePrivateMessage : username = " + username + " message = " + message); - // save to redis + // save to redis // redisTemplate.convertAndSend(userStatus, JsonUtil.parseObjToJson(chatMessage)); - redisTemplate.opsForSet().add(privateChannel + "." + username, JsonUtil.parseObjToJson(message)); + // TODO : fix data model + // current : handlePrivateMessage : username = {"sender":"fewfew","content":"777","type":"PRIVATE_CHAT"} message = Message(sender=fewfew, content=777, type=PRIVATE_CHAT) + //redisTemplate.opsForSet().add(privateChannel + "." + username, JsonUtil.parseObjToJson(message)); + redisTemplate.opsForSet().add(privateChannel + "." + message.getSender(), JsonUtil.parseObjToJson(message)); simpMessagingTemplate.convertAndSendToUser(username, "/topic/private", message); } diff --git a/springChatRoom/src/main/resources/static/js/main.js b/springChatRoom/src/main/resources/static/js/main.js index b64009c1c..3b3fedfcf 100644 --- a/springChatRoom/src/main/resources/static/js/main.js +++ b/springChatRoom/src/main/resources/static/js/main.js @@ -214,8 +214,17 @@ function startChat(username) { // send msg to BE //stompClient.subscribe('/app/private/' + username, onPrivateMessageReceived); //stompClient.subscribe('/app/private/' + username); - console.log(">>> send msg to /app/private/" + username + ", message = " + message); - stompClient.send('/app/private/' + username, {}, JSON.stringify({ sender: 'You', content: message, type: 'CHAT' })); + + var chatMessage = { + sender: username, + content: messageInput.value, + type: 'PRIVATE_CHAT' + }; + + console.log(">>> chatMessage = " + JSON.stringify(chatMessage)) + + console.log(">>> send msg to /app/private/" + chatMessage.sender + ", message = " + message + " chatMessage = " + chatMessage); + stompClient.send(`/app/private/${chatMessage.sender}`, {}, JSON.stringify(chatMessage) ); console.log("send private msg end") From 33e393d9efdb6cf8a676ea2de202850fc676b017 Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 29 Nov 2023 00:01:25 +0800 Subject: [PATCH 3/4] add BE private chat history endpoint, fix log, FE api call pathj --- .../springChatRoom/controller/ChatController.java | 12 ++++++++++++ springChatRoom/src/main/resources/static/js/main.js | 5 +++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java index d32a6c2d5..251f7edb0 100644 --- a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java @@ -18,6 +18,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; +import java.util.Set; + @Slf4j @Controller public class ChatController { @@ -107,4 +109,14 @@ public void handlePrivateMessage(@PathVariable String username, Message message) simpMessagingTemplate.convertAndSendToUser(username, "/topic/private", message); } + @MessageMapping("/private/history/{username}") + public void getHistoryPrivateChat(@PathVariable String username, Message message){ + + String key = "/private/history/" + username; + // Set resultSet = redisTemplate.opsForSet().members("key1"); + Set res = redisTemplate.opsForSet().members(key); + res.forEach(System.out::println); + + } + } diff --git a/springChatRoom/src/main/resources/static/js/main.js b/springChatRoom/src/main/resources/static/js/main.js index 3b3fedfcf..a2ffbcdba 100644 --- a/springChatRoom/src/main/resources/static/js/main.js +++ b/springChatRoom/src/main/resources/static/js/main.js @@ -223,7 +223,7 @@ function startChat(username) { console.log(">>> chatMessage = " + JSON.stringify(chatMessage)) - console.log(">>> send msg to /app/private/" + chatMessage.sender + ", message = " + message + " chatMessage = " + chatMessage); + console.log(">>> send msg to /private/" + chatMessage.sender + ", message = " + message + " chatMessage = " + chatMessage); stompClient.send(`/app/private/${chatMessage.sender}`, {}, JSON.stringify(chatMessage) ); console.log("send private msg end") @@ -236,7 +236,8 @@ function startChat(username) { // Function to fetch and display chat history function fetchChatHistory(username, chatMessages) { - fetch('/app/chat/history/' + username) + console.log("fetch history chat : " + `/private/history/${username}`) + fetch(`/private/history/${username}`) .then(response => response.json()) .then(history => { history.forEach(message => { From 44dcd420f9452cb53b93fc7d3637270c0dd5589c Mon Sep 17 00:00:00 2001 From: yennanliu Date: Wed, 29 Nov 2023 18:38:49 +0800 Subject: [PATCH 4/4] add chatHistory controller, fix fetch api url, fix fetch logic, fix main.js conflict --- .../controller/ChatController.java | 4 +- .../controller/HistoryController.java | 39 +++++++++++++++++++ .../src/main/resources/static/js/main.js | 28 ++++++------- 3 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 springChatRoom/src/main/java/com/yen/springChatRoom/controller/HistoryController.java diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java index 251f7edb0..dc514ccaf 100644 --- a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/ChatController.java @@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.simp.SimpMessagingTemplate; @@ -15,8 +14,9 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; + import java.util.Set; diff --git a/springChatRoom/src/main/java/com/yen/springChatRoom/controller/HistoryController.java b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/HistoryController.java new file mode 100644 index 000000000..c6143ddd3 --- /dev/null +++ b/springChatRoom/src/main/java/com/yen/springChatRoom/controller/HistoryController.java @@ -0,0 +1,39 @@ +package com.yen.springChatRoom.controller; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Set; + +@RestController +@Slf4j +public class HistoryController { + + @Value("${redis.channel.private}") + private String privateChannel; + + @Autowired + private RedisTemplate redisTemplate; + //private RedisTemplate redisTemplate; + + //@MessageMapping("/private/chat_history/{username}") + @GetMapping("/private/chat_history/{username}") + public void getChatHistory(@PathVariable String username){ + + log.info("getChatHistory : username = " + username); + + String key = "websocket.privateMsg." + username; // websocket.privateMsg.zzz + log.info("key = " + key); + Set resultSet = redisTemplate.opsForSet().members(key); + + log.info("--> start"); + resultSet.forEach(System.out::println); + log.info("--> end"); + } + +} diff --git a/springChatRoom/src/main/resources/static/js/main.js b/springChatRoom/src/main/resources/static/js/main.js index a2ffbcdba..cf89c1b0d 100644 --- a/springChatRoom/src/main/resources/static/js/main.js +++ b/springChatRoom/src/main/resources/static/js/main.js @@ -47,6 +47,8 @@ function onConnected() { console.log(">>> subscribe /app/private/"+username ); stompClient.subscribe('/app/private/'+username); + stompClient.subscribe(`/app/private/chat_history/${username}`); + // Tell your username to the server stompClient.send("/app/chat.addUser", {}, @@ -128,6 +130,7 @@ function getAvatarColor(messageSender) { // online user function fetchUserList() { + // NOTE !!! it's http call (not web socket call) fetch('/user/online_user') // Replace with the actual endpoint URL .then(response => response.json()) .then(data => { @@ -142,12 +145,6 @@ function updateOnlineUsers(users) { const userList = document.getElementById('userList'); userList.innerHTML = ''; // Clear the list first -// users.forEach(user => { -// const listItem = document.createElement('li'); -// listItem.textContent = user; -// userList.appendChild(listItem); -// }); - users.forEach(user => { const listItem = document.createElement('li'); @@ -199,14 +196,13 @@ function startChat(username) { const messageInput = popupWindow.document.getElementById('messageInput'); const chatMessages = popupWindow.document.getElementById('chatMessages'); + //log.info(">>> chatMessages = " + JSON.stringify(chatMessages)) + const message = messageInput.value.trim(); if (message !== '') { // Customize the way messages are displayed in the popup window chatMessages.innerHTML += '

You: ' + message + '

'; - // TODO: Fetch and display chat history - //fetchChatHistory(username, chatMessages); - // TODO : implement below in BE // Add your logic to send the message to the other user // Example: stompClient.send('/app/private/' + username, {}, JSON.stringify({ sender: 'You', content: message, type: 'CHAT' })); @@ -228,6 +224,11 @@ function startChat(username) { console.log("send private msg end") + // TODO : check whether send private msg to Redis or fetch history msg from Redis first ? + // TODO: Fetch and display chat history + //fetchChatHistory(username, chatMessages); + //fetchChatHistory(username); + // Clear the input field messageInput.value = ''; } @@ -235,13 +236,14 @@ function startChat(username) { } // Function to fetch and display chat history -function fetchChatHistory(username, chatMessages) { - console.log("fetch history chat : " + `/private/history/${username}`) - fetch(`/private/history/${username}`) +function fetchChatHistory(username) { + fetch(`/private/chat_history/${username}`) .then(response => response.json()) + .then(console.log(">>> response = " + JSON.stringify(response))) .then(history => { history.forEach(message => { - chatMessages.innerHTML += '

' + message.sender + ': ' + message.content + '

'; + //chatMessages.innerHTML += '

' + message.sender + ': ' + message.content + '

'; + console.log(">>> message = " + JSON.stringify(message)) }); }) .catch(error => {