🔗 WebSocket 연동 흐름 정리 (서버 ↔ 클라이언트)
✅ 1. 연결 시작 (Connection Established)
📌 클라이언트 (chatting.js)
client.onopen = (event) => {
console.log("[Client] 연결 성공 / Successful Connection with Server");
console.log(event);
const msg = {
type: "join",
room: room,
nickName: nickName
};
client.send(JSON.stringify(msg));
};
📌 서버 (ChatSocketHandler.java)
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("[Server] 연결 성공 / Successful connection with client socket");
}
✅ 2. 입장 처리 (type: "join")
📌 클라이언트
const msg = {
type: "join",
room: room,
nickName: nickName
};
client.send(JSON.stringify(msg));
📌 서버
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("[Server] 메시지 수신 / message from client socket");
System.out.println(message.getPayload());
Map<String, String> msg = objectMapper.readValue(
message.getPayload(),
new TypeReference<>() {}
);
if (msg.get("type").equals("join")) {
String room = msg.get("room");
String nickName = msg.get("nickName");
session.getAttributes().put("room", room);
session.getAttributes().put("nickName", nickName);
if (connectingMap.containsKey(room)) {
connectingMap.get(room).add(session);
} else {
List<WebSocketSession> list = new Vector<>();
list.add(session);
connectingMap.put(room, list);
}
alarmMessage(room, nickName + "이 입장했습니다.");
}
✅ 3. 메시지 전송 (type: "msg")
📌 클라이언트
const onMsgSend = () => {
const msginput = document.querySelector(".msginput");
const message = msginput.value;
if (message === '') return;
const msg = {
type: "msg",
message: message,
from: nickName,
date: new Date().toLocaleString()
};
client.send(JSON.stringify(msg));
msginput.value = '';
};
📌 서버
else if (msg.get("type").equals("msg")) {
String room = (String) session.getAttributes().get("room");
for (WebSocketSession client : connectingMap.get(room)) {
client.sendMessage(message);
}
}
✅ 4. 서버 → 클라이언트 메시지 수신 처리
📌 클라이언트
client.onmessage = (event) => {
console.log("[Client] 메시지 수신 / Incoming Message from Server");
const message = JSON.parse(event.data);
const msgbox = document.querySelector(".msgbox");
let html = '';
if (message.type === "alarm") {
html += `${message.message}`;
} else if (message.type === "msg") {
if (message.from === nickName) {
html += `${message.date} ${message.message}`;
} else {
html += `${message.from} ${message.message} ${message.date}`;
}
}
msgbox.innerHTML += html;
msgbox.scrollTop = msgbox.scrollHeight;
};
📌 서버
public void alarmMessage(String room, String message) throws Exception {
Map<String, String> msg = new HashMap<>();
msg.put("type", "alarm");
msg.put("message", message);
String sendMsg = objectMapper.writeValueAsString(msg);
for (WebSocketSession session : connectingMap.get(room)) {
session.sendMessage(new TextMessage(sendMsg));
}
}
✅ 5. 연결 종료 처리
📌 클라이언트
client.onclose = (event) => {
console.log("[Client] 연결 종료 / Shutting down the connection with Server");
console.log(event);
};
📌 서버
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("[Server] 연결 종료 / Shutting down the connection with the client socket");
String room = (String) session.getAttributes().get("room");
String nickName = (String) session.getAttributes().get("nickName");
if (room != null && nickName != null) {
List<WebSocketSession> list = connectingMap.get(room);
list.remove(session);
alarmMessage(room, nickName + "이 퇴장했습니다.");
}
}
✅ ChatSocketHandler
@Component
public class ChatSocketHandler extends TextWebSocketHandler {
private static final Map<String, List<WebSocketSession>> connectingMap = new Hashtable<>();
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("[Server] 연결 성공 / Successful connection with client socket");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("[Server] 연결 종료 / Shutting down the connection with the client socket");
String room = (String) session.getAttributes().get("room");
String nickName = (String) session.getAttributes().get("nickName");
if (room != null && nickName != null) {
List<WebSocketSession> list = connectingMap.get(room);
list.remove(session);
alarmMessage(room, nickName + "이 퇴장했습니다.");
}
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("[Server] 메세지 / message from client socket");
System.out.println(message.getPayload());
Map<String, String> msg = objectMapper.readValue(
message.getPayload(),
new com.fasterxml.jackson.core.type.TypeReference<Map<String, String>>() {
}
);
if (msg.get("type").equals("join")) {
String room = msg.get("room");
String nickName = msg.get("nickName");
session.getAttributes().put("room", room);
session.getAttributes().put("nickName", nickName);
if (connectingMap.containsKey(room)) {
connectingMap.get(room).add(session);
} else {
List<WebSocketSession> list = new Vector<>();
list.add(session);
connectingMap.put(room, list);
}
alarmMessage(room, nickName + "이 입장했습니다.");
}
else if (msg.get("type").equals("msg")) {
String room = (String) session.getAttributes().get("room");
for (WebSocketSession client : connectingMap.get(room)){
client.sendMessage(message);
}
}
System.out.println(connectingMap);
}
public void alarmMessage(String room, String message) throws Exception {
Map<String, String> msg = new HashMap<>();
msg.put("type", "alarm");
msg.put("message", message);
String sendMsg = objectMapper.writeValueAsString(msg);
for (WebSocketSession session : connectingMap.get(room)) {
session.sendMessage(new TextMessage(sendMsg));
}
}
}
✅ WebSocketConfig
@Component
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private ChatSocketHandler chatSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(chatSocketHandler, "/chat");
}
}
✅ chatting.js
console.log("chatting js exe")
const randomId = Math.floor(Math.random() * 1000) + 1
const nickName = `익명${randomId}`
const params = new URL(location.href).searchParams;
const room = params.get("room") || "0";
const clinet = new WebSocket("/chat")
clinet.onopen = (event) => {
console.log("[Client] 연결 성공 / Successful Connection with Server")
console.log(event)
let msg = { type: "join", room: room, nickName: nickName }
clinet.send(JSON.stringify(msg));
}
clinet.onclose = (event) => {
console.log("[Client] 연결 종료 / Shutting down the connection with Server")
console.log(event)
}
clinet.onmessage = (event) => {
console.log("[Client] 메세지 / Incomming Message from Server")
console.log(event)
const message = JSON.parse(event.data);
const msgbox = document.querySelector(".msgbox")
let html = '';
if (message.type == "alarm") {
html += `<div class="alarm"> <span>${message.message}</span></div>`
}
else if (message.type == "msg") {
if (message.from == nickName) {
html += `<div class="secontent">
<div class="date"> ${message.date} </div>
<div class="content"> ${message.message} </div>
</div>`;
}
else {
html += `<div class="receiveBox">
<div class="profileImg">
<img src="default.jpg"/>
</div>
<div>
<div class="recontent">
<div class="memberNic"> ${message.from} </div>
<div class="subcontent">
<div class="content"> ${message.message} </div>
<div class="date"> ${message.date} </div>
</div>
</div>
</div>
</div>`;
}
}
msgbox.innerHTML += html;
msgbox.scrollTop = msgbox.scrollHeight
}
clinet.onerror = (event) => {
console.log("[Client] 에러 / Error")
console.log(event)
}
const onMsgSend = () => {
const msginput = document.querySelector(".msginput")
const message = msginput.value;
if (message == '') return
const msg = { type: "msg", message: message, from: nickName, date : new Date().toLocaleString() }
clinet.send(JSON.stringify(msg))
msginput.value = '';
}
const enterKey = () => {
if (window.event.keyCode == 13) {
onMsgSend()
}
}