Skip to content

Commit 7027552

Browse files
안훈기안훈기
authored andcommitted
✨ Feat: 내 매칭 이력 조회 API 추가
1 parent 49c2144 commit 7027552

File tree

6 files changed

+108
-2
lines changed

6 files changed

+108
-2
lines changed

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
up:
2+
docker compose -f docker/docker-compose.local.yml up -d
3+
4+
down:
5+
docker compose -f docker/docker-compose.local.yml down
6+
7+
restart:
8+
docker compose -f docker/docker-compose.local.yml down && \
9+
docker compose -f docker/docker-compose.local.yml up -d
10+
11+
logs:
12+
docker compose -f docker/docker-compose.local.yml logs -f

src/main/java/com/be/sportizebe/domain/match/controller/MatchController.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.be.sportizebe.domain.match.dto.request.MatchNearRequest;
44
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
55
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
6+
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
67
import com.be.sportizebe.domain.match.service.MatchService;
78
import com.be.sportizebe.global.cache.dto.UserAuthInfo;
89
import com.be.sportizebe.global.response.BaseResponse;
@@ -65,7 +66,16 @@ public ResponseEntity<BaseResponse<Void>> leaveMatch(
6566
return ResponseEntity.ok(BaseResponse.success("매칭 취소 성공", null));
6667
}
6768

68-
@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
69+
@Operation(summary = "내가 참여 중인 매칭 목록", description = "JOINED 상태인 매칭만 반환한다.")
70+
@GetMapping("/me")
71+
public ResponseEntity<BaseResponse<List<MyMatchResponse>>> getMyMatches(
72+
@AuthenticationPrincipal UserAuthInfo userAuthInfo
73+
) {
74+
List<MyMatchResponse> response = matchService.getMyMatches(userAuthInfo.getId());
75+
return ResponseEntity.ok(BaseResponse.success("내 매칭 목록 조회 성공", response));
76+
}
77+
78+
@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
6979
@GetMapping("/near")
7080
public ResponseEntity<BaseResponse<List<MatchNearResponse>>> getNearMatches(
7181
@ParameterObject @Valid @ModelAttribute MatchNearRequest request
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.be.sportizebe.domain.match.dto.response;
2+
3+
import com.be.sportizebe.common.enums.SportType;
4+
import com.be.sportizebe.domain.match.entity.MatchParticipant;
5+
import com.be.sportizebe.domain.match.entity.MatchParticipantStatus;
6+
import com.be.sportizebe.domain.match.entity.MatchRoom;
7+
import com.be.sportizebe.domain.match.entity.MatchStatus;
8+
import io.swagger.v3.oas.annotations.media.Schema;
9+
10+
import java.time.LocalDateTime;
11+
12+
@Schema(description = "내 매칭 이력 응답")
13+
public record MyMatchResponse(
14+
15+
@Schema(description = "매칭방 ID", example = "42")
16+
Long matchId,
17+
18+
@Schema(description = "스포츠 종류", example = "SOCCER")
19+
SportType sportsName,
20+
21+
@Schema(description = "체육시설 ID", example = "7")
22+
Long facilityId,
23+
24+
@Schema(description = "최대 인원", example = "12")
25+
int maxMembers,
26+
27+
@Schema(description = "현재 인원", example = "8")
28+
int curMembers,
29+
30+
@Schema(description = "매칭 상태", example = "OPEN")
31+
MatchStatus matchStatus,
32+
33+
@Schema(description = "매칭 시작 일시", example = "2026-03-10T18:00:00")
34+
LocalDateTime scheduledAt,
35+
36+
@Schema(description = "진행 시간(분)", example = "60")
37+
int durationMinutes,
38+
39+
@Schema(description = "참가비", example = "5000")
40+
int entryFee,
41+
42+
@Schema(description = "내 참가 상태 (JOINED: 참여 중, LEFT: 취소)", example = "JOINED")
43+
MatchParticipantStatus participantStatus,
44+
45+
@Schema(description = "참가 일시", example = "2026-03-07T12:00:00")
46+
LocalDateTime joinedAt
47+
) {
48+
public static MyMatchResponse from(MatchParticipant participant) {
49+
MatchRoom room = participant.getMatchRoom();
50+
return new MyMatchResponse(
51+
room.getId(),
52+
room.getSportsName(),
53+
room.getFacilityId(),
54+
room.getMaxMembers(),
55+
room.getCurMembers(),
56+
room.getStatus(),
57+
room.getScheduledAt(),
58+
room.getDurationMinutes(),
59+
room.getEntryFee(),
60+
participant.getStatus(),
61+
participant.getJoinedAt()
62+
);
63+
}
64+
}

src/main/java/com/be/sportizebe/domain/match/repository/MatchParticipantRepository.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import com.be.sportizebe.domain.match.entity.MatchRoom;
66
import com.be.sportizebe.domain.user.entity.User;
77
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.Query;
9+
import org.springframework.data.repository.query.Param;
810

911
import java.util.List;
1012
import java.util.Optional;
@@ -25,4 +27,9 @@ public interface MatchParticipantRepository extends JpaRepository<MatchParticipa
2527

2628
// 특정 유저의 특정 매칭방 참가 이력 단건 조회 (상태 무관)
2729
Optional<MatchParticipant> findByMatchRoomAndUser(MatchRoom matchRoom, User user);
30+
31+
// 내 참여 중인 매칭 목록 (JOINED, N+1 방지 fetch join)
32+
@Query("SELECT mp FROM MatchParticipant mp JOIN FETCH mp.matchRoom WHERE mp.user.id = :userId AND mp.status = :status ORDER BY mp.joinedAt DESC")
33+
List<MatchParticipant> findAllByUserIdAndStatusFetch(@Param("userId") Long userId, @Param("status") MatchParticipantStatus status);
34+
2835
}

src/main/java/com/be/sportizebe/domain/match/service/MatchService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
66
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
77
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
8-
import com.be.sportizebe.domain.user.entity.User;
8+
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
99

1010
import java.util.List;
1111

@@ -23,4 +23,6 @@ public interface MatchService {
2323

2424
void deleteMatch(Long matchId); // 매칭 삭제 (관리자 전용)
2525

26+
List<MyMatchResponse> getMyMatches(Long userId); // 참여 중인 매칭 목록
27+
2628
}

src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
55
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
66
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
7+
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
78
import com.be.sportizebe.domain.match.entity.MatchParticipant;
89
import com.be.sportizebe.domain.match.entity.MatchParticipantStatus;
910
import com.be.sportizebe.domain.match.entity.MatchRoom;
@@ -135,6 +136,16 @@ public void deleteMatch(Long matchId) {
135136
}
136137

137138
@Override
139+
@Transactional(readOnly = true)
140+
public List<MyMatchResponse> getMyMatches(Long userId) {
141+
return matchParticipantRepository
142+
.findAllByUserIdAndStatusFetch(userId, MatchParticipantStatus.JOINED)
143+
.stream()
144+
.map(MyMatchResponse::from)
145+
.toList();
146+
}
147+
148+
@Override
138149
@Transactional(readOnly = true)
139150
public List<MatchNearResponse> getNearMatches(MatchNearRequest request) {
140151
String sportsName = request.getSportsName() == null

0 commit comments

Comments
 (0)