[Road To MQ] WebSocket으로 실시간 통신

CodeKong의 기술 블로그·2024년 1월 21일
3

Road To MQ

목록 보기
1/6
post-thumbnail

안녕하세요 오늘은 Road To MQ 첫 단계인 WebSocket에 대해 알아보고자 합니다.

대부분 WebSocket과 STOMP를 같이쓰지만 오늘은 WebSocket 자체만을 사용하여 통신을 해보도록 하겠습니다!

📌 배경

기존의 Http 환경에서는 클라이언트->서버로의 단방향 통신만이 가능합니다.

하지만 알람, 통신등에서는 양방향 통신등이 필요한데요 그것을 가능하게 해주는 것중 하나가 WebSocket입니다.

오늘은 간단하게 연결 & 간단한 통신등을 해보도록 하겠습니다!

📌 기본 설정

🛠️ 의존성 추가

//WebSocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'

먼저 WebSocket을 위한 의존성을 추가해줍니다.


❗❗ Config , Handler 설정이 순서의 초기가 되어야하나 작성하기 편하게 역순으로 작성하도록 하겠습니다. ❗❗

ChatRoom

먼저 채팅을 하려면 채팅방이 필요하겠죠

@Getter
public class ChatRoom {
    private String roomId;
    private String name;
    private Set<WebSocketSession> sessions = new HashSet<>();

    @Builder
    public ChatRoom(String roomId, String name) {
        this.roomId = roomId;
        this.name = name;
    }

}

채팅방은

  • 채팅방 id
  • 채팅방 이름
  • 들어와있는 세션으로 구분합니다.
    (세션은 클라이언트가 WebSocket으로 연결시 얻어올 수 있습니다.)

ChatMessage

@Getter
public class ChatMessage {

    public enum MessageType {
        ENTER, TALK
    }

    private MessageType type;
    private String roomId;
    private String sender;
    private String message;
}

채팅 메세지는

  • MessageType
  • 채팅룸 id
  • 발신자
  • 메세지 내용
    으로 구성되어 있습니다.

메세지 id 같은 속성은 현재 단계에서 과감히 빼도록 합니다

ChatService

@Service
@RequiredArgsConstructor
@Slf4j
public class ChatService {

    private final ObjectMapper objectMapper;
    //repository 대신 사용
    private Map<String, ChatRoom> chatRooms;

    //서버가 실행되면 실행
    @PostConstruct
    public void init() {
        chatRooms = new LinkedHashMap<>();
    }

    //채팅방 생성
    public ChatRoom createChatRoom(String name) {
        String randomId = UUID.randomUUID().toString();

        ChatRoom chatRoom = ChatRoom.builder()
                .roomId(randomId)
                .name(name)
                .build();

        //chatRooms(목록)에 채팅방 추가
        chatRooms.put(chatRoom.getRoomId(), chatRoom);
        return chatRoom;
    }

    //roomId로 채팅방 찾기
    public ChatRoom findChatRoom(String roomId) {
        return chatRooms.get(roomId);
    }

    //ChatRoom에 있는 모든 session에 메시지 전송
    public void sendToAllMessage(ChatRoom chatRoom, String message) {
        chatRoom.getSessions().forEach(session -> {
            sendMessage(session, message);
        });
    }

    //session에 메시지 전송
    public <T> void sendMessage(WebSocketSession session, T message) {
        try {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
        } catch (IOException e) {
            throw new IllegalArgumentException("메시지 전송 실패");
        }
    }

    //MessageType에 따라 로직 실행
    public void handleMessage(ChatRoom chatRoom, ChatMessage message, WebSocketSession session) {

        //메시지 타입이 ENTER면
        if (message.getType().equals(ChatMessage.MessageType.ENTER)) {

            //채팅방에 session추가
            chatRoom.getSessions().add(session);

            //메시지 보낸 사람 이름 가져오기
            String sender = message.getSender();
            sendToAllMessage(chatRoom, sender + "님이 입장하셨습니다.");
        }
        else {
            
            //메시지 보낸 사람 이름 가져오기
            String sender = message.getSender();
            sendToAllMessage(chatRoom, sender + " : " + message.getMessage());
        }
    }

}

Controller

마지막으로 채팅방 생성을 위한 Contoller 작성을 해보겠습니다

@RestController
@RequiredArgsConstructor
@RequestMapping("chat-rooms")
public class ChatController {

    private final ChatService chatService;

    //RoomName으로 채팅방 생성
    @PostMapping
    public ChatRoom createRoom(@RequestParam("RoomName") String RoomName) {
        return chatService.createChatRoom(RoomName);
    }

}

이제부터는 WebSocket에 관한 Config 설정을 하겠습니다❗

Handler 설정

@Component
@RequiredArgsConstructor
@Slf4j
public class WebSocketHandler extends TextWebSocketHandler {

    private final ChatService chatService;
    private final ObjectMapper objectMapper;
    private String roomId;
    private ChatRoom chatRoom;

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        String payload = message.getPayload();

        //메시지를 ChatMessage 객체로 변환
        ChatMessage chatMessage = objectMapper.readValue(payload, ChatMessage.class);

        //UUID 가져오기
        roomId = chatMessage.getRoomId();

        //CharRoom 찾기
        chatRoom = chatService.findChatRoom(roomId);

        //로직 실행
        chatService.handleMessage(chatRoom, chatMessage,session);
    }

}

다음은 WebSocketConfigurer을 구현하여 Config 설정을 하였습니다.

Config 설정

@EnableWebSocket
@Configuration
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {

    private final WebSocketHandler webSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

        registry.addHandler(webSocketHandler, "/ws/chat")
                .setAllowedOrigins("*");

    }

}

📌 테스트

채팅방 생성

입장

대화

로그가 잘 찍히는 것을 볼 수 있습니다!🔫🔫

0개의 댓글