반응형
지난번에 웹소켓을 학습하고 도입해보면서 방을 여러개 만들어서 여러 방에서 사람들을 나누는 방법에 대해 궁금해졌습니다.
따라서 오늘 해볼것은 "방 여러개 만들어서 채팅하기"입니다.
- 방 생성하기
- user1으로 room에 접속하기
- user2도 room에 접속하기
- user1으로 TALK 하기
코드
- WebSockChatHandler
package com.example.websocket.config;
import com.example.websocket.dto.ChatMessage;
import com.example.websocket.dto.ChatRoom;
import com.example.websocket.service.ChatService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
@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);
ChatRoom room = chatService.findRoomById(chatMessage.getRoomId());
room.handleActions(session, chatMessage, chatService);
}
}
- WebSockConfig
package com.example.websocket.config;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@RequiredArgsConstructor
@Configuration
@EnableWebSocket
public class WebSockConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/ws/chat").setAllowedOrigins("*");
}
}
- ChatController
package com.example.websocket.controller;
import com.example.websocket.dto.ChatRoom;
import com.example.websocket.service.ChatService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequiredArgsConstructor
@RestController
@RequestMapping("/chat")
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();
}
}
- ChatMessage
package com.example.websocket.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ChatMessage {
public enum MessageType {
ENTER, TALK
}
private MessageType type;
private String roomId;
private String sender;
private String message;
}
- ChatRoom
package com.example.websocket.dto;
import com.example.websocket.service.ChatService;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.socket.WebSocketSession;
import java.util.HashSet;
import java.util.Set;
@Getter
public class ChatRoom {
private String roomId;
private String name;
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
package com.example.websocket.service;
import com.example.websocket.dto.ChatRoom;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
@Slf4j
@RequiredArgsConstructor
@Service
public class ChatService {
private final ObjectMapper objectMapper;
private Map<String, ChatRoom> chatRooms;
@PostConstruct
private void init() {
chatRooms = new LinkedHashMap<>();
}
public List<ChatRoom> findAllRoom() {
return new ArrayList<>(chatRooms.values());
}
public ChatRoom findRoomById(String roomId) {
return chatRooms.get(roomId);
}
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;
}
public <T> void sendMessage(WebSocketSession session, T message) {
try {
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
- build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.projectlombok:lombok:1.18.10'
implementation 'org.springframework.boot:spring-boot-starter:2.2.1.RELEASE'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
}
tasks.named('test') {
useJUnitPlatform()
}
위와 같은 방식으로 방 여러개를 만들어 유저들끼리 소통하는 서비스를 구현해봤습니다.
다음에 해볼 것은 STOMP를 이용하여 채팅을 고도화하고 좀 더 최적화를 해보도록 하겠습니다.
참고자료
https://www.daddyprogrammer.org/post/4077/spring-websocket-chatting/#google_vignette
반응형
'기타 > WebSocket' 카테고리의 다른 글
WebSocket + Spring Boot 도입기 : 웹소켓 기초 (2) | 2024.01.04 |
---|
댓글