Java Spring Boot | Socket의 이해 및 실습

Yunny.Log ·2022년 5월 12일
0

Spring Boot

목록 보기
48/80
post-thumbnail
  • 일반적으로 서버는 클라이언트의 요청에만 응답을 처리할 수 있음
  • 그러나 소켓을 이용한다면 서버가 작업을 마친 후 자체적으로 응답 제공 가능

WebSocketConfig.java

@RequiredArgsConstructor
@Configuration
@EnableWebSocket
public class WebSockConfig implements WebSocketConfigurer {
    private final WebSocketHandler webSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketHandler, "/ws/design-file").setAllowedOrigins("*");
    }
}

WebSocketHandler.java

/**
 * 웹소켓 클라이언트로부터 채팅 메시지를 전달받아 채팅 메시지 객체로 변환
 * 전달받은 메시지에 담긴 채팅방 Id로 발송 대상 채팅방 정보를 조회함
 * 해당 채팅방에 입장해있는 모든 클라이언트들(Websocket session)에게 타입에 따른 메시지 발송
 */
    @Slf4j
    @RequiredArgsConstructor
    @Component
    public class WebSockChatHandler 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 = objectMapper.readValue(payload, ChatMessage.class);
            ChatRoomDto room = chatService.findRoomById(chatMessage.getRoomId());
            room.handleTempActions(session, chatMessage, chatService);

        }

    }

String payload = message.getPayload();
log.info("payload {}", payload);
=> 클라이언트가 보낸 요청을 로그에 찍히게 해준다.

SocketService.java

@Slf4j
@RequiredArgsConstructor
@Service
public class ChatService {

    private final ObjectMapper objectMapper;
    private Map<String, ChatRoomDto> chatRooms;

    @PostConstruct
    private void init() {
        chatRooms = new LinkedHashMap<>();
    }

    public List<ChatRoomDto> findAllRoom() {
        return new ArrayList<>(chatRooms.values());
    }

    public ChatRoomDto findRoomById(String roomId) {
        return chatRooms.get(roomId);
    }

    public ChatRoomDto createRoom() {
        String randomId = UUID.randomUUID().toString();
        ChatRoomDto chatRoom = ChatRoomDto.builder()
                .roomId(randomId)
                .build();
        chatRooms.put(randomId, chatRoom);

        return chatRoom;
    }

    public <T> void sendMessage(WebSocketSession session, T message) {//메시지 발송
        try {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }
}

ChatMessage.java

@Getter
@Setter
public class ChatMessage {
    // 메시지 타입 : 입장, 채팅
    public enum MessageType {
        ENTER, ENTER2
    }
    private MessageType type; // 메시지 타입
    private String roomId; // 방번호
    private String message; // 메시지

}

ChatRoomDto.java


@Getter
public class ChatRoomDto {

    private String roomId;
    private Set<WebSocketSession> sessions = new HashSet<>();

    @Builder
    public ChatRoomDto(String roomId) {
        this.roomId = roomId;
    }

    public void handleTempActions(WebSocketSession session, ChatMessage chatMessage, ChatService chatService) throws ParseException {

        if (chatMessage.getType().equals(ChatMessage.MessageType.ENTER)
        //메세지 타입이 enter 라면 보내줄 것) {
            sessions.add(session);
//보낼 메세지를 set해주는 과정
            chatMessage.setMessage(
                    jsonText.MatchjsonTest()
            );

            sendMessage(chatMessage, chatService);
        }
        if 
       (chatMessage.getType().equals(ChatMessage.MessageType.ENTER2)
       //메세지 타입이 enter2라면 보내줄 것) {
            sessions.add(session);

            chatMessage.setMessage(
                    jsonText.UnMatchjsonTest()
            );

            sendMessage(chatMessage, chatService);
        }

    }


    public <T> void sendMessage(T message, ChatService chatService) {
        sessions.parallelStream().forEach(session -> chatService.sendMessage(session, message));
    }

}

  • 소켓 커넥션을 연결할 때 프로토콜은 http가 아니라 ws를 사용
  • https 의 경우에는 wss로 자동으로 변환이 된다.
  • 로컬

    ws://localhost:8081/ws/design-file

  • 서버

    wss://홈페이지 주소(ssl 적용된 https)/ws/design-file


소켓 구현 출처 : https://daddyprogrammer.org/

0개의 댓글