Skip to content

Commit 25f59af

Browse files
authored
Merge pull request #216 from prgrms-web-devcourse-final-project/feature/EA3-111-groupchat
[EA3-111] refactor : 그룹 채팅 로직 studyId 기반으로 전면 리팩토링
2 parents 6b37630 + 61c6251 commit 25f59af

12 files changed

+58
-56
lines changed

src/main/java/grep/neogulcoder/domain/groupchat/controller/GroupChatRestController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ public class GroupChatRestController implements GroupChatRestSpecification {
1616

1717
// 과거 채팅 메시지 페이징 조회 (무한 스크롤용)
1818
@Override
19-
@GetMapping("/room/{roomId}/messages")
19+
@GetMapping("/study/{studyId}/messages")
2020
public ApiResponse<PageResponse<GroupChatMessageResponseDto>> getMessages(
21-
@PathVariable("roomId") Long roomId,
21+
@PathVariable("studyId") Long studyId,
2222
@RequestParam(defaultValue = "0") int page,
2323
@RequestParam(defaultValue = "20") int size
2424
) {
2525
// 서비스에서 페이징된 메시지 조회
2626
PageResponse<GroupChatMessageResponseDto> pageResponse =
27-
groupChatService.getMessages(roomId, page, size);
27+
groupChatService.getMessages(studyId, page, size);
2828

2929
return ApiResponse.success(pageResponse);
3030
}

src/main/java/grep/neogulcoder/domain/groupchat/controller/GroupChatRestSpecification.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ public interface GroupChatRestSpecification {
1616
summary = "채팅 메시지 페이징 조회",
1717
description = """
1818
이 API는 **채팅방의 과거 메시지**를 페이지 단위로 가져오는 용도입니다.
19-
WebSocket의 실시간 수신(`/sub/chat/room/{roomId}`)과는 별개로,
19+
WebSocket의 실시간 수신(`/sub/chat/study/{studyId}`)과는 별개로,
2020
채팅방에 입장할 때 이전 대화 기록을 불러오는 데 사용됩니다.
2121
2222
---
2323
2424
**프론트엔드 연동 흐름 (권장 방식)**:
25-
1. **채팅방 입장 시** → `GET /api/chat/room/{roomId}/messages?page=0&size=20` 호출해 최신 메시지 20개 로드
25+
1. **채팅방 입장 시** → `GET /api/chat/study/{studyId}/messages?page=0&size=20` 호출해 최신 메시지 20개 로드
2626
2. **스크롤 위로 올릴 때** → `page=1`, `page=2` ... 순차적으로 과거 메시지를 추가 로딩 (무한 스크롤)
27-
3. **동시에** → WebSocket(`wss://wibby.cedartodo.uk/ws-stomp`) 연결 후 `/sub/chat/room/{roomId}`를 **구독**해 실시간 메시지 수신
27+
3. **동시에** → WebSocket(`wss://wibby.cedartodo.uk/ws-stomp`) 연결 후 `/sub/chat/study/{studyId}`를 **구독**해 실시간 메시지 수신
2828
2929
---
3030
3131
**파라미터 설명**:
32-
- `roomId`: 채팅방 ID
32+
- `studyId`: 스터디 ID
3333
- `page`: 페이지 번호 (0부터 시작, 0 = 최신 메시지 20개)
3434
- `size`: 한 페이지당 메시지 수 (기본값 20)
3535
- 메시지는 **오래된 순(오름차순)**으로 반환됩니다.
@@ -45,7 +45,7 @@ public interface GroupChatRestSpecification {
4545
4646
**예시 요청 URL**:
4747
```
48-
/api/chat/room/1/messages?page=0&size=20
48+
/api/chat/study/1/messages?page=0&size=20
4949
```
5050
5151
**예시 응답**:
@@ -56,7 +56,7 @@ public interface GroupChatRestSpecification {
5656
"content": [
5757
{
5858
"id": 101,
59-
"roomId": 1,
59+
"studyId": 1,
6060
"senderId": 10,
6161
"senderNickname": "유강현",
6262
"profileImageUrl": "https://example.com/profile.jpg",
@@ -74,8 +74,8 @@ public interface GroupChatRestSpecification {
7474
)
7575

7676
ApiResponse<PageResponse<GroupChatMessageResponseDto>> getMessages(
77-
@Parameter(description = "채팅방 ID", example = "1")
78-
@PathVariable("roomId") Long roomId,
77+
@Parameter(description = "스터디 ID", example = "1")
78+
@PathVariable("studyId") Long studyId,
7979

8080
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0")
8181
@RequestParam(defaultValue = "0") int page,

src/main/java/grep/neogulcoder/domain/groupchat/controller/GroupChatSwaggerController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ public ApiResponse<GroupChatSwaggerResponse> sendMessage(
2020
}
2121

2222

23-
@GetMapping("/sub/chat/room/{roomId}")
23+
@GetMapping("/sub/chat/study/{studyId}")
2424
@Override
25-
public ApiResponse<List<GroupChatSwaggerResponse>> getMessages(@PathVariable Long roomId) {
25+
public ApiResponse<List<GroupChatSwaggerResponse>> getMessages(@PathVariable Long studyId) {
2626
List<GroupChatSwaggerResponse> messages = List.of(
2727
new GroupChatSwaggerResponse(),
2828
new GroupChatSwaggerResponse()

src/main/java/grep/neogulcoder/domain/groupchat/controller/GroupChatSwaggerSpecification.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface GroupChatSwaggerSpecification {
2424
**예시 Request JSON**
2525
```json
2626
{
27-
"roomId": 1,
27+
"studyId": 1,
2828
"senderId": 10,
2929
"message": "안녕하세요!"
3030
}
@@ -43,16 +43,16 @@ public interface GroupChatSwaggerSpecification {
4343
- 먼저 `wss://wibby.cedartodo.uk/ws-stomp` 엔드포인트로 STOMP 연결을 맺습니다.
4444
4545
**2. 메시지 구독**
46-
- 연결 후 `/sub/chat/room/{roomId}` 경로를 구독(subscribe)하면 해당 채팅방의 새로운 메시지를 실시간으로 수신할 수 있습니다.
46+
- 연결 후 `/sub/chat/study/{studyId}` 경로를 구독(subscribe)하면 해당 채팅방의 새로운 메시지를 실시간으로 수신할 수 있습니다.
4747
4848
**예시 Subscribe 경로**
49-
`/sub/chat/room/1`
49+
`/sub/chat/study/1`
5050
5151
**예시 수신 데이터(JSON)**
5252
```json
5353
{
5454
"id": 101,
55-
"roomId": 1,
55+
"studyId": 1,
5656
"senderId": 10,
5757
"senderNickname": "유강현",
5858
"profileImageUrl": "https://example.com/profile.jpg",
@@ -64,5 +64,5 @@ public interface GroupChatSwaggerSpecification {
6464
** Swagger에서는 WebSocket 구독을 테스트할 수 없으며,
6565
이 문서는 프론트엔드 구현 참고용입니다.**
6666
""")
67-
ApiResponse<List<GroupChatSwaggerResponse>> getMessages(Long roomId);
67+
ApiResponse<List<GroupChatSwaggerResponse>> getMessages(Long studyId);
6868
}

src/main/java/grep/neogulcoder/domain/groupchat/controller/GroupChatWebSocketController.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ public GroupChatWebSocketController(GroupChatService groupChatService,
2828
// 클라이언트가 /pub/chat/message 로 보낼 때 처리됨
2929
@MessageMapping("/chat/message")
3030
public void handleMessage(GroupChatMessageRequestDto requestDto) {
31-
log.info("[웹소켓] 새 메시지 수신 - 채팅방: {}, 보낸 사람: {}, 내용: {}",
32-
requestDto.getRoomId(), requestDto.getSenderId(), requestDto.getMessage());
31+
log.info("[웹소켓] 새 메시지 수신 - 스터디: {}, 보낸 사람: {}, 내용: {}",
32+
requestDto.getStudyId(), requestDto.getSenderId(), requestDto.getMessage());
3333

3434
// 메시지를 DB에 저장하고, 응답 DTO 생성
3535
GroupChatMessageResponseDto responseDto = groupChatService.saveMessage(requestDto);
3636

37-
// 구독 중인 클라이언트에게 메시지 전송 (채팅방 구분)
38-
// 클라이언트는 /sub/chat/room/{roomId} 구독 중이어야 실시간으로 수신 가능
39-
log.info("[웹소켓] 채팅방 {} 구독자에게 메시지 전송 완료", requestDto.getRoomId());
37+
// 구독 중인 클라이언트에게 메시지 전송 (스터디 구분)
38+
// 클라이언트는 /sub/chat/study/{studyId} 구독 중이어야 실시간으로 수신 가능
39+
log.info("[웹소켓] 스터디 {} 구독자에게 메시지 전송 완료", requestDto.getStudyId());
4040
messagingTemplate.convertAndSend(
41-
"/sub/chat/room/" + requestDto.getRoomId(), // 메시지를 받을 대상
41+
"/sub/chat/study/" + requestDto.getStudyId(), // 메시지를 받을 대상
4242
responseDto // 클라이언트에 전달할 응답 메시지 DTO
4343
);
4444
}

src/main/java/grep/neogulcoder/domain/groupchat/controller/dto/requset/GroupChatMessageRequestDto.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
@Hidden
1010
@Getter
1111
public class GroupChatMessageRequestDto {
12-
private Long roomId;
12+
private Long studyId;
1313
private Long senderId;
1414
private String message;
1515

1616
public GroupChatMessageRequestDto() {}
1717

18-
public GroupChatMessageRequestDto(Long roomId, Long senderId, String message) {
19-
this.roomId = roomId;
18+
public GroupChatMessageRequestDto(Long studyId, Long senderId, String message) {
19+
this.studyId = studyId;
2020
this.senderId = senderId;
2121
this.message = message;
2222
}

src/main/java/grep/neogulcoder/domain/groupchat/controller/dto/requset/GroupChatSwaggerRequest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ public class GroupChatSwaggerRequest {
1010
@Schema(description = "보낸 사람 ID", example = "456")
1111
private Long senderId;
1212

13-
@Schema(description = "채팅방 ID", example = "100")
14-
private Long roomId;
13+
@Schema(description = "스터디 ID", example = "100")
14+
private Long studyId;
1515

1616
@Schema(description = "보낼 메시지", example = "안녕하세요!")
1717
private String message;

src/main/java/grep/neogulcoder/domain/groupchat/controller/dto/response/GroupChatMessageResponseDto.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
public class GroupChatMessageResponseDto {
1212

1313
private Long id; // 메시지 고유 ID
14-
private Long roomId; // 채팅방 ID
14+
private Long studyId; // 채팅방 ID
1515
private Long senderId; // 보낸 사람 ID
1616
private String senderNickname; // 보낸 사람 닉네임
1717
private String profileImageUrl; // 프로필 이미지 URL
1818
private String message; // 메시지 내용
1919
private LocalDateTime sentAt; // 보낸 시간
2020

21-
private GroupChatMessageResponseDto(Long id, Long roomId, Long senderId,
21+
private GroupChatMessageResponseDto(Long id, Long studyId, Long senderId,
2222
String senderNickname, String profileImageUrl,
2323
String message, LocalDateTime sentAt) {
2424
this.id = id;
25-
this.roomId = roomId;
25+
this.studyId = studyId;
2626
this.senderId = senderId;
2727
this.senderNickname = senderNickname;
2828
this.profileImageUrl = profileImageUrl;
@@ -33,7 +33,7 @@ private GroupChatMessageResponseDto(Long id, Long roomId, Long senderId,
3333
public static GroupChatMessageResponseDto from(GroupChatMessage message, User sender) {
3434
return new GroupChatMessageResponseDto(
3535
message.getMessageId(),
36-
message.getGroupChatRoom().getRoomId(),
36+
message.getGroupChatRoom().getStudyId(),
3737
sender.getId(),
3838
sender.getNickname(),
3939
sender.getProfileImageUrl(),

src/main/java/grep/neogulcoder/domain/groupchat/controller/dto/response/GroupChatSwaggerResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public class GroupChatSwaggerResponse {
2020
@Schema(description = "프로필 이미지 URL", example = "https://ganghyeon.jpg")
2121
private String profileImageUrl;
2222

23-
@Schema(description = "채팅방 ID", example = "100")
24-
private Long roomId;
23+
@Schema(description = "스터디 ID", example = "100")
24+
private Long studyId;
2525

2626
@Schema(description = "보낸 메시지", example = "안녕하세요!")
2727
private String message;

src/main/java/grep/neogulcoder/domain/groupchat/service/GroupChatService.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,20 @@ public class GroupChatService {
3232

3333
@Transactional
3434
public GroupChatMessageResponseDto saveMessage(GroupChatMessageRequestDto requestDto) {
35-
log.info("[서비스] 메시지 저장 시작 - 채팅방: {}, 보낸 사람: {}",
36-
requestDto.getRoomId(), requestDto.getSenderId());
35+
log.info("[서비스] 메시지 저장 시작 - 스터디: {}, 보낸 사람: {}",
36+
requestDto.getStudyId(), requestDto.getSenderId());
3737

3838
// 채팅방 존재 여부 확인
39-
GroupChatRoom room = roomRepository.findById(requestDto.getRoomId())
39+
GroupChatRoom room = roomRepository.findByStudyId(requestDto.getStudyId())
4040
.orElseThrow(() -> new IllegalArgumentException("채팅방이 존재하지 않습니다."));
4141
// 메시지 발신자(사용자) 정보 조회
4242
User sender = userRepository.findById(requestDto.getSenderId())
4343
.orElseThrow(() -> new IllegalArgumentException("사용자가 존재하지 않습니다."));
4444

45-
log.info("[서비스] 보낸 사람 '{}' 검증 완료 (roomId={})", sender.getNickname(), room.getRoomId());
45+
log.info("[서비스] 보낸 사람 '{}' 검증 완료 (studyId={})", sender.getNickname(), room.getStudyId());
4646

4747
// 스터디 참가자 검증 로직 추가
48-
Long studyId = room.getStudyId();
49-
boolean isParticipant = studyMemberRepository.existsByStudyIdAndUserId(studyId, sender.getId());
48+
boolean isParticipant = studyMemberRepository.existsByStudyIdAndUserId(requestDto.getStudyId(), sender.getId());
5049
if (!isParticipant) {
5150
throw new IllegalArgumentException("해당 스터디에 참가한 사용자만 채팅할 수 있습니다.");
5251
}
@@ -56,20 +55,23 @@ public GroupChatMessageResponseDto saveMessage(GroupChatMessageRequestDto reques
5655
// 메시지 저장
5756
messageRepository.save(message);
5857

59-
log.info("[서비스] 메시지 저장 완료 - 메시지ID: {}, 채팅방: {}, 시간: {}",
60-
message.getMessageId(), room.getRoomId(), message.getSentAt());
58+
log.info("[서비스] 메시지 저장 완료 - 메시지ID: {}, 스터디: {}, 시간: {}",
59+
message.getMessageId(), room.getStudyId(), message.getSentAt());
6160

6261
// 응답 dto 생성
6362
return GroupChatMessageResponseDto.from(message, sender);
6463
}
6564

6665
// 과거 채팅 메시지 페이징 조회 (무한 스크롤용)
67-
public PageResponse<GroupChatMessageResponseDto> getMessages(Long roomId, int page, int size) {
66+
public PageResponse<GroupChatMessageResponseDto> getMessages(Long studyId, int page, int size) {
67+
GroupChatRoom room = roomRepository.findByStudyId(studyId)
68+
.orElseThrow(() -> new IllegalArgumentException("채팅방이 존재하지 않습니다."));
69+
6870
// 오래된 메시지부터 조회되도록 정렬 기준을 ASC로 설정
6971
Pageable pageable = PageRequest.of(page, size, Sort.by("sentAt").ascending());
7072

7173
// JPQL 쿼리 메서드 기반 조회
72-
Page<GroupChatMessage> messages = messageRepository.findMessagesByRoomIdAsc(roomId, pageable);
74+
Page<GroupChatMessage> messages = messageRepository.findMessagesByRoomIdAsc(room.getRoomId(), pageable);
7375

7476
// 응답 DTO로 변환
7577
Page<GroupChatMessageResponseDto> messagePage = messages.map(message -> {
@@ -81,7 +83,7 @@ public PageResponse<GroupChatMessageResponseDto> getMessages(Long roomId, int pa
8183

8284
// PageResponse로 감싸서 반환
8385
return new PageResponse<>(
84-
"/api/chat/room/" + roomId + "/messages",
86+
"/api/chat/study/" + studyId + "/messages",
8587
messagePage,
8688
5 // 페이지 버튼 개수
8789
);

0 commit comments

Comments
 (0)