반응형
Theo | 테오
시행착오를 줄이는 방법 - 진태양
Theo | 테오
  • 분류 전체보기 (26)
    • General (10)
      • Essay (8)
      • Craftsmanship (1)
      • IT Meet & Hack (1)
    • Development (9)
      • News (2)
      • Architecture (1)
      • Spring Framework (3)
      • JVM (1)
      • React (0)
      • Next.js (0)
      • Web (0)
      • Git (2)
      • Algorithm (0)
      • Python (0)
    • Security (0)
      • PKI (0)
    • Infrastructure (1)
      • Kubernetes (0)
      • AWS (1)
    • Computer Science (0)
      • Network (0)
    • Civic Hacking (3)
      • Code for Korea (3)
    • Know-how (2)
      • IT Service (1)
      • Career (1)
    • Finance (0)
      • Portfolio (0)
      • Activity (0)
    • English (1)
      • Translation (1)

인기 글

블로그 메뉴

  • 홈
  • 관리
  • 방명록
hELLO · Designed By 정상우.
Theo | 테오

시행착오를 줄이는 방법 - 진태양

SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (2)
Development/Spring Framework

SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (2)

2021. 12. 14. 15:53
반응형

목차

  • SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (1)
  • SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (2) - 현재 게시글
  • SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (3)

 

springboot-web 관련 의존성은 추가되어있다는 것을 가정으로 글을 작성하니 참고 부탁드립니다.

1. 채팅방 관리를 위한 Entity 및 Component 추가

여기선 Repository에 별도 DataSource를 연결하지 않고 memory 상에 Map으로 관리해주었다.

// ChatRoom.kt
data class ChatRoom(
    val name: String
) {
    val id: String
        get() = "room_$name"
}
// ChatRoomRepository.kt
@Repository
class ChatRoomRepository {

    private val chatRooms = LinkedHashMap<String, ChatRoom>()

    fun findAllRoom(): List<ChatRoom> {
        return chatRooms.values.toList()
    }

    fun findById(id: String): ChatRoom {
        return chatRooms[id]!!
    }

    fun createRoom(name: String): ChatRoom {
        return ChatRoom(
            name = name
        ).also {
            chatRooms[it.id] = it
        }
    }
}
// ChatRoomService.kt
@Service
class ChatRoomService(
    private val chatRoomRepository: ChatRoomRepository
) {

    fun findAllRoom(): List<ChatRoom> {
        return chatRoomRepository.findAllRoom()
    }

    fun findById(id: String): ChatRoom {
        return chatRoomRepository.findById(id)
    }

    fun createRoom(name: String): ChatRoom {
        return chatRoomRepository.createRoom(name)
    }
}

2. SpringBoot websocket 의존성 추가

dependencies {
  implementation("org.springframework.boot:spring-boot-starter-websocket")
}

해당 라이브러리에는 STOMP를 비롯한 소켓 통신을 위한 여러 구현체가 존재한다.

3. WebSocketConfig 생성

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig : WebSocketMessageBrokerConfigurer {

    override fun registerStompEndpoints(registry: StompEndpointRegistry) {
        registry.addEndpoint("/ws/chat")
            .setAllowedOriginPatterns("*")
            .withSockJS()
    }

    override fun configureMessageBroker(registry: MessageBrokerRegistry) {
        registry.enableSimpleBroker("/sub")
    }
}
  • STOMP 엔드포인트를 /ws/chat 으로 설정 해주고, 어느 곳에서나 접근 가능하게 해둔 뒤 SocketJS를 이용해 통신할 것임을 명시해준다.
  • 브로커(여기선 in-memory broker)에게 /sub 이라는 prefix로 오는 요청을 수신할 것을 등록해준다.

4. Client와 통신 시 사용할 Mapping 정보 등록

// dto.kt
data class ChatRoomDto(
    val id: String
)

data class ChatDto(
    val type: Type,
    val sender: String,
    val message: String
) {

    val createdAt: Long = LocalDateTime.now().toEpochMillis()

    enum class Type {
        ENTER, COMMENT
    }
}


internal fun ChatRoom.toDto() = ChatRoomDto(
    id = id
)

private fun LocalDateTime.toEpochMillis(zoneId: ZoneId = ZoneOffset.UTC): Long = this.atZone(zoneId).toInstant().toEpochMilli()
// ChatRoomRestController.kt
@RestController
class ChatRoomRestController(
    private val chatRoomService: ChatRoomService
) {

    /**
     * 클라이언트의 /pub 요청을 받아 /sub 에게 보낸다
     * 실제론 해당 블록 내에 채팅 기록 저장 등의 로직이 필요하다
     */
    @MessageMapping("/pub/chat/room/{roomId}")
    @SendTo("/sub/chat/room/{roomId}")
    fun message(@DestinationVariable roomId: String, dto: ChatDto): ChatDto {
        return dto
    }

    /**
     * 채팅방 생성
     */
    @PostMapping(
        value = ["/api/v1/chat/room"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    fun createRoom(@RequestParam name: String): ChatRoomDto {
        return chatRoomService.createRoom(name).toDto()
    }

    /**
     * 등록된 채팅방 전체 조회
     */
    @GetMapping(
        value = ["/api/v1/chat/room"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    fun findAllRoom(): List<ChatRoomDto> {
        return chatRoomService.findAllRoom().map {
            it.toDto()
        }
    }

    /**
     * 채팅방 정보 조회
     */
    @GetMapping(
        value = ["/api/v1/chat/room/{roomId}"],
        produces = [MediaType.APPLICATION_JSON_VALUE]
    )
    fun roomInfo(
        @PathVariable roomId: String
    ): ChatRoom {
        return chatRoomService.findById(roomId)
    }
}

다음은 구현한 서버에 맞는 클라이언트를 만들어 볼 차례다.

다음 편에 계속 - SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (3)

반응형
저작자표시 비영리 동일조건 (새창열림)

    ☕️ Networking

    기술 직군의 기술적인 교류, 커리어 이야기, 직군 무관 네트워킹 모두 환영합니다!

    위클리 아카데미 오픈 채팅방(비밀번호: 9323)

    kakaotalk: https://open.kakao.com/o/gyvuT5Yd

    📑 간편 세금계산서 발행, 관리

    볼타: https://bolta.io

    볼타 채용: https://careers.bolta.io

    'Development/Spring Framework' 카테고리의 다른 글
    • SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (3)
    • SpringBoot에서 STOMP로 채팅 애플리케이션 만들기 (1)
    Theo | 테오
    Theo | 테오
    Java/Kotlin, Spring 백엔드 관련 기술을 익히고 공유합니다.

    티스토리툴바