참고 : https://dev-gorany.tistory.com/212?category=901854
정말 잘 정리해주셔서 쉽게 구현해 낼 수 있었다.
노드로 했던 채팅 기능은 오류를 못잡아내겠어서 다음에 다시 해보기로 하고 웹소켓을 사용해서 구현하였다.
chatting > ChatHandler / WebSocketConfig 생성
ChatHandler
package com.phl.cocolo.chatting;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.ArrayList;
import java.util.List;
@Component
@Log4j2
public class ChatHandler extends TextWebSocketHandler {
private static List<WebSocketSession> list = new ArrayList<>();
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
log.info("payload : " + payload);
for(WebSocketSession sess: list) {
sess.sendMessage(message);
}
}
/* Client가 접속 시 호출되는 메서드 */
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
list.add(session);
log.info(session + " 클라이언트 접속");
}
/* Client가 접속 해제 시 호출되는 메서드드 */
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
log.info(session + " 클라이언트 접속 해제");
list.remove(session);
}
}
WebSocketConfig
왜 웹소켓으로 할 때는 cors 오류가 이렇게 쉽게 잡혔을까? 다음에 노드를 다시 시도해보면서 알아가야겠다.
package com.phl.cocolo.chatting;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@RequiredArgsConstructor
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final ChatHandler chatHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(chatHandler, "ws/chat").setAllowedOrigins("*");
}
}
chat.html
모달을 사용하여 채팅창을 띄우기로 했다.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html">
<html lang="en" itemscope itemtype="http://schema.org/WebPage">
<!-- 공통 헤더-->
<th:block th:replace="/layout/fragments/head :: headFragment"></th:block>
<body>
<th:block th:replace="/layout/fragments/navbar :: navbarFragment"></th:block>
<div class="modal fade" id="chatModal" data-bs-backdrop="static" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="user-container modal-header">
<label class="modal-title" id="staticBackdropLabel" for="nickname">대화명</label>
<span type="text" id="nickname" th:text="${session['loginNick']}" th:value="${session['loginNick']}"></span>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="display-container modal-body" style="height: 1000px">
<ul class="chatting-list">
</ul>
</div>
<div class="input-container modal-footer">
<span>
<textarea type="text" id="msg" class="chatting-input form-control" aria-label="Recipient's username" aria-describedby="button-addon2"></textarea>
<button type="button" id="send-button" class="send-button">전송</button>
</span>
</div>
</div>
</div>
</div>
<div class="wrapper" style="margin-top: 100px;">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#chatModal">채팅하기</button>
</div>
</body>
<th:block th:replace="/layout/fragments/script :: scriptFragment"></th:block>
<script th:inline="javascript">
$(document).ready(function(){
const date = new Date();
const hours = String(date.getHours()).padStart(2,"0");
const minutes = String(date.getMinutes()).padStart(2,"0");
const time = `${hours}시 : ${minutes}분`;
const username = "관리자";
const msg = document.getElementById('msg');
console.log(msg.value);
console.log(username);
$("#disconn").on("click", (e) => {
disconnect();
})
$("#send-button").on("click", (e) => {
if(msg.value == "" || msg.value == " "){
}else {
send();
}
});
let websocket = new WebSocket("ws://localhost:8095/ws/chat");
websocket.onmessage = onMessage;
websocket.onopen = onOpen;
websocket.onclose = onClose;
function send(){
let msg = document.getElementById("msg");
console.log(username + ":" + msg.value);
websocket.send(username + ":" + msg.value);
msg.value = '';
}
//채팅창에서 나갔을 때
function onClose(evt) {
let str = username + ": 님이 방을 나가셨습니다.";
websocket.send(str);
}
//채팅창에 들어왔을 때
function onOpen(evt) {
let str = username + ": 님이 입장하셨습니다.";
websocket.send(str);
}
function onMessage(msg) {
let data = msg.data;
let sessionId = null;
//데이터를 보낸 사람
let message = null;
let arr = data.split(":");
for(let i=0; i<arr.length; i++){
console.log('arr[' + i + ']: ' + arr[i]);
}
let cur_session = username;
//현재 세션에 로그인 한 사람
console.log("cur_session : " + cur_session);
sessionId = arr[0];
message = arr[1];
console.log("sessionID : " + sessionId);
console.log("cur_session : " + cur_session);
const item = new LiModel(sessionId, message,time);
item.makeLi();
}
function LiModel(sessionId,message,time){
this.name = sessionId;
this.msg = message;
this.time = time;
const chatList = document.querySelector(".chatting-list");
const nickname = document.querySelector("#nickname");
this.makeLi = ()=>{
const li = document.createElement("li");
li.classList.add(nickname.value === this.name ? "sent" : "received")
const dom = ` <span class="profile">
<span class="user">${this.name}</span>
<img class="image" src="https://placeimg.com/50/50/any" alt="any">
</span>
<span class="message">${this.msg}</span>
<span class="time">${this.time}</span>`;
li.innerHTML = dom;
chatList.appendChild(li)
}
}
})
</script>
</html>
아직 자세히 구현하지 않았지만, 고쳐가면서 열심히 익히도록 해야겠다.
공부한 후에 채팅방 나누기, 세션값 가져오기를 해야겠다.