WebSocket 채팅 (2)

보트·2023년 9월 21일
0

채팅

목록 보기
2/7

기능

  • 클라이언트 서버에 접속 → 개별적으로 WebSocket session 가지게 됨
  • 채팅방에 클라이언트의 session 정보 저장
  • 서버에 전달된 메세지를 채팅방의 sessionList로 발송

Chat

  • ChatMessage.java
    • 클라이언트 메세지 DTO

      @Getter
      @Setter
      public class ChatMessage {
      
          // 메세지 타입 : 입장, 채팅
          public enum MessageType {
              ENTER, TALK
          }
      
          private MessageType type;
          private String roomId;
          private String sender;
          private String message;
      }
  • ChatRoom.java
    • 채팅방
      - 채팅방 정보
      - 채팅방 내 메세지 전송 메서드

      @Getter
      public class ChatRoom {
          private String roomId;
          private String name;
      
          // 입장한 클라이언트들의 session 정보
          private Set<WebSocketSession> sessions = new HashSet<>();
      
          /* 생성자 */
          @Builder
          public ChatRoom(String roomId, String name) {
              this.roomId = roomId;
              this.name = name;
          }
      
          public void handleActions(WebSocketSession session, ChatMessage chatMessage, ChatService chatService) {
              // 채팅방에 입장했을 때
              if (chatMessage.getType().equals(ChatMessage.MessageType.ENTER)) {
                  sessions.add(session);
                  chatMessage.setMessage(chatMessage.getSender() + "님이 입장했습니다.");
              }
      
              sendMessage(chatMessage, chatService);
          }
      
          public <T> void sendMessage(T message, ChatService chatService) {
              // 채팅방의 모든 클라이언트에게 메세지 전송
              sessions.parallelStream().forEach(session -> chatService.sendMessage(session, message));
          }
      }

ChatService

  • ChatController.java
    • 채팅방 생성 및 전체 채팅방 조회

      @RequiredArgsConstructor
      @RestController
      @RequestMapping("/chat")
      @Slf4j(topic = "채팅방 생성/ 조회")
      public class ChatController {
      
          private final ChatService chatService;
      
          @PostMapping
          public ChatRoom createRoom(@RequestParam String name) {
              return chatService.createRoom(name);
          }
      
          @GetMapping
          public List<ChatRoom> findAllRoom() {
              return chatService.findAllRoom();
          }
      
      }
  • ChatService.java
    • 채팅 서비스
      - 컨트롤러에서 사용할 메서드
      - 채팅 handler에서 사용할 메서드

      @Slf4j(topic = "ChatService")
      @Service
      @RequiredArgsConstructor
      public class ChatService {
      
          private final ObjectMapper objectMapper;
      
          // 생성된 모든 채팅방 정보 roomId - ChatRoom
          private Map<String, ChatRoom> chatRooms;
      
          @PostConstruct
          private void init() {
              chatRooms = new LinkedHashMap<>();
          }
      
          /**
           * 모든 채팅방 조회
           *
           * @return
           */
          public List<ChatRoom> findAllRoom() {
              return new ArrayList<>(chatRooms.values());
          }
      
          /**
           * 채팅방 조회
           *
           * @param roomId 조회할 채팅방 id
           * @return 채팅방
           */
          public ChatRoom findRoomById(String roomId) {
              return chatRooms.get(roomId);
          }
      
          /**
           * 채팅방 생성
           *
           * @param name 생성할 채팅방 이름
           * @return 채팅방
           */
          public ChatRoom createRoom(String name) {
              String randomId = UUID.randomUUID().toString();
              ChatRoom chatRoom = ChatRoom.builder()
                      .roomId(randomId)
                      .name(name)
                      .build();
      
              chatRooms.put(randomId, chatRoom);
              return chatRoom;
          }
      
          /**
           * 메세지 발송
           *
           * @param session 목적지 session
           * @param message 발송할 message
           * @param <T>     type
           */
          public <T> void sendMessage(WebSocketSession session, T message) {
              try {
                  session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
              } catch (IOException e) {
                  log.error(e.getMessage(), e);
              }
          }
      }

Handler

  • WebSocketChatHandler.java
    • handler 수정
      - 기본 입장 메세지 삭제 후 ChatMessage, ChatRoom 사용하도록 수정

      ```java
      TextMessage textMessage = new TextMessage("채팅 입장");
      session.sendMessage(textMessage);
      ```
      @Slf4j(topic = "WebSocketChatHandler")
      @Component
      @RequiredArgsConstructor
      public class WebSocketChatHandler extends TextWebSocketHandler {
      
          private final ObjectMapper objectMapper;
          private final ChatService chatService;
      
          @Override
          protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
              String payload = message.getPayload();
              log.info("payload : {}", payload);
      
              // 클라이언트로부터 채팅 메세지를 전달받아 ChatMessage 객체로 변환
              ChatMessage chatMessage = objectMapper.readValue(payload, ChatMessage.class);
              // 메세지 속의 roomId로 채팅방 조회
              ChatRoom room = chatService.findRoomById(chatMessage.getRoomId());
              // 해당 채팅방에 있는 클라이언트들에게 메세지 발송
              room.handleActions(session, chatMessage, chatService);
          }
      }

테스트

채팅방

  • 채팅방 생성

  • 채팅방 조회

채팅

  • simple websocket client 두 개를 열어 채팅

(참고 : https://www.daddyprogrammer.org/post/4077/spring-websocket-chatting/)

profile
일주일에 한 번

0개의 댓글