프로그래밍 언어/JAVA, SPRING

[SPRING BOOT] WebSocket과 Redis를 활용한 실시간 채팅 시스템 구축하기

doomole 2024. 11. 26. 15:31
728x90
 

개요

Spring Boot와 WebSocket을 활용하면 효율적인 실시간 통신 기능을 구현할 수 있다.

이번 글에서는 Redis를 추가로 사용해 메시지 저장과 자동 삭제 기능을 갖춘 채팅 시스템을 구축하는 방법을 작성했다.

 

 



구성요소

  1. WebSocket: 클라이언트와 서버 간의 양방향 통신을 가능하게 하는 프로토콜.
  2. Redis: 메시지 저장소로 활용하며 TTL(Time to Live)을 사용해 일정 시간이 지나면 메시지를 삭제.
  3. Spring Boot: WebSocket 서버를 구현하는 데 사용.

 

 



WebSocket 설정

Spring Boot에서 WebSocket 서버를 구현하려면 @EnableWebSocket과 WebSocketHandler를 사용한다.

 

WebSocketConfig.java

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 {

    private final ChatHandler chatHandler;

    public WebSocketConfig(ChatHandler chatHandler) {
        this.chatHandler = chatHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatHandler, "/ws/chat").setAllowedOrigins("*");
    }
}

 

ChatHandler.java

메시지를 처리하는 핵심 클래스

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

public class ChatHandler extends TextWebSocketHandler {

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("Received: " + payload);
        session.sendMessage(new TextMessage("Echo: " + payload));
    }
}

 

 



Redis 설정

Redis는 메시지를 저장하고 TTL을 활용해 자동 삭제 기능을 제공한다.

 

RedisConfig.java

Redis 설정파일

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

 

 

ChatMessageService.java

Redis에 메시지를 저장하면서 TTL을 설정한다.

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class ChatMessageService {

    private final RedisTemplate<String, String> redisTemplate;

    public ChatMessageService(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void saveMessage(String roomId, String message) {
        String key = "chat:" + roomId;
        redisTemplate.opsForList().leftPush(key, message);
        redisTemplate.expire(key, 1, TimeUnit.HOURS); // 1시간 후 자동 삭제
    }

    public List<String> getMessages(String roomId) {
        String key = "chat:" + roomId;
        return redisTemplate.opsForList().range(key, 0, -1);
    }
}

 

 



WebSocket과 Redis 연결

WebSocket에서 받은 메시지를 Redis에 저장한다.

 

ChatHandler.java

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

public class ChatHandler extends TextWebSocketHandler {

    private final ChatMessageService chatMessageService;

    public ChatHandler(ChatMessageService chatMessageService) {
        this.chatMessageService = chatMessageService;
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("Received: " + payload);

        // 메시지 저장
        String roomId = "room1"; // 예제에서는 고정된 채팅방 ID 사용
        chatMessageService.saveMessage(roomId, payload);

        // 클라이언트에 응답
        session.sendMessage(new TextMessage("Saved: " + payload));
    }
}

 

 



Frontend WebSocket 연결

클라이언트에서 WebSocket을 통해 서버와 연결한다.

const socket = new WebSocket("ws://localhost:8080/ws/chat");

socket.onopen = () => {
    console.log("WebSocket connection established.");
    socket.send("Hello, server!");
};

socket.onmessage = (event) => {
    console.log("Message from server:", event.data);
};

 

 

문의사항이나 피드백은 댓글로 남겨주세요.