클라이언트 메세지 DTO
@Getter
@Setter
public class ChatMessage {
// 메세지 타입 : 입장, 채팅
public enum MessageType {
ENTER, TALK
}
private MessageType type;
private String roomId;
private String sender;
private String message;
}
채팅방
- 채팅방 정보
- 채팅방 내 메세지 전송 메서드
@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));
}
}
채팅방 생성 및 전체 채팅방 조회
@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();
}
}
채팅 서비스
- 컨트롤러에서 사용할 메서드
- 채팅 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 수정
- 기본 입장 메세지 삭제 후 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);
}
}
(참고 : https://www.daddyprogrammer.org/post/4077/spring-websocket-chatting/)