[22/02/19] 채팅 기능 구현하기(1)

Que Lin·2022년 2월 19일
0


참고 : 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>

아직 자세히 구현하지 않았지만, 고쳐가면서 열심히 익히도록 해야겠다.

공부한 후에 채팅방 나누기, 세션값 가져오기를 해야겠다.

profile
1일 1커밋 1일 1벨로그!

0개의 댓글