오늘 공부한 것
* WebSocket 사용한 채팅 기능 구현 (Stomp 도입)
Stomp 란?메시징 전송을 효율적으로 하기 위해 나온 프로토콜이고 기본적으로 pub / sub 구조로 되어있어 메세지를 발송하고, 메세지를 받아 처리하는 부분이 확실히 정해져 있기 때문에 개발하는 입장에서 명확하게 인지하고 개발할 수 있는 이점이 있다. 또한 통신 메세지의 헤더에 값을 세팅할 수 있어 헤다 값을 기반으로 통신시 인증처리를 구현하는 것도 가능
pub / sub 란 메세지를 공급하는 주체와 소비하는 주체를 분리하여 제공하는 메세징 방법이다.
예를 들어 우체통 (topic) 이 있으면 집배원 (publisher) 이 신문을 우체통에 배달하는 액션이 있고,
기다렸다가 빼서 보는 구독자 (subscriber) 의 액션이 있다 여기서 구독자는 여러명이 될 수 있다
* 채팅방 생성 : pub / sub 구현을 위한 Topic 생성
* 채팅방 입장 : Topic 을 구독
* 메세지 주고 받음 : 해당 Topic 으로 메세지를 발송하거나 (pub) 메세지를 받는다 (sub)
코드는 아래와 같이 변경 되었다
1. Config
@Configuration
@EnableWebSocketMessageBroker // 웹소켓 서버를 사용한다는 설정
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// 서버 -> 클라이언트로 발행하는 메세지에 대한 endpoint 설정 : 구독
config.enableSimpleBroker("/sub"); // 발행자가 queue (1:1) topic (1:다)의 경로로 메세지를 주면 구독자들에게 전달
// 클라이언트 -> 서버로 발행하는 메세지에 대한 endpoint 설정 : 구독에 대한 메세지
config.setApplicationDestinationPrefixes("/pub"); // 메세지 앞에 app이 붙어있는 경로로 발신되면 해당 경로를 처리하고 있는 핸들러로 전달됨 @MessageMapping 어노테이션이 붙은 곳을 타겟으로 한다는 설정
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 웹 소켓이 hanshake를 하기 위해 연결하는 endpoint
registry.addEndpoint("/ws-stomp") // WebSocket 또는 SockJS가 웹소켓 핸드세이크 커넥션을 생성할 경로
.setAllowedOriginPatterns("*")
.withSockJS(); // WebSocket을 지원하지 않는 브라우저에서 HTTP의 Polling과 같은 방식으로 WebSocket의 요청을 수행하도록 도와줌
}
}
2. Controller
@RequiredArgsConstructor
@Controller
public class ChatController {
private final SimpMessageSendingOperations messagingTemplate; //특정 Broker로 메세지를 전달
@MessageMapping("/chat/message")
public void message(ChatMessageDto message) {
if (ChatMessageDto.MessageType.ENTER.equals(message.getType()))
message.setMessage(message.getSender() + "님이 입장하셨습니다.");
messagingTemplate.convertAndSend("/sub/chat/room/" + message.getRoomId(), message);
}
}
@RequiredArgsConstructor
@Controller
@RequestMapping("/chat")
public class ChatRoomController {
private final ChatRoomRepository chatRoomRepository;
// 채팅 리스트 화면
@GetMapping("/room")
public String room(Model model) {
return "/chat/room";
}
// 모든 채팅방 목록 반환
@GetMapping("/rooms")
@ResponseBody
public List<ChatRoomDto> room () {
return chatRoomRepository.findAllRoom();
}
// 채팅방 생성
@PostMapping("/room")
@ResponseBody
public ChatRoomDto createRoom(@RequestParam String name) {
return chatRoomRepository.createChatRoom(name);
}
// 채팅방 입장화면
@GetMapping("/room/enter/{roomId}")
public String roomDetail(Model model, @PathVariable String roomId) {
model.addAttribute("roomId", roomId);
return "/chat/roomdetail";
}
// 특정 채팅방 조회
@GetMapping("room/{roomId}")
@ResponseBody
public ChatRoomDto roomInfo(@PathVariable String roomId) {
return chatRoomRepository.findRoomById(roomId);
}
}
3. Dto
@Getter
@Setter
public class ChatMessageDto {
// 메세지 타입 : 입장, 채팅
public enum MessageType{
ENTER,
TALK
}
private MessageType type; // 메세지 타입
private String roomId; // 방번호
private String sender; //메세지 보낸사람
private String message; // 메세지
}
@Getter
@Setter
public class ChatRoomDto {
private String roomId;
private String name;
public static ChatRoomDto create(String name) {
ChatRoomDto chatRoomDto = new ChatRoomDto();
chatRoomDto.roomId = UUID.randomUUID().toString(); // UUID : 네트워크 상에서 고유성이 보장되는 id
chatRoomDto.name = name;
return chatRoomDto;
}
}
4. Repository
@Repository
public class ChatRoomRepository {
private Map<String, ChatRoomDto> chatRoomDtoMap;
// 의존하는 객체를 설정한 이후 초기화 작업을 수행하는 메서드에 적용
@PostConstruct
private void init() {
chatRoomDtoMap = new LinkedHashMap<>();
}
public List<ChatRoomDto> findAllRoom(){
// 채팅방 생성순서 최근 순으로 반환
List chatRooms = new ArrayList<>(chatRoomDtoMap.values());
Collections.reverse(chatRooms);
return chatRooms;
}
public ChatRoomDto findRoomById(String id) {
return chatRoomDtoMap.get(id);
}
public ChatRoomDto createChatRoom(String name) {
ChatRoomDto chatRoomDto = ChatRoomDto.create(name);
chatRoomDtoMap.put(chatRoomDto.getRoomId(), chatRoomDto);
return chatRoomDto;
}
}
5. 결과
'항해99' 카테고리의 다른 글
23.10.21 항해 99 16기 실전 프로젝트 16일차 (0) | 2023.10.21 |
---|---|
23.10.20 항해 99 16기 실전 프로젝트 15일차 (0) | 2023.10.20 |
23.10.18 항해 99 16기 실전 프로젝트 13일차 (1) | 2023.10.18 |
23.10.17 항해 99 16기 실전 프로젝트 12일차 (0) | 2023.10.17 |
23.10.16 항해 99 16기 실전 프로젝트 11일차 (0) | 2023.10.16 |