프로젝트 생성
Java버전 및 Gradle 선택
Spring 버전, 의존성 추가
패키지 구조
chat
WebSockConfig
WebSocketHandler
- controller
- ChatController
- dto
- ChatMessage
- ChatRoom
- service
- ChatService
WebSocket 기본설정
- WebSockConfig
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; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Configuration @EnableWebSocket public class WebSockConfig implements WebSocketConfigurer { private final WebSocketHandler webSocketHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(webSocketHandler, "ws").setAllowedOrigins("*"); } }
- WebSocketHandler
import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import com.blackcode.www.chat.dto.ChatMessage; import com.blackcode.www.chat.dto.ChatRoom; import com.blackcode.www.chat.service.ChatService; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @RequiredArgsConstructor @Component public class WebSocketHandler 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); ChatMessage chatMessage = objectMapper.readValue(payload, ChatMessage.class); ChatRoom chatRoom = chatService.findRoomById(chatMessage.getRoomId()); chatRoom.handlerActions(session, chatMessage, chatService); } }
Controller 생성
- ChatController
import java.util.List; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.blackcode.www.chat.dto.ChatRoom; import com.blackcode.www.chat.service.ChatService; import lombok.RequiredArgsConstructor; @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(); } }
Service 생성
- ChatService Class
import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.springframework.stereotype.Service; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import com.blackcode.www.chat.dto.ChatRoom; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @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); log.info(chatRoom.toString()); 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); } } }
dto 생성
- ChatMessage Class
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 Class
import java.util.HashSet; import java.util.Set; import org.springframework.web.socket.WebSocketSession; import com.blackcode.www.chat.service.ChatService; import lombok.Builder; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @Slf4j @Getter public class ChatRoom { private String roomId; private String name; private Set<WebSocketSession> sessions = new HashSet<>(); @Builder public ChatRoom(String roomId, String name) { log.info("roomID : "+roomId); log.info("name : "+name); this.roomId = roomId; this.name = name; } public void handlerActions(WebSocketSession session, ChatMessage chatMessage, ChatService chatService) { if (chatMessage.getType().equals(ChatMessage.MessageType.ENTER)) { sessions.add(session); chatMessage.setMessage(chatMessage.getSender() + "님이 입장했습니다."); } sendMessage(chatMessage, chatService); } private <T> void sendMessage(T message, ChatService chatService) { sessions.parallelStream() .forEach(session -> chatService.sendMessage(session, message)); } }
1. 채팅방 개설
- post
- url : http://127.0.0.1:8080/chat
- Body
- key:name
- Value:방제목
post 방식으로 key/value 값을 송출하고 나면 roomId를 return받는다.
roomId값 메모 필요
2. 방 생성 조회
- get
- url : http://127.0.0.1:8080/chat
3. 방 진입
- WebSocket Text Client
- url : ws://127.0.0.1:8080/ws
- Request
{ "type":"ENTER", "roomId":"<기록해둔 roomId 입력>", "sender":"<참가자 ID>", "message":"<채팅할때만 message 입력>" }
4. 채팅 진행
- WebSocket Text Client
- url : ws://127.0.0.1:8080/ws
- Request
{ "type":"TALK", "roomId":"<기록해둔 roomId 입력>", "sender":"<참가자 ID>", "message":"<채팅할때만 message 입력>" }