[Spring-Boot] WebSocket 구현하기 (1)

JE·2022년 8월 30일

WebSocket이란

HTTP 프로토콜과 호환되며, 실시간 양방향 통신을 제공하기 위한 프로토콜이며 Spring 4.0에서 등장한 네트워크 서비스이다. (접속까지는 HTTP프로토콜을 사용하지만 이후 WebSocket프로토콜로 변경)

WebSocket Spring-boot로 구현하기

  1. WebSocket Config 작성하기

    웹 소켓을 사용하기 위한 설정 파일이 필요하다.
    +) @Configuration을 통해 해당 파일이 Bean 설정을 할 것을 나타냄
    +) @EnableWebSocketMessageBroker을 통해 WebSocket사용을 나타냄

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
	
    /*클라이언트가 웹 소켓 서버에 연결하는데 사용할 웹 소켓 엔드포인트 등록
	  withSockJS를 통해 웹 소켓을 지원하지 않는 브라우저에 대해 웹 소켓을 대체한다.
	  +)메소드명에 STOMP가 들어가는 경우 통신 프로토콜인 STOMP구현에서 작동된다. */
	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/ws").withSockJS();
	}
	
	/*한 클라이언트에서 다른 클라이언트로 메시지를 라우팅하는데 사용될 메시지 브로커*/
	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		
		//roomname으로 시작되는 요청을 구독한 모든 사용자들에게 메시지를 broadcast한다.
		registry.enableSimpleBroker("/roomname");
		// message로 시작되는 메시지는 message-handling methods로 라우팅된다.
		registry.setApplicationDestinationPrefixes("/message");
	}
}
  1. 채팅내용 및 사용자를 담아줄 ChatMessageDTO 생성하기
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatMessageDTO {
	private MessageType type;
	private String content;
	private String sender;
}

이때 MessageType은 일반 class가 아닌 enum으로 작성한다.
+) Java의 Enum타입은 일정 개수의 상수값을 선언하는 관련있는 상수들의 집합을 의미한다.

public enum MessageType {
	CHAT,
	JOIN,
	LEAVE
}
  1. 채팅을 보냈을 때 또는 채팅인원이 변경되면 처리해줄 ChatController 생성
@Controller
@Slf4j
public class ChatController {
	
	@Autowired
	private SimpMessageSendingOperations messagingTemplate;
	
	ArrayList<String> users = new ArrayList<String>();
	
	// 새로운 사용자가 웹 소켓을 연결할 때 실행됨
    // @EventListener은 한개의 매개변수만 가질 수 있다.
	@EventListener
	public void handleWebSocketConnecListener(SessionConnectEvent event) {
		log.info("Received a new web socket connection");
	}
    
	// 사용자가 웹 소켓 연결을 끊으면 실행됨
	@EventListener
	public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
		StompHeaderAccessor headerAccesor = StompHeaderAccessor.wrap(event.getMessage());
		String username = (String) headerAccesor.getSessionAttributes().get("username");
	
		if(username != null) {
			log.info("User Disconnected : " + username);
			
			users.remove(username);
			System.out.println(users);
			
			ChatMessageDTO chat = new ChatMessageDTO(MessageType.LEAVE, null, username);
			messagingTemplate.convertAndSend("/roomname/public", chat);
		}
	}
	
	// /message/sendMessage로 요청이 들어오면 해당 메소드로 처리된다.
	@MessageMapping("/sendMessage")
	@SendTo("/roomname/public")
	public ChatMessageDTO sendMessage(@Payload ChatMessageDTO chat) {
		return chat;
	}
	
	// /message/addUser로 요청이 들어오면 해당 메소드로 처리된다.
	@MessageMapping("/addUser")
	@SendTo("/roomname/public")
	public ChatMessageDTO addUser(@Payload ChatMessageDTO chat, SimpMessageHeaderAccessor headerAccessor) {
		headerAccessor.getSessionAttributes().put("username", chat.getSender());
		users.add(chat.getSender());
		return chat;
	}
}

참고한 블로그 및 사이트

https://blog.naver.com/PostView.naver?blogId=qjawnswkd&logNo=222283176175&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView

https://ratseno.tistory.com/71?category=773803

https://dev-gorany.tistory.com/212

profile
정리가 필요한 부분만 정리합니다

0개의 댓글