스프링 부트와 웹소켓을 활용한 실시간 채팅 애플리케이션 구축

스프링 부트와 웹소켓

스프링 부트는 자바 개발자들이 개발을 빠르고 쉽게 할 수 있도록 도와주는 프레임워크입니다. 웹소켓은 브라우저와 서버 사이에 실시간 양방향 통신을 가능하게 하는 기술입니다. 스프링 부트와 웹소켓을 함께 사용하면 높은 수준의 실시간성을 가진 웹 애플리케이션을 구축할 수 있습니다.

이번 글에서는 스프링 부트와 웹소켓을 활용하여 실시간 채팅 애플리케이션을 구축하는 방법에 대해 다루겠습니다.

실시간 채팅 애플리케이션

실시간 채팅 애플리케이션은 사용자들이 회의나 소규모 그룹에서 대화를 할 때 유용합니다. 이러한 애플리케이션은 메시지를 보내면 즉시 다른 사용자들에게 전달되기 때문에 실시간적인 대화가 가능합니다.

실시간 채팅 애플리케이션을 구축하기 위해서는 사용자 인터페이스, 서버 측 로직, 데이터 저장소 등 다양한 요소들이 필요합니다. 스프링 부트와 웹소켓을 이용하면 서버 측 로직을 구현하고 실시간으로 메시지를 전송할 수 있습니다.

구축을 위한 개발 환경 설정

실시간 채팅 애플리케이션을 구축하기 위해서는 몇 가지 도구와 프레임워크를 설치해야 합니다. 이번 장에서는 필요한 도구와 프레임워크, 그리고 개발 환경을 설정하는 방법에 대해 다루겠습니다.

스프링 부트 설치

스프링 부트를 사용하기 위해서는 먼저 Java Development Kit(JDK)와 스프링 부트 CLI(Command Line Interface)를 설치해야 합니다. JDK는 Java 개발 환경을 제공하는 도구이며, 스프링 부트 CLI는 스프링 부트 프로젝트를 생성하고 빌드하는 도구입니다.

스프링 부트 CLI를 설치하려면 공식 홈페이지에서 다운로드 받아야 합니다. 다운로드 후 설치 파일을 실행하고 CLI를 설치합니다.

웹소켓 프로토콜

웹소켓 프로토콜은 브라우저와 서버 사이에 실시간 양방향 통신을 가능하게 하는 프로토콜입니다. 이 프로토콜을 사용하기 위해서는 브라우저와 서버 양쪽에서 지원해야 합니다.

STOMP

STOMP(Simple Text Oriented Messaging Protocol)은 웹소켓과 함께 사용할 수 있는 메시징 프로토콜입니다. STOMP는 헤더와 바디로 이루어진 메시지를 전송할 수 있습니다. STOMP는 스프링 프레임워크에서도 지원하고 있습니다.

데이터 저장소

실시간 채팅 애플리케이션에서는 대화 기록을 저장해야 합니다. 이를 위해 데이터 저장소가 필요합니다. 대표적인 데이터 저장소로는 MySQL, MongoDB, Redis 등이 있습니다.

스프링 부트와 웹소켓을 활용한 구현 방법

이번 장에서는 스프링 부트와 웹소켓을 활용하여 실시간 채팅 애플리케이션을 구축하는 방법에 대해 다루겠습니다.

스프링 부트 프로젝트 생성

스프링 부트 프로젝트를 생성하기 위해서는 스프링 부트 CLI를 사용합니다. 다음 명령어를 사용하여 스프링 부트 프로젝트를 생성합니다.

spring init -dweb,websocket,thymeleaf,jpa --dependencies=devtools,mysql,redis chat-app

이 명령어는 chat-app이라는 이름의 스프링 부트 프로젝트를 생성하며, 웹소켓, Thymeleaf, JPA 등의 라이브러리를 사용하고, 개발 도구와 데이터베이스로는 DevTools, MySQL, Redis를 사용한다는 의미입니다.

의존성 추가

스프링 부트 프로젝트에는 이미 웹소켓과 STOMP 라이브러리가 포함되어 있습니다. 따라서 추가적인 의존성을 추가할 필요는 없습니다.

WebSocketConfig 클래스 생성

WebSocketConfig 클래스를 생성하여 웹소켓 구성을 정의합니다. 이 클래스는 @Configuration 어노테이션을 사용하여 스프링 컨텍스트에 등록합니다.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat").withSockJS();
    }

}

위 코드는 configureMessageBroker() 메소드에서 /topic을 구독하고 있는 모든 클라이언트에게 메시지를 전송할 수 있도록 메시지 브로커를 등록하고, /app으로 시작하는 메시지를 컨트롤러로 라우팅할 수 있도록 설정합니다.

registerStompEndpoints() 메소드는 클라이언트가 웹소켓 서버에 접속할 수 있는 엔드포인트를 등록합니다. withSockJS() 메소드는 SockJS를 사용하도록 설정합니다.

WebSocketController 클래스 생성

WebSocketController 클래스를 생성하여 클라이언트로부터 메시지를 수신하고, 다른 클라이언트에게 메시지를 전송하는 역할을 합니다.

@Controller
public class WebSocketController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @MessageMapping("/chat")
    public void sendMessage(ChatMessage chatMessage) {
        messagingTemplate.convertAndSend("/topic/" + chatMessage.getRoomId(), chatMessage);
    }

}

위 코드는 @MessageMapping 어노테이션을 사용하여 /chat으로 시작하는 메시지를 처리합니다. messagingTemplate 객체를 사용하여 /topic/{roomId}로 메시지를 전송합니다. {roomId}는 채팅방의 고유한 식별자입니다.

ChatMessage 클래스 생성

ChatMessage 클래스를 생성하여 채팅 메시지를 담고 있습니다.

public class ChatMessage {

    private String content;
    private String sender;
    private String roomId;

    // getters and setters

}

위 코드는 채팅 메시지의 내용, 발신자, 채팅방의 고유한 식별자를 저장합니다.

채팅방 생성

채팅방을 생성하기 위해서는 Redis를 사용합니다. Redis는 In-Memory 데이터 저장소로서, 채팅방 정보를 저장하기에 적합합니다.

@Component
public class ChatRoomRepository {

    private final RedisTemplate redisTemplate;
    private static final String KEY = "CHAT_ROOM";

    public ChatRoomRepository(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public List findAllRoom() {
        return redisTemplate.opsForHash().values(KEY)
                .stream()
                .map(o -> objectMapper.convertValue(o, ChatRoom.class))
                .collect(Collectors.toList());
    }

    public ChatRoom findRoomById(String id) {
        return (ChatRoom) redisTemplate.opsForHash().get(KEY, id);
    }

    public void enterChatRoom(String roomId, ChatRoomUser chatRoomUser) {
        ChatRoom chatRoom = findRoomById(roomId);
        chatRoom.getUserList().add(chatRoomUser);
        redisTemplate.opsForHash().put(KEY, chatRoom.getId(), chatRoom);
    }

    public ChatRoom createChatRoom(String name) {
        ChatRoom chatRoom = ChatRoom.create(name);
        redisTemplate.opsForHash().put(KEY, chatRoom.getId(), chatRoom);
        return chatRoom;
    }

}

위 코드는 Redis를 사용하여 채팅방을 생성하고, 채팅방에 접속한 사용자를 추가합니다.

채팅방 생성 API

채팅방 생성을 위한 API를 구현합니다.

@RestController
@RequestMapping("/api/chat")
public class ChatRoomApiController {

    @Autowired
    private ChatRoomRepository chatRoomRepository;

    @PostMapping
    public ChatRoom createRoom(@RequestParam String name) {
        return chatRoomRepository.createChatRoom(name);
    }

    @GetMapping
    public List findAllRoom() {
        return chatRoomRepository.findAllRoom();
    }

}

위 코드는 createRoom() 메소드를 사용하여 채팅방을 생성하고, findAllRoom() 메소드를 사용하여 모든 채팅방을 조회합니다.

결론

이번 글에서는 스프링 부트와 웹소켓을 활용하여 실시간 채팅 애플리케이션을 구축하는 방법에 대해 다뤘습니다. 스프링 부트와 웹소켓을 사용하면 높은 수준의 실시간성을 가진 웹 애플리케이션을 쉽게 구축할 수 있습니다. 이를 바탕으로 사용자들은 빠르고 쉽게 대화를 나눌 수 있습니다.