단체 채팅 기능 구현해보기 (기초 작업)

2024. 5. 23. 21:21컴퓨터 전공 공부/안드로이드 앱 개발

반응형

개념 및 지식

  1. WebSocket:
    • WebSocket은 HTTP와는 다른 전이중 통신 채널을 제공하는 프로토콜입니다. 서버와 클라이언트 간의 실시간 통신이 필요할 때 주로 사용됩니다.
    • WebSocket을 사용하면 클라이언트와 서버 간의 지속적인 연결을 유지하면서 양방향 데이터 전송이 가능합니다.
  2. STOMP (Simple Text Oriented Messaging Protocol):
    • STOMP는 WebSocket 위에서 동작하는 간단한 텍스트 기반 프로토콜로, 메시징 시스템을 쉽게 구현할 수 있게 해줍니다.
    • 주로 채팅 시스템에서 많이 사용됩니다.
  3. Spring WebSocket:
    • Spring 프레임워크는 WebSocket과 STOMP를 쉽게 설정하고 사용할 수 있는 기능을 제공합니다.
    • Spring WebSocket을 사용하면 WebSocket 엔드포인트를 쉽게 구성하고, STOMP 메시징을 통해 클라이언트와 서버 간의 메시지를 처리할 수 있습니다.
    • WebSocket 엔드포인트란? WebSocket 엔드포인트는 클라이언트가 WebSocket을 통해 서버에 연결할 수 있는 URL 또는 경로를 말합니다. 이는 WebSocket 통신을 시작하기 위한 진입점 역할을 합니다. 클라이언트는 이 엔드포인트를 통해 서버와 WebSocket 연결을 설정하고, 이후 양방향 통신을 수행할 수 있습니다.
  4. Spring Boot:
    • Spring Boot는 스프링 프레임워크를 기반으로 하는 애플리케이션을 신속하게 개발할 수 있게 해주는 도구입니다.
    • 최소한의 설정으로 신속하게 개발할 수 있으며, WebSocket과 같은 기술을 쉽게 통합할 수 있습니다.
  5. JPA (Java Persistence API):
    • JPA는 자바 객체와 데이터베이스 간의 매핑을 관리하는 표준입니다.
    • Spring Data JPA를 사용하면 데이터베이스와 상호작용하는 코드를 쉽게 작성할 수 있습니다.
  6. Lombok:
    • Lombok은 자바 코드에서 반복되는 보일러플레이트 코드를 줄이기 위해 사용되는 라이브러리입니다.
    • 애노테이션을 통해 getter, setter, 생성자 등을 자동으로 생성할 수 있습니다.

 

각 클래스별 설명 및 개념 활용

1. WebSocketConfig.java

개념: WebSocket 및 STOMP 설정

  • WebSocketConfig 클래스는 WebSocket을 설정하는 역할을 합니다.
  • @EnableWebSocketMessageBroker 애노테이션을 사용하여 STOMP 메시지 브로커를 활성화합니다.
  • 메시지 브로커 설정 및 엔드포인트 등록을 통해 클라이언트가 WebSocket 연결을 할 수 있게 합니다.

 

package hello.community.global.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@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("/ws").setAllowedOrigins("*").withSockJS();
    }
}

 

2. ChatMessage.java

개념: 메시지 모델

  • ChatMessage 클래스는 채팅 메시지의 데이터 구조를 정의합니다.
  • 메시지 타입을 열거형으로 정의하여 다양한 유형의 메시지를 처리할 수 있습니다.
package hello.community.domain.chat;

public class ChatMessage {
    private MessageType type;
    private String content;
    private String sender;

    public enum MessageType {
        CHAT,
        JOIN,
        LEAVE
    }

    // Getters and Setters
    public MessageType getType() {
        return type;
    }

    public void setType(MessageType type) {
        this.type = type;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getSender() {
        return sender;
    }

    public void setSender(String sender) {
        this.sender = sender;
    }
}

 

3. ChatController.java

개념: WebSocket 메시지 처리

  • ChatController 클래스는 클라이언트로부터 메시지를 받고, 이를 브로커를 통해 전달합니다.
  • @MessageMapping 애노테이션을 사용하여 특정 경로로 들어오는 메시지를 처리합니다.
package hello.community.domain.chat;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Controller;

@Controller
public class ChatController {

    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {
        return chatMessage;
    }

    @MessageMapping("/chat.addUser")
    @SendTo("/topic/public")
    public ChatMessage addUser(@Payload ChatMessage chatMessage, SimpMessageHeaderAccessor headerAccessor) {
        headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());
        return chatMessage;
    }
}

 

4. ChatRoom.java

개념: 채팅방 모델

  • ChatRoom 클래스는 채팅방의 데이터를 정의합니다.
  • JPA를 사용하여 데이터베이스에 매핑합니다.
package hello.community.domain.chat;

import lombok.Getter;
import lombok.Setter;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Getter
@Setter
@Entity
public class ChatRoom {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
}

 

5. ChatRoomRepository.java

개념: 데이터베이스 연동

  • ChatRoomRepository는 JPA를 사용하여 ChatRoom 엔티티를 데이터베이스와 상호작용하도록 합니다.
package hello.community.domain.chat;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ChatRoomRepository extends JpaRepository<ChatRoom, Long> {
}

 

6. ChatService.java

개념: 비즈니스 로직

  • ChatService 클래스는 채팅방과 관련된 비즈니스 로직을 처리합니다.
  • 채팅방 생성, 조회 등의 기능을 제공합니다.
package hello.community.domain.chat;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
@RequiredArgsConstructor
public class ChatService {
    private final ChatRoomRepository chatRoomRepository;

    public List<ChatRoom> findAllRooms() {
        return chatRoomRepository.findAll();
    }

    public ChatRoom findRoomById(Long id) {
        return chatRoomRepository.findById(id).orElse(null);
    }

    public ChatRoom createRoom(String name) {
        ChatRoom chatRoom = new ChatRoom();
        chatRoom.setName(name);
        return chatRoomRepository.save(chatRoom);
    }
}

 

7. WebSocketEventListener.java

개념: WebSocket 이벤트 처리

  • WebSocketEventListener 클래스는 WebSocket 연결 및 연결 해제 이벤트를 처리합니다.
  • 새로운 연결이 생성되거나 연결이 끊어질 때 로그를 남깁니다.
package hello.community.domain.chat;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;

@Component
@Slf4j
public class WebSocketEventListener {

    @EventListener
    public void handleWebSocketConnectListener(SessionConnectedEvent event) {
        log.info("Received a new web socket connection");
    }

    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());

        String username = (String) headerAccessor.getSessionAttributes().get("username");
        if (username != null) {
            log.info("User Disconnected : " + username);
        }
    }
}
반응형