Skip to content

Commit 7269d94

Browse files
authored
Merge pull request #72 from Sportize/feat/match-api
✨ Feat: Match 도메인 조회 API 추가 (참가자 목록 / 구장 기반 매칭)
2 parents a928094 + 8097b9f commit 7269d94

File tree

6 files changed

+66
-1
lines changed

6 files changed

+66
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ src/main/resources/*.yml
4343

4444
# 기타
4545
CLAUDE.md
46+
Makefile

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
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.MatchParticipantResponse;
7+
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
68
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
79
import com.be.sportizebe.domain.match.service.MatchService;
810
import com.be.sportizebe.global.cache.dto.UserAuthInfo;
@@ -23,6 +25,7 @@
2325
import org.springframework.web.bind.annotation.PathVariable;
2426
import org.springframework.web.bind.annotation.PostMapping;
2527
import org.springframework.web.bind.annotation.RequestMapping;
28+
import org.springframework.web.bind.annotation.RequestParam;
2629
import org.springframework.web.bind.annotation.RestController;
2730

2831
import java.util.List;
@@ -75,7 +78,25 @@ public ResponseEntity<BaseResponse<List<MyMatchResponse>>> getMyMatches(
7578
return ResponseEntity.ok(BaseResponse.success("내 매칭 목록 조회 성공", response));
7679
}
7780

78-
@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
81+
@Operation(summary = "매칭 참가자 목록 조회", description = "JOINED 상태인 참가자만 반환한다.")
82+
@GetMapping("/{matchId}/participants")
83+
public ResponseEntity<BaseResponse<List<MatchParticipantResponse>>> getMatchParticipants(
84+
@PathVariable Long matchId
85+
) {
86+
List<MatchParticipantResponse> response = matchService.getMatchParticipants(matchId);
87+
return ResponseEntity.ok(BaseResponse.success("매칭 참가자 목록 조회 성공", response));
88+
}
89+
90+
@Operation(summary = "구장 기반 매칭 목록 조회", description = "해당 구장의 OPEN/FULL 상태이며 아직 시작 전인 매칭을 반환한다.")
91+
@GetMapping
92+
public ResponseEntity<BaseResponse<List<MatchResponse>>> getMatchesByFacility(
93+
@RequestParam Long facilityId
94+
) {
95+
List<MatchResponse> response = matchService.getMatchesByFacility(facilityId);
96+
return ResponseEntity.ok(BaseResponse.success("구장 매칭 목록 조회 성공", response));
97+
}
98+
99+
@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
79100
@GetMapping("/near")
80101
public ResponseEntity<BaseResponse<List<MatchNearResponse>>> getNearMatches(
81102
@ParameterObject @Valid @ModelAttribute MatchNearRequest request

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,8 @@ public interface MatchParticipantRepository extends JpaRepository<MatchParticipa
3232
@Query("SELECT mp FROM MatchParticipant mp JOIN FETCH mp.matchRoom WHERE mp.user.id = :userId AND mp.status = :status ORDER BY mp.joinedAt DESC")
3333
List<MatchParticipant> findAllByUserIdAndStatusFetch(@Param("userId") Long userId, @Param("status") MatchParticipantStatus status);
3434

35+
// 매칭 참가자 목록 (N+1 방지 fetch join)
36+
@Query("SELECT mp FROM MatchParticipant mp JOIN FETCH mp.user WHERE mp.matchRoom.id = :matchId AND mp.status = :status")
37+
List<MatchParticipant> findAllByMatchRoomIdAndStatusFetch(@Param("matchId") Long matchId, @Param("status") MatchParticipantStatus status);
38+
3539
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.be.sportizebe.domain.match.repository;
22

33
import com.be.sportizebe.domain.match.entity.MatchRoom;
4+
import com.be.sportizebe.domain.match.entity.MatchStatus;
45
import com.be.sportizebe.domain.match.repository.projection.MatchNearProjection;
56
import org.springframework.data.jpa.repository.JpaRepository;
67
import org.springframework.data.jpa.repository.Modifying;
@@ -46,6 +47,10 @@ List<MatchNearProjection> findNear(
4647
@Param("sportsName") String sportsName
4748
);
4849

50+
// 구장 기반 모집 중 매칭 목록 (OPEN/FULL, 미래 일정만)
51+
List<MatchRoom> findByFacilityIdAndStatusInAndScheduledAtAfterOrderByScheduledAtAsc(
52+
Long facilityId, List<MatchStatus> statuses, java.time.LocalDateTime now);
53+
4954
// scheduledAt이 지난 OPEN/FULL → CLOSED
5055
@Modifying
5156
@Query(value = """

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.be.sportizebe.domain.match.dto.request.MatchNearRequest;
55
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
66
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
7+
import com.be.sportizebe.domain.match.dto.response.MatchParticipantResponse;
78
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
89
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
910

@@ -27,4 +28,8 @@ public interface MatchService {
2728

2829
List<MyMatchResponse> getMyMatches(Long userId); // 참여 중인 매칭 목록
2930

31+
List<MatchParticipantResponse> getMatchParticipants(Long matchId); // 매칭 참가자 목록
32+
33+
List<MatchResponse> getMatchesByFacility(Long facilityId); // 구장 기반 매칭 목록
34+
3035
}

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

Lines changed: 29 additions & 0 deletions
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.MatchParticipantResponse;
67
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
78
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
89
import com.be.sportizebe.domain.match.entity.MatchParticipant;
@@ -23,6 +24,7 @@
2324
import org.springframework.stereotype.Service;
2425
import org.springframework.transaction.annotation.Transactional;
2526
import com.be.sportizebe.domain.match.dto.request.MatchCreateRequest;
27+
import java.time.LocalDateTime;
2628
import java.util.List;
2729
import java.util.Optional;
2830

@@ -165,6 +167,33 @@ public List<MyMatchResponse> getMyMatches(Long userId) {
165167
}
166168

167169
@Override
170+
@Transactional(readOnly = true)
171+
public List<MatchParticipantResponse> getMatchParticipants(Long matchId) {
172+
if (!matchRoomRepository.existsById(matchId)) {
173+
throw new CustomException(MatchErrorCode.MATCH_NOT_FOUND);
174+
}
175+
return matchParticipantRepository
176+
.findAllByMatchRoomIdAndStatusFetch(matchId, MatchParticipantStatus.JOINED)
177+
.stream()
178+
.map(MatchParticipantResponse::from)
179+
.toList();
180+
}
181+
182+
@Override
183+
@Transactional(readOnly = true)
184+
public List<MatchResponse> getMatchesByFacility(Long facilityId) {
185+
return matchRoomRepository
186+
.findByFacilityIdAndStatusInAndScheduledAtAfterOrderByScheduledAtAsc(
187+
facilityId,
188+
List.of(MatchStatus.OPEN, MatchStatus.FULL),
189+
LocalDateTime.now()
190+
)
191+
.stream()
192+
.map(MatchResponse::from)
193+
.toList();
194+
}
195+
196+
@Override
168197
@Transactional(readOnly = true)
169198
public List<MatchNearResponse> getNearMatches(MatchNearRequest request) {
170199
String sportsName = request.getSportsName() == null

0 commit comments

Comments
 (0)