Skip to content

Commit

Permalink
add online user, controller, js, remove legacy code, add junit dep
Browse files Browse the repository at this point in the history
  • Loading branch information
yennanliu committed Nov 12, 2023
1 parent f628fd0 commit a8d2ec1
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 52 deletions.
29 changes: 17 additions & 12 deletions springChatRoom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ java -jar target/springChatRoom-0.0.1-SNAPSHOT.jar

## Todo
- Feature
- show user(online/offline) list
- private msg (1 to 1)
- setup group, group chat
- @ "notification"
- msg push (?)
- "read" 已讀 feature
- show user list
- save history msg
- broadcast msg
- push msg to users (offer API)
Expand All @@ -67,16 +67,21 @@ java -jar target/springChatRoom-0.0.1-SNAPSHOT.jar
## Knowledge

- WebSocket
- Server can send info to client (bi-directon communicartion, TCP protocol)
- 3 ways handshake
- server, client side can send/receive msg, and terminate connection
- long connection between server and client, no need to check with client every time
- more efficient when communicating (header is shorter)
- Server can send info to client (bi-directon communicartion, TCP protocol)
- 3 ways handshake
- server, client side can send/receive msg, and terminate connection
- long connection between server and client, no need to check with client every time
- more efficient when communicating (header is shorter)

- Use case of WebSocket
- chat room
- online game
- geo location app
- stock market app
- co-editing system (e.g. google doc ?)
- app needs near real-time update/sync, data transmit is not small
- chat room
- online game
- geo location app
- stock market app
- co-editing system (e.g. google doc ?)
- app needs near real-time update/sync, data transmit is not small

## Reference

- redisTemplate API cmd
- https://ost.51cto.com/posts/2333
3 changes: 2 additions & 1 deletion springChatRoom/doc/ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@
- Chat with specific user
- https://www.baeldung.com/spring-websockets-send-message-to-user
- https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-web-sockets - code
-
- https://juejin.cn/post/6844903717636947981

- https://www.jb51.net/article/257091.htm
8 changes: 7 additions & 1 deletion springChatRoom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@
<version>1.2.79</version>
</dependency>

</dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.yen.springChatRoom.bean;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class OnlineUser {

public OnlineUser(){
}

public OnlineUser(List<String> users){
this.users = users;
}

private List<String> users;

public List<String> getUsers() {
return users;
}

public void setUsers(List<String> users) {
this.users = users;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.Set;

@Controller
public class ChatController {
Expand All @@ -25,6 +28,8 @@ public class ChatController {
@Value("${redis.channel.userStatus}")
private String userStatus;

final String onlineUserKey = "websocket.onlineUsers";

// TODO : check difference ? RedisTemplate VS RedisTemplate<String, String>
@Autowired
private RedisTemplate<String, String> redisTemplate;
Expand Down Expand Up @@ -58,7 +63,6 @@ public void sendMessage(@Payload ChatMessage chatMessage){
}
}


@MessageMapping("/chat.addUser")
public void addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {

Expand All @@ -67,28 +71,12 @@ public void addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor
headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
redisTemplate.opsForSet().add(onlineUsers, chatMessage.getSender());
redisTemplate.convertAndSend(userStatus, JsonUtil.parseObjToJson(chatMessage));

// show online user

} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}

// @MessageMapping("/chat.addUser")
// @SendTo("/topic/public")
// public ChatMessage addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {
//
// LOGGER.info("User added in Chatroom:" + chatMessage.getSender());
// // add username in web socket session
// headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
// return chatMessage;
//
// // TODO : update with below
//// try {
//// headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
////// redisTemplate.opsForSet().add(onlineUsers, chatMessage.getSender());
////// redisTemplate.convertAndSend(userStatus, JsonUtil.parseObjToJson(chatMessage));
//// } catch (Exception e) {
//// LOGGER.error(e.getMessage(), e);
//// }
// }

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.yen.springChatRoom.controller;

import com.yen.springChatRoom.bean.OnlineUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("/user")
public class UserController {

@Value("${redis.channel.msgToAll}")
private String msgToAll;

@Value("${redis.set.onlineUsers}")
private String onlineUsers;

@Value("${redis.channel.userStatus}")
private String userStatus;

final String onlineUserKey = "websocket.onlineUsers";

@Autowired
private RedisTemplate<String, String> redisTemplate;

private static final Logger LOGGER = LoggerFactory.getLogger(ChatController.class);

@GetMapping("/online_user")
public List<String> getOnlineUser(){

Set<String> resultSet = redisTemplate.opsForSet().members(onlineUserKey);
System.out.println("(getOnlineUser) resultSet = " + resultSet);
// TODO : optimize below
OnlineUser onlineUser = new OnlineUser();
List<String> users = new ArrayList<>();
resultSet.forEach(x -> {
users.add(x);
});
onlineUser.setUsers(users);
return onlineUser.getUsers();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,4 @@ public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
}
}

// @EventListener
// public void handleWebSocketDisConnectListener(SessionDisconnectEvent event){
//
// StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
// String username = (String) headerAccessor.getSessionAttributes().get("username");
//
// if (username != null){
//
// LOGGER.info("User disconnected : " + username);
// ChatMessage chatMessage = new ChatMessage();
// chatMessage.setType(ChatMessage.MessageType.LEAVE);
// chatMessage.setSender(username);
//
// messagingTemplate.convertAndSend("/topic/public", chatMessage);
// }
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public void onMessage(Message message, byte[] bytes) {
return;
}


if (msgToAll.equals(topic)) {
LOGGER.info("Send message to all users:" + rawMsg);
ChatMessage chatMessage = JsonUtil.parseJsonToObj(rawMsg, ChatMessage.class);
Expand Down
6 changes: 6 additions & 0 deletions springChatRoom/src/main/resources/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ <h2>Spring WebSocket Chat Demo</h2>
</div>
</form>
</div>

<div id="online-users">
<h2>Online Users</h2>
<ul id="userList"></ul>
</div>

</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
Expand Down
29 changes: 29 additions & 0 deletions springChatRoom/src/main/resources/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,34 @@ function getAvatarColor(messageSender) {
return colors[index];
}

// online user
function fetchUserList() {
fetch('/user/online_user') // Replace with the actual endpoint URL
.then(response => response.json())
.then(data => {
updateOnlineUsers(data);
})
.catch(error => {
console.error('Error fetching user list: ', error);
});
}

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);
});
}

// Call the fetchUserList function to initially populate the user list
fetchUserList();

// You can also periodically update the user list using a timer or other events
setInterval(fetchUserList, 5000); // Update every 5 seconds (adjust as needed)

usernameForm.addEventListener('submit', connect, true)
messageForm.addEventListener('submit', sendMessage, true)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.yen.springChatRoom.controller;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

@RunWith(SpringRunner.class)
@SpringBootTest
class ChatControllerTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Test
public void testQueryRedis(){

final String onlineUserKey = "websocket.onlineUsers";
// https://ost.51cto.com/posts/2333
Set<String> resultSet = redisTemplate.opsForSet().members(onlineUserKey);
System.out.println("resultSet:" + resultSet);

}

}

0 comments on commit a8d2ec1

Please sign in to comment.