Spring

부트캠프89일차 (chatting)

동곤일상 2025. 6. 18. 16:50
반응형

 

1) 채팅시스템 (WebSocket이용)

 

 

webapp/chat/chat.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="port" value="${pageContext.request.localPort}"/>
<c:set var="server" value="${pageContext.request.serverName}"/>
<c:set var="path" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<script type="text/javascript">
$(function(){
    //서버에서 수신할 수 있는 준비 필요
    let ws = new WebSocket("ws://${server}:${port}${path}/chatting");
    let username = "User" + Math.floor(Math.random() * 1000);
    let sessionId = null;

    //서버와 연결 성공된 경우
    ws.onopen = function() {
        $("#chatStatus").text("메시지 💨");
        console.log("WebSocket opened for user:", username);
        // 이벤트 중복 방지
        $("input[name=chatInput]").off('keydown').on("keydown", function(evt) {
            if (evt.keyCode == 13) {
                //enter키가 눌리면 sendMessage호출
                sendMessage();
            }
        });
        //class="send-btn"을 클릭해도   sendMessage호출
        $(".send-btn").off('click').on("click", sendMessage);
    };

    function sendMessage() {
        let msg = $("input[name=chatInput]").val().trim();
        if (msg !== "") {
            let payload = JSON.stringify({ username: username, message: msg });
            ws.send(payload);
            console.log("Sent:", payload);
            $("input[name=chatInput]").val("");
        }
    }

  //onmessage: 서버로부터 메시지를 받으면 실행
    ws.onmessage = function(event) {
        let data = JSON.parse(event.data);
        console.log("Received:", data);
        let $msgDiv = $('<div>').addClass('message').text(data.message);
        if (data.username === username) {
            $msgDiv.addClass('sent');
        } else {
            $msgDiv.addClass('received');
        }
        $(".chat-messages").append($msgDiv);
        $(".chat-messages").scrollTop($(".chat-messages")[0].scrollHeight);
    };

  //onclose: 연결 종료 시 상태를 "connection close"로 표시.
    ws.onclose = function(event) {
        $("#chatStatus").text("info: connection closed");
        console.log("WebSocket closed:", event);
    };

    ws.onerror = function(event) {
        $("#chatStatus").text("error: connection failed");
        console.error("WebSocket error:", event);
    };
});
</script>
</head>
<body>
<div class="chat-container">
    <div id="chatStatus"></div>
    <div class="chat-messages"></div>
    <div class="chat-input-container">
        <input type="text" name="chatInput" class="w3-input" placeholder="메시지를 입력하세요...">
        <button class="send-btn">➤</button>
    </div>
</div>
<textarea name="chatMsg" rows="15" cols="40" class="w3-input" style="display:none;"></textarea>
</body>
</html>

 

 

kr.gdu/webSocekt / EchoHandler.java

package kr.gdu.webSocket;

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

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
public class EchoHandler extends TextWebSocketHandler implements InitializingBean {

	
	private Set<WebSocketSession> clients = new HashSet<>();
	
	//클라이언트로부터 요청이들어오고 연결완료 후
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		//session : 웹소켓 접속객체의 고유한ID값
		super.afterConnectionEstablished(session);
		System.out.println("클라이언트 접속 : "+session.getId());
		clients.add(session);
	}


	//메시지가 수신된 경우
	@Override
	public void handleMessage
	(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		/* loadMessage : 클라이언트가 전송한 메시지 */
		String loadMessage = (String)message.getPayload();
		System.out.println(session.getId()+" > 클라이언트 메시지 : "+loadMessage);
		//클라이언트의 session을 clients(map)에 추가
		clients.add(session);
		for (WebSocketSession s : clients) {
			// s : 접속 된 클라이언트 객체
			s.sendMessage(new TextMessage(loadMessage));
		}
	}


	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) 
			throws Exception {
		super.handleTransportError(session, exception);
		System.out.println("오류발생 : "+exception.getMessage());
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		super.afterConnectionClosed(session, status);
		System.out.println("클라이언트 접속 해제 : "+status.getReason());
		clients.remove(session);
	}


	@Override
	public void afterPropertiesSet() throws Exception {	}

	
}

 

 

config/WebSocketConfig.java

package kr.gdu.config;

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;

import kr.gdu.webSocket.EchoHandler;

@Configuration
@EnableWebSocket //웹소켓 처리
public class WebSocketConfig implements WebSocketConfigurer{

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		//chatting : 웹소켓에서 호출되는URL정보
		// ws://localhost:8080/chatting
		registry.addHandler(new EchoHandler(),"chatting")
		.setAllowedOrigins("*");	
	}
}

 

 

ChatController (그냥 주소매핑말고는 하는게없음)

package kr.gdu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("chat")
public class ChatController {
	
	@RequestMapping("*")
	public String chat() {
		return null;
	}
}

 

'Spring' 카테고리의 다른 글

parameter값 or logic대신 Dto객체 사용  (0) 2025.06.22
Exception과 AOP의 동작원리  (2) 2025.06.21
부트캠프88일차(ajax 2)  (0) 2025.06.17
부트캠프87일차 (ajax)  (2) 2025.06.16
부트캠프86일차 (interceptor)  (1) 2025.06.13