Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

고마구의 개발 블로그

240722 14주차 월요일 - Spring 06 본문

KDT풀스택과정 공부

240722 14주차 월요일 - Spring 06

고마구 2024. 7. 22. 16:17

1:1 채팅 기능을 구현하기 위해서는 각 세션을 개별적으로 관리해야 합니다. 이를 위해 클라이언트와 서버 모두에서 사용자 구분과 메시지 전송 로직을 변경해야 합니다. 여기서는 Spring Boot와 WebSocket을 이용하여 1:1 채팅 기능을 구현하는 방법을 설명하겠습니다.

1. WebSocketConfig 클래스

기본 설정은 동일하지만, 사용자별 메시지 전송을 위해 사용자 ID를 사용할 수 있도록 합니다.

WebSocketConfig.java

java
package com.example.websocket;

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
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new ChatWebSocketHandler(), "/Chatting").setAllowedOrigins("*");
    }
}

2. WebSocket 핸들러

사용자별로 메시지를 관리할 수 있도록 WebSocket 핸들러를 수정합니다.

ChatWebSocketHandler.java

java
package com.example.websocket;

import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ChatWebSocketHandler extends TextWebSocketHandler {
    private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String userId = getUserId(session);
        sessions.put(userId, session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String userId = getUserId(session);
        String payload = message.getPayload();

        // 메시지 형식: "toUserId:message"
        String[] parts = payload.split(":", 2);
        if (parts.length == 2) {
            String toUserId = parts[0];
            String msg = parts[1];

            WebSocketSession toSession = sessions.get(toUserId);
            if (toSession != null && toSession.isOpen()) {
                toSession.sendMessage(new TextMessage(userId + ":" + msg));
            }
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String userId = getUserId(session);
        sessions.remove(userId);
    }

    private String getUserId(WebSocketSession session) {
        // 세션에서 사용자 ID를 가져오는 로직 구현
        // 예: session.getAttributes().get("userId");
        return session.getUri().getQuery().split("=")[1];
    }
}

3. 채팅 기록을 처리하는 ChatController

채팅 기록을 데이터베이스에서 불러오고 저장하는 컨트롤러를 작성합니다.

ChatController.java

java
package com.example.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.sql.Timestamp;
import java.util.List;
import java.util.Map;

@RestController
public class ChatController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/Chat_Select.do")
    public String getChatHistory(String userId, String otherUserId) {
        String sql = "SELECT CHAT_ARTICLE, CHAT_TIME FROM CHATTING WHERE (USER_ID = ? AND OTHER_USER_ID = ?) OR (USER_ID = ? AND OTHER_USER_ID = ?) ORDER BY CHAT_TIME";
        List<Map<String, Object>> chats = jdbcTemplate.queryForList(sql, userId, otherUserId, otherUserId, userId);

        StringBuilder response = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?><chats><chat>");
        for (Map<String, Object> chat : chats) {
            response.append("<chat_Article>")
                    .append(chat.get("CHAT_ARTICLE"))
                    .append("</chat_Article>");
        }
        response.append("</chat></chats>");
        return response.toString();
    }
    
    @GetMapping("/Chat_Save.do")
    public void saveChat(String userId, String otherUserId, String chatArticle) {
        String sql = "INSERT INTO CHATTING (USER_ID, OTHER_USER_ID, CHAT_ARTICLE, CHAT_TIME) VALUES (?, ?, ?, ?)";
        jdbcTemplate.update(sql, userId, otherUserId, chatArticle, new Timestamp(System.currentTimeMillis()));
    }
}

4. Spring Boot 애플리케이션 클래스

Spring Boot 애플리케이션 클래스를 작성합니다.

WebSocketApplication.java

java
package com.example.websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebSocketApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketApplication.class, args);
    }
}

5. 클라이언트 HTML 파일 수정

클라이언트가 사용자 ID를 전송할 수 있도록 HTML 파일을 수정합니다.

Chatting.jsp

html
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.ui/1.12.1/jquery-ui.js"></script>
    <style>
        #messageWindow {
            padding-left: 10px;
            width: 275px;
            height: 340px;
            line-height: 20px;
            resize: none;
            outline: none;
            border: 0px;
            background-color: #fafbfc;
        }
        #inputMessage {
            width: 227px;
            height: 25px;
        }
        #submit_btn {
            width: 40px;
            height: 30px;
        }
        fieldset {
            margin-top: 10px;
            margin-left: 7px;
            border: 0px;
        }
    </style>
</head>
<body>
    <fieldset onkeydown="key(event.keyCode)">
        <textarea id="messageWindow" readonly></textarea>
        <br/>
        <input id="inputMessage" type="text"/>
        <input id="submit_btn" type="submit" value="전송" onclick="send()" />
    </fieldset>
</body>
<script type="text/javascript">
    var nick = '${login_Name}';
    var toUserId = 'admin'; // 1:1 채팅 상대방의 사용자 ID
    var textarea = document.getElementById("messageWindow");
    var webSocket = new WebSocket('ws://localhost:8082/manager2/Chatting?userId=' + nick);
    var inputMessage = document.getElementById('inputMessage'); 
    
    function key(e){
        if(e==13){
            send();
        }
    }
   
    webSocket.onerror = function(event) {
        onError(event)
    };

    webSocket.onopen = function(event) {
        onOpen(event)
    };

    webSocket.onmessage = function(event) {
        onMessage(event)
    };

    function onMessage(event) {
        textarea.value += event.data + "\n";
        document.getElementById("messageWindow").scrollTop =
            document.getElementById("messageWindow").scrollHeight;
    }

    function onOpen(event) {
        $.ajax({
            url: 'Chat_Select.do',
            dataType: 'text',
            data: {
                userId: nick,
                otherUserId: toUserId
            },
            success: function(data){
                $(data).find('chat').each(function(){
                    var count = $('chat_Article', this).text();
                    textarea.value += count;
                    document.getElementById("messageWindow").scrollTop =
                        document.getElementById("messageWindow").scrollHeight;
                })
            }
        })
    }

    function onError(event) {
        alert(event.data);
    }

    function send() {
        if(inputMessage.value!=""){
            textarea.value += nick+": "+ inputMessage.value + "\n";
            webSocket.send(toUserId + ":" + inputMessage.value);
            $.ajax({
                url: 'Chat_Save.do',
                data: {
                    userId: nick,
                    otherUserId: toUserId,
                    chatArticle: inputMessage.value
                }
            });
            inputMessage.value = "";
            document.getElementById("messageWindow").scrollTop =
                document.getElementById("messageWindow").scrollHeight;
        }
    }
</script>
</html>