Skip to content

Commit b9b3db8

Browse files
authored
Feat(be) : SSE 설정 삭제 및 Controller 분리 및 WebSocket 설정 (#45)
* refactor(be): 컨트롤러 분리 및 SSE 사설정 삭제 * refactor(be)feat(be): WebSocket 설정 추가 * feat(be) : WebSocket 컨트롤러 추가 * refactor(be): 사용하지 않는 코드 제거 * refactor(be): 사용하지 않는 코드 제거
1 parent f57fc5c commit b9b3db8

File tree

6 files changed

+106
-78
lines changed

6 files changed

+106
-78
lines changed

src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/UserChatSseEvents.kt

Lines changed: 0 additions & 34 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.back.koreaTravelGuide.domain.userChat.chatmessage.controller
2+
3+
import com.back.koreaTravelGuide.common.ApiResponse
4+
import com.back.koreaTravelGuide.domain.userChat.chatmessage.service.ChatMessageService
5+
import org.springframework.http.ResponseEntity
6+
import org.springframework.messaging.simp.SimpMessagingTemplate
7+
import org.springframework.web.bind.annotation.GetMapping
8+
import org.springframework.web.bind.annotation.PathVariable
9+
import org.springframework.web.bind.annotation.PostMapping
10+
import org.springframework.web.bind.annotation.RequestBody
11+
import org.springframework.web.bind.annotation.RequestMapping
12+
import org.springframework.web.bind.annotation.RequestParam
13+
import org.springframework.web.bind.annotation.RestController
14+
15+
@RestController
16+
@RequestMapping("/api/userchat/rooms")
17+
class ChatMessageController(
18+
private val msgSvc: ChatMessageService,
19+
private val messagingTemplate: SimpMessagingTemplate,
20+
) {
21+
@GetMapping("/{roomId}/messages")
22+
fun listMessages(
23+
@PathVariable roomId: Long,
24+
@RequestParam(required = false) after: Long?,
25+
@RequestParam(defaultValue = "50") limit: Int,
26+
): ResponseEntity<ApiResponse<Any>> {
27+
val messages =
28+
if (after == null) {
29+
msgSvc.getlistbefore(roomId, limit)
30+
} else {
31+
msgSvc.getlistafter(roomId, after)
32+
}
33+
return ResponseEntity.ok(ApiResponse(msg = "메시지 조회", data = messages))
34+
}
35+
36+
@PostMapping("/{roomId}/messages")
37+
fun sendMessage(
38+
@PathVariable roomId: Long,
39+
@RequestBody req: ChatMessageService.SendMessageReq,
40+
): ResponseEntity<ApiResponse<Any>> {
41+
val saved = msgSvc.send(roomId, req)
42+
messagingTemplate.convertAndSend(
43+
"/topic/userchat/$roomId",
44+
ApiResponse(msg = "메시지 전송", data = saved),
45+
)
46+
return ResponseEntity.status(201).body(ApiResponse(msg = "메시지 전송", data = saved))
47+
}
48+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.back.koreaTravelGuide.domain.userChat.chatmessage.controller
2+
3+
import com.back.koreaTravelGuide.common.ApiResponse
4+
import com.back.koreaTravelGuide.domain.userChat.chatmessage.service.ChatMessageService
5+
import org.springframework.messaging.handler.annotation.DestinationVariable
6+
import org.springframework.messaging.handler.annotation.MessageMapping
7+
import org.springframework.messaging.handler.annotation.Payload
8+
import org.springframework.messaging.simp.SimpMessagingTemplate
9+
import org.springframework.stereotype.Controller
10+
11+
@Controller
12+
class ChatMessageSocketController(
13+
private val chatMessageService: ChatMessageService,
14+
private val messagingTemplate: SimpMessagingTemplate,
15+
) {
16+
@MessageMapping("/userchat/{roomId}/messages")
17+
fun handleMessage(
18+
@DestinationVariable roomId: Long,
19+
@Payload req: ChatMessageService.SendMessageReq,
20+
) {
21+
val saved = chatMessageService.send(roomId, req)
22+
messagingTemplate.convertAndSend(
23+
"/topic/userchat/$roomId",
24+
ApiResponse(msg = "메시지 전송", data = saved),
25+
)
26+
}
27+
}
Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,26 @@
11
package com.back.koreaTravelGuide.domain.userChat.chatroom.controller
22

33
import com.back.koreaTravelGuide.common.ApiResponse
4-
import com.back.koreaTravelGuide.domain.userChat.UserChatSseEvents
5-
import com.back.koreaTravelGuide.domain.userChat.chatmessage.service.ChatMessageService
64
import com.back.koreaTravelGuide.domain.userChat.chatroom.service.ChatRoomService
7-
import org.springframework.http.MediaType
85
import org.springframework.http.ResponseEntity
96
import org.springframework.web.bind.annotation.DeleteMapping
107
import org.springframework.web.bind.annotation.GetMapping
118
import org.springframework.web.bind.annotation.PathVariable
129
import org.springframework.web.bind.annotation.PostMapping
1310
import org.springframework.web.bind.annotation.RequestBody
1411
import org.springframework.web.bind.annotation.RequestMapping
15-
import org.springframework.web.bind.annotation.RequestParam
1612
import org.springframework.web.bind.annotation.RestController
17-
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter
1813

19-
// 컨트롤러는 임시로 강사님 스타일 따라서 통합해놓았음. 추후 리팩토링 예정
2014
@RestController
2115
@RequestMapping("/api/userchat/rooms")
2216
class ChatRoomController(
2317
private val roomSvc: ChatRoomService,
24-
private val msgSvc: ChatMessageService,
25-
private val events: UserChatSseEvents,
2618
) {
2719
data class StartChatReq(val guideId: Long, val userId: Long)
2820

2921
data class DeleteChatReq(val userId: Long)
3022

31-
// MVP: 같은 페어는 방 재사용
23+
// 같은 페어는 방 재사용
3224
@PostMapping("/start")
3325
fun startChat(
3426
@RequestBody req: StartChatReq,
@@ -50,36 +42,4 @@ class ChatRoomController(
5042
fun get(
5143
@PathVariable roomId: Long,
5244
) = ResponseEntity.ok(ApiResponse(msg = "채팅방 조회", data = roomSvc.get(roomId)))
53-
54-
@GetMapping("/{roomId}/messages")
55-
fun listMessages(
56-
@PathVariable roomId: Long,
57-
@RequestParam(required = false) after: Long?,
58-
@RequestParam(defaultValue = "50") limit: Int,
59-
): ResponseEntity<ApiResponse<Any>> {
60-
val messages =
61-
if (after == null) {
62-
msgSvc.getlistbefore(roomId, limit)
63-
} else {
64-
msgSvc.getlistafter(roomId, after)
65-
}
66-
return ResponseEntity.ok(ApiResponse(msg = "메시지 조회", data = messages))
67-
}
68-
69-
@PostMapping("/{roomId}/messages")
70-
fun sendMessage(
71-
@PathVariable roomId: Long,
72-
@RequestBody req: ChatMessageService.SendMessageReq,
73-
): ResponseEntity<ApiResponse<Any>> {
74-
val saved = msgSvc.send(roomId, req)
75-
events.publishNew(roomId, saved.id!!)
76-
return ResponseEntity.status(201).body(ApiResponse(msg = "메시지 전송", data = saved))
77-
}
78-
79-
// SSE는 스트림이여서 ApiResponse로 감싸지 않았음
80-
// WebSocket,Stomp 적용되면 바로 삭제 예정
81-
@GetMapping("/{roomId}/events", produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
82-
fun subscribe(
83-
@PathVariable roomId: Long,
84-
): SseEmitter = events.subscribe(roomId)
8545
}

src/main/kotlin/com/back/koreaTravelGuide/domain/userChat/chatroom/service/ChatRoomService.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.koreaTravelGuide.domain.userChat.chatroom.service
22

3+
import com.back.koreaTravelGuide.domain.userChat.chatmessage.repository.ChatMessageRepository
34
import com.back.koreaTravelGuide.domain.userChat.chatroom.entity.ChatRoom
45
import com.back.koreaTravelGuide.domain.userChat.chatroom.repository.ChatRoomRepository
56
import org.springframework.stereotype.Service
@@ -9,9 +10,8 @@ import java.time.Instant
910
@Service
1011
class ChatRoomService(
1112
private val roomRepository: ChatRoomRepository,
13+
private val messageRepository: ChatMessageRepository,
1214
) {
13-
data class CreateRoomReq(val title: String, val guideId: Long, val userId: Long)
14-
1515
@Transactional
1616
fun exceptOneToOneRoom(
1717
guideId: Long,
@@ -27,7 +27,9 @@ class ChatRoomService(
2727
)
2828
}
2929

30-
fun get(roomId: Long): ChatRoom = roomRepository.findById(roomId).orElseThrow { NoSuchElementException("room not found: $roomId") }
30+
fun get(roomId: Long): ChatRoom =
31+
roomRepository.findById(roomId)
32+
.orElseThrow { NoSuchElementException("room not found: $roomId") }
3133

3234
@Transactional
3335
fun deleteByOwner(
@@ -39,6 +41,7 @@ class ChatRoomService(
3941
// 예외처리 임시
4042
throw IllegalArgumentException("채팅방 생성자만 삭제할 수 있습니다.")
4143
}
44+
messageRepository.deleteByRoomId(roomId)
4245
roomRepository.deleteById(roomId)
4346
}
4447
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.back.koreaTravelGuide.domain.userChat.config
2+
3+
import org.springframework.context.annotation.Configuration
4+
import org.springframework.messaging.simp.config.MessageBrokerRegistry
5+
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker
6+
import org.springframework.web.socket.config.annotation.StompEndpointRegistry
7+
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer
8+
9+
// userChat에서만 사용할 것 같아서 전역에 두지 않고 userChat 도메인에 두었음
10+
11+
@Configuration
12+
@EnableWebSocketMessageBroker
13+
class UserChatWebSocketConfig : WebSocketMessageBrokerConfigurer {
14+
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
15+
registry.addEndpoint("/ws/userchat")
16+
.setAllowedOriginPatterns("*")
17+
.withSockJS()
18+
}
19+
20+
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
21+
registry.enableSimpleBroker("/topic")
22+
registry.setApplicationDestinationPrefixes("/pub")
23+
}
24+
}

0 commit comments

Comments
 (0)