Blog

[Spring][iLanD] [Web Socket] 실시간 채팅 기능 구현

Category
Author
Tags
PinOnMain
1 more property
웹 소켓을 활용한 채팅 기능 구현 과정
웹소켓을 활용한 채팅 기능을 구현하고자한다.
의존성 추가build.gradle 에 의존성 추가
// websocket implementation 'org.springframework.boot:spring-boot-starter-websocket'
Java
복사
Configuration 추가
@Configuration // 스프링 프레임 워크 설정 클래스로 등록 @EnableWebSocketMessageBroker // 웹소켓 서버 활성화하는데 사용한다. public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { // => 웹소켓 설정을 사용자 정의한다. @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/chatMessage"); //chatMessage 로 시작하는 목적지 메시지 관리 config.setApplicationDestinationPrefixes("/app"); //목적지가 /app 시작 메시지 라우팅 } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket"); // URL을 웹소켓 엔드포인트로 등록한다. 클라이언트는 이 URL을 통해 웹소켓 연결을 초기화 } }
Java
복사
뷰 컨트롤러 추가
@Controller public class ChatViewController { // 채팅 화면 @GetMapping("/chatting") public String chatView(){ return "/contents/chatting"; } }
Java
복사
chatting.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="shortcut icon" href="#"> <link rel="stylesheet" type="text/css" href="/assets/23_HP010_iLanD-main/nav.css"> <link rel="stylesheet" type="text/css" href="/assets/23_HP010_iLanD-main/movies&tv.css"> <link href="/css/style.css" rel="stylesheet" /> <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> <title> Chatting Room </title> </head> <body> <!-- Navigation --> <nav class="navbar navbar-expand-xxl navbar-dark bg-white"> <div class="container px-9"> <a href="#"><img width="32" height="32" src="/assets/23_HP010_iLanD-main/icon/iLanD_logo.png" onclick="openPage('/')"></a> <h5> Chatting Room </h5> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav ms-auto mb-2 mb-lg-0"> <li class="nav-item"><a class="nav-link" aria-current="page" href="/">Home</a></li> <li class="nav-item"><a class="nav-link" href="/movies&tv">Movies&TV</a></li> <li class="nav-item"><a class="nav-link" href="/game">Game</a></li> <li class="nav-item"><a class="nav-link" href="/chatting">Chatting</a></li> <li class="nav-item"><a class="nav-link" href="/announcement">Announcement</a></li> <li class="nav-item"><a class="nav-link" href="/aboutus_page">About Us</a></li> <li class="nav-item"><a class="nav-link" href="/service_guide">Service Guide</a></li> <li class="nav-item"><a class="nav-link" href="/login">Login(Staffs&Admin)</a></li> </ul> </div> </div> </nav> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="/assets/23_HP010_iLanD-main/nav.js"></script> <script src="/assets/23_HP010_iLanD-main/chatting.js"></script> <div id="main-content" class="container"> <h2 class="text-center">채팅 페이지</h2> <div class="row"> <div class="col-md-6"> <form class="form-inline"> <div class="form-group"> <label for="chatConnect">채팅 연결:</label> <button id="chatConnect" class="btn btn-primary" type="submit">연결</button> <button id="chatDisconnect" class="btn btn-danger" type="submit" disabled="disabled">연결 끊기</button> </div> </form> </div> <div class="col-md-6"> <form class="form-inline"> <div class="form-group"> <label for="name">채팅 메시지:</label> <input type="text" id="name" class="form-control" placeholder="메시지를 입력하세요..."> <button id="messageSend" class="btn btn-success" type="submit">전송</button> </div> </form> </div> </div> <div class="row mt-4"> <div class="col-md-12"> <table id="conversation" class="table table-bordered"> <thead> <tr> <th class="text-center">채팅 시작</th> </tr> </thead> <tbody id="message"> </tbody> </table> </div> </div> </div> </body> </html>
Java
복사
chatting.js
const client = new StompJs.Client({ brokerURL: 'ws://localhost:8080/websocket' }); client.onConnect = (frame) => { setConnected(true); console.log('Connected: ' + frame); client.subscribe('/chatMessage', (chatting) => { showChatting(JSON.parse(chatting.body).content); }); }; client.onWebSocketError = (error) => { console.error('Error with websocket', error); }; client.onStompError = (frame) => { console.error('Broker reported error: ' + frame.headers['message']); console.error('Additional details: ' + frame.body); }; function setConnected(connected) { $("#chatConnect").prop("disabled", connected); $("#chatDisconnect").prop("disabled", !connected); if (connected) { $("#conversation").show(); } else { $("#conversation").hide(); } $("#message").html(""); } function connect() { client.activate(); } function disconnect() { client.deactivate(); setConnected(false); console.log("Disconnected"); } function sendMessage() { client.publish({ destination: "/app/chat", body: JSON.stringify({'chattingMessage': $("#chattingMessage").val()}) }); } function showChatting(message) { $("#message").append("<tr><td>" + message + "</td></tr>"); } $(function () { $("form").on('submit', (e) => e.preventDefault()); $("#chatConnect").click(() => connect()); $("#chatDisconnect").click(() => disconnect()); $("#messageSend").click(() => sendMessage()); });
Java
복사
Controllers
우선 채팅 페이지를 반환하는 뷰컨트롤러
@Controller public class ChatViewController { @GetMapping("/chatting") public String chatView(){ return "contents/chatting"; } }
Java
복사
실제 비지니스로직이 시작되는 컨트롤러
@Controller public class ChatController { @MessageMapping("/chat") @SendTo("/chatMessage") public ChattingContent chat(ChatMessageDto message) throws Exception { return new ChattingContent( HtmlUtils.htmlEscape(message.getChattingMessage()) ); } }
Java
복사
채팅 객체와 반환 Dto
ChattingContent.java
public class ChattingContent { private String content; public ChattingContent() { } public ChattingContent(String content) { this.content = content; } public String getContent() { return content; } }
Java
복사
ChatMessageDto.java
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @Builder public class ChatMessageDto { private String chattingMessage; }
Java
복사
기본 상태 구현 테스트
픈으로 접속했을때의 트러블 슈팅
채팅 웹소켓 서버에 접속하지 못하는 문제가 발생했다. 이는 웹 소켓의 URL자체가 localhost:8080으로 되있던 점에서의 문제였다.
모바일은 데스크탑으로 IP주소를 통해 접근한다. 따라서 다음과같은 오류가 나타날수있다. 모바일 브라우저 개발자도구를 맥을 통해서 확인해보았다.
내부 네트워크 서버의 IP주소를 통해서 접속하기 때문에 추후 환경구축시 서버IP주소를 작성해야한다.
const client = new StompJs.Client({ brokerURL: 'ws://192.168.0.2:8080/websocket' // 브로커주소를 서버 IP로 수정해야한다. // brokerURL: 'ws://localhost:8080/websocket' });
Java
복사
이처럼 JS내 상단 소스코드 중 ws을 지정하는 부분에서 서버 PC의 IP를 작성하면서 해결되었다.