Skip to content

Commit ddebd99

Browse files
authored
Refactor: 파티 조회 시 거리 정보 반환 및 API 개선
1 parent d17d8a4 commit ddebd99

File tree

5 files changed

+159
-37
lines changed

5 files changed

+159
-37
lines changed

src/main/java/ita/tinybite/domain/party/controller/PartyController.java

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public ResponseEntity<?> completeRecruitment(
194194
content = @Content
195195
)
196196
})
197-
@PostMapping("{partyId}/participants/{participantId}/approve")
197+
@PostMapping("/{partyId}/participants/{participantId}/approve")
198198
public ResponseEntity<Void> approveParticipant(
199199
@PathVariable Long partyId,
200200
@PathVariable Long participantId,
@@ -262,7 +262,7 @@ public ResponseEntity<Void> rejectParticipant(
262262
content = @Content
263263
)
264264
})
265-
@GetMapping("{partyId}/chat/group")
265+
@GetMapping("/{partyId}/chat/group")
266266
public ResponseEntity<ChatRoomResponse> getGroupChatRoom(
267267
@PathVariable Long partyId,
268268
@Parameter(hidden = true) @AuthenticationPrincipal Long userId) {
@@ -285,7 +285,7 @@ public ResponseEntity<ChatRoomResponse> getGroupChatRoom(
285285
content = @Content
286286
)
287287
})
288-
@GetMapping("{partyId}/can-settle")
288+
@GetMapping("/{partyId}/can-settle")
289289
public ResponseEntity<Boolean> canSettle(@PathVariable Long partyId) {
290290
boolean canSettle = partyService.canSettle(partyId);
291291
return ResponseEntity.ok(canSettle);
@@ -319,7 +319,7 @@ public ResponseEntity<Boolean> canSettle(@PathVariable Long partyId) {
319319
content = @Content
320320
)
321321
})
322-
@PostMapping("{partyId}/settle")
322+
@PostMapping("/{partyId}/settle")
323323
public ResponseEntity<Void> settleParty(
324324
@PathVariable Long partyId,
325325
@Parameter(hidden = true) @AuthenticationPrincipal Long userId) {
@@ -352,7 +352,7 @@ public ResponseEntity<Void> settleParty(
352352
content = @Content
353353
)
354354
})
355-
@GetMapping("{partyId}/participants/pending")
355+
@GetMapping("/{partyId}/participants/pending")
356356
public ResponseEntity<List<PartyParticipant>> getPendingParticipants(
357357
@PathVariable Long partyId,
358358
@Parameter(hidden = true) @AuthenticationPrincipal Long userId) {
@@ -365,6 +365,27 @@ public ResponseEntity<List<PartyParticipant>> getPendingParticipants(
365365
/**
366366
* 파티 목록 조회 (홈 화면)
367367
*/
368+
@Operation(
369+
summary = "파티 목록 조회",
370+
description = "홈 화면에서 파티 목록을 조회합니다. 카테고리별 필터링, 정렬, 위치 기반 조회를 지원합니다."
371+
)
372+
@ApiResponses({
373+
@ApiResponse(
374+
responseCode = "200",
375+
description = "조회 성공",
376+
content = @Content(schema = @Schema(implementation = PartyListResponse.class))
377+
),
378+
@ApiResponse(
379+
responseCode = "400",
380+
description = "잘못된 요청 (위치 정보 형식 오류)",
381+
content = @Content
382+
),
383+
@ApiResponse(
384+
responseCode = "401",
385+
description = "인증 실패",
386+
content = @Content
387+
)
388+
})
368389
@GetMapping
369390
public ResponseEntity<PartyListResponse> getPartyList(
370391
@Parameter(hidden = true) @AuthenticationPrincipal Long userId,
@@ -380,9 +401,6 @@ public ResponseEntity<PartyListResponse> getPartyList(
380401
) {
381402
Double lat = null;
382403
Double lon = null;
383-
// if (userLat == null || userLon == null) {
384-
// throw new IllegalArgumentException("거리순 정렬을 위해서는 현재 위치 정보가 필요합니다.");
385-
// }
386404

387405
if (latitude != null && longitude != null) {
388406
try {
@@ -577,6 +595,18 @@ public ResponseEntity<Void> deleteParty(
577595
몇 번째 페이지 인지 (page), 한 페이지 당 몇 개의 파티를 조회할 지 (size) 파라미터로 입력해주시면 됩니다.
578596
"""
579597
)
598+
@ApiResponses({
599+
@ApiResponse(
600+
responseCode = "200",
601+
description = "검색 성공",
602+
content = @Content(schema = @Schema(implementation = PartyQueryListResponse.class))
603+
),
604+
@ApiResponse(
605+
responseCode = "400",
606+
description = "잘못된 요청 (검색어 누락)",
607+
content = @Content
608+
)
609+
})
580610
@GetMapping("/search")
581611
public APIResponse<PartyQueryListResponse> getParty(
582612
@RequestParam String q,
@@ -602,6 +632,17 @@ public APIResponse<PartyQueryListResponse> getParty(
602632
한 번에 20개가 조회됩니다.
603633
"""
604634
)
635+
@ApiResponses({
636+
@ApiResponse(
637+
responseCode = "200",
638+
description = "조회 성공"
639+
),
640+
@ApiResponse(
641+
responseCode = "401",
642+
description = "인증 실패",
643+
content = @Content
644+
)
645+
})
605646
@GetMapping("/search/log")
606647
public APIResponse<List<String>> getRecentLog() {
607648
return success(partySearchService.getLog());
@@ -614,6 +655,17 @@ public APIResponse<List<String>> getRecentLog() {
614655
이때 검색어에 대한 Id값은 없고, 최근 검색어 자체를 keyword에 넣어주시면 됩니다.
615656
"""
616657
)
658+
@ApiResponses({
659+
@ApiResponse(
660+
responseCode = "200",
661+
description = "삭제 성공"
662+
),
663+
@ApiResponse(
664+
responseCode = "401",
665+
description = "인증 실패",
666+
content = @Content
667+
)
668+
})
617669
@DeleteMapping("/search/log/{keyword}")
618670
public APIResponse<?> deleteRecentLog(@PathVariable String keyword) {
619671
partySearchService.deleteLog(keyword);
@@ -626,6 +678,17 @@ public APIResponse<?> deleteRecentLog(@PathVariable String keyword) {
626678
특정 유저에 대한 모든 최근 검색어를 삭제합니다.
627679
"""
628680
)
681+
@ApiResponses({
682+
@ApiResponse(
683+
responseCode = "200",
684+
description = "전체 삭제 성공"
685+
),
686+
@ApiResponse(
687+
responseCode = "401",
688+
description = "인증 실패",
689+
content = @Content
690+
)
691+
})
629692
@DeleteMapping("/search/log")
630693
public APIResponse<?> deleteRecentLogAll() {
631694
partySearchService.deleteAllLog();

src/main/java/ita/tinybite/domain/party/dto/response/PartyCardResponse.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,36 @@ public class PartyCardResponse {
2828
private LocalDateTime createdAt;
2929

3030
public static PartyCardResponse from(Party party, int currentParticipants) {
31+
return from(party, currentParticipants, null, null);
32+
}
33+
34+
public static PartyCardResponse from(Party party, int currentParticipants, Double userLat, Double userLon) {
35+
String distanceValue = null;
36+
String distanceKmValue = null;
37+
38+
// 거리 계산
39+
if (userLat != null && userLon != null
40+
&& party.getPickupLocation() != null
41+
&& party.getPickupLocation().getPickupLatitude() != null
42+
&& party.getPickupLocation().getPickupLongitude() != null) {
43+
double distance = DistanceCalculator.calculateDistance(
44+
userLat,
45+
userLon,
46+
party.getPickupLocation().getPickupLatitude(),
47+
party.getPickupLocation().getPickupLongitude()
48+
);
49+
distanceKmValue = DistanceCalculator.formatDistance(distance);
50+
distanceValue = Double.toString(distance);
51+
}
52+
3153
return PartyCardResponse.builder()
3254
.partyId(party.getId())
3355
.thumbnailImage(party.getThumbnailImage())
3456
.title(party.getTitle())
3557
.pricePerPerson(calculatePricePerPerson(party, currentParticipants))
3658
.participantStatus(formatParticipantStatus(currentParticipants, party.getMaxParticipants()))
37-
.distance(null) // 거리 계산은 별도 처리 필요
38-
.distanceKm(null) // 거리 계산은 별도 처리 필요
59+
.distance(distanceValue)
60+
.distanceKm(distanceKmValue)
3961
.timeAgo(calculateTimeAgo(party.getCreatedAt()))
4062
.isClosed(checkIfClosed(party, currentParticipants))
4163
.category(party.getCategory())

src/main/java/ita/tinybite/domain/party/service/PartyService.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ public PartyListResponse getPartyList(Long userId, PartyListRequest request) {
143143
int page = request.getPage() != null ? request.getPage() : 0;
144144
int size = request.getSize() != null ? request.getSize() : 20;
145145

146-
// String myTown = getMyTown(request.getUserLat(),request.getUserLon());
146+
String myTown = getMyTown(request.getUserLat(),request.getUserLon());
147147

148148
// 동네 기준으로 파티 조회
149-
List<Party> parties = fetchPartiesByTown(user, request);
149+
List<Party> parties = fetchPartiesByTown(user, request, myTown);
150150

151151
// PartyCardResponse로 변환
152152
List<PartyCardResponse> cardResponses = parties.stream()
@@ -234,7 +234,7 @@ public PartyDetailResponse getPartyDetail(Long partyId, Long userId, Double user
234234

235235
// 거리 계산 (사용자 위치 필요)
236236
double distance = 0.0;
237-
if (validateLocation(user,userLat, userLon,party)) {
237+
if (validateLocation(userLat, userLon, party)) {
238238
distance = DistanceCalculator.calculateDistance(
239239
userLat,
240240
userLon,
@@ -246,12 +246,12 @@ public PartyDetailResponse getPartyDetail(Long partyId, Long userId, Double user
246246
return convertToDetailResponse(party, distance, isParticipating);
247247
}
248248

249-
private boolean validateLocation(User user, Double userLat, Double userLon, Party party) {
250-
return (user != null
251-
&& userLat != null
252-
&& userLon!= null
253-
&& party.getPickupLocation().getPickupLatitude()!= null
254-
&& party.getPickupLocation().getPickupLongitude()!=null);
249+
private boolean validateLocation(Double userLat, Double userLon, Party party) {
250+
return (userLat != null
251+
&& userLon != null
252+
&& party.getPickupLocation() != null
253+
&& party.getPickupLocation().getPickupLatitude() != null
254+
&& party.getPickupLocation().getPickupLongitude() != null);
255255
}
256256

257257
/**
@@ -301,6 +301,7 @@ public Long joinParty(Long partyId, Long userId) {
301301
/**
302302
* 파티 탈퇴 - 인원 감소 시 다시 모집 중으로 변경
303303
*/
304+
@Transactional
304305
public void leaveParty(Long partyId, Long userId) {
305306
Party party = partyRepository.findById(partyId)
306307
.orElseThrow(() -> new IllegalArgumentException("파티를 찾을 수 없습니다."));
@@ -373,8 +374,6 @@ private PartyCardResponse convertToCardResponse(Party party,
373374
.title(party.getTitle())
374375
.pricePerPerson(pricePerPerson)
375376
.participantStatus(participantStatus)
376-
// .distance(DistanceCalculator.formatDistance(distanceKm))
377-
// .distanceKm(distanceKm)
378377
.timeAgo(party.getTimeAgo())
379378
.isClosed(party.getIsClosed())
380379
.category(party.getCategory())
@@ -445,20 +444,27 @@ public void updateParty(Long partyId, Long userId, PartyUpdateRequest request) {
445444
);
446445
} else {
447446
// 승인된 파티원이 없는 경우, 호스트 혼자인 경우: 모든 항목 수정 가능
447+
PickupLocation updatedPickupLocation = getPickUpLocationIfExists(request, party);
448448
party.updateAllFields(
449449
request.getTitle(),
450450
request.getTotalPrice(),
451451
request.getMaxParticipants(),
452-
getPickUpLocationIfExists(request, party),
452+
updatedPickupLocation,
453453
request.getProductLink(),
454454
request.getDescription(),
455455
request.getImages()
456456
);
457457

458-
// 주어진 좌표로 법정동 반환
459-
String location = locationService.getLocation(request.getPickupLocation().getPickupLatitude().toString(), request.getPickupLocation().getPickupLongitude().toString());
460-
// place는 pickupLocation, locaton은 town에 저장
461-
party.updatePartyLocation(request.getPickupLocation(), location);
458+
// pickupLocation이 변경된 경우에만 town 업데이트
459+
if (request.getPickupLocation() != null
460+
&& request.getPickupLocation().getPickupLatitude() != null
461+
&& request.getPickupLocation().getPickupLongitude() != null) {
462+
String location = locationService.getLocation(
463+
request.getPickupLocation().getPickupLatitude().toString(),
464+
request.getPickupLocation().getPickupLongitude().toString()
465+
);
466+
party.updatePartyLocation(updatedPickupLocation, location);
467+
}
462468
}
463469
}
464470
private PickupLocation getPickUpLocationIfExists(PartyUpdateRequest request, Party currentParty) {
@@ -813,7 +819,7 @@ private String formatDistanceIfExists(Double distance) {
813819
}
814820

815821
//카테고리에 따라 파티 조회
816-
private List<Party> fetchPartiesByTown(User user, PartyListRequest request) {
822+
private List<Party> fetchPartiesByTown(User user, PartyListRequest request,String myTown) {
817823
if (user == null || user.getLocation() == null) {
818824
return List.of();
819825
}
@@ -831,8 +837,11 @@ private List<Party> fetchPartiesByTown(User user, PartyListRequest request) {
831837
// 정렬 기준에 따른 Comparator 반환
832838
private Comparator<PartyCardResponse> getComparator(PartySortType sortType) {
833839
if (sortType == PartySortType.DISTANCE) {
834-
// 거리 가까운 순
835-
return Comparator.comparing(PartyCardResponse::getDistanceKm)
840+
// 거리 가까운 순 (null은 맨 뒤로)
841+
return Comparator.comparing(
842+
PartyCardResponse::getDistanceKm,
843+
Comparator.nullsLast(Comparator.naturalOrder())
844+
)
836845
.thenComparing((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt()));
837846
} else {
838847
// 최신순 (createdAt 내림차순)
@@ -849,6 +858,9 @@ private PartyCardResponse convertToCardResponseWithDistance(
849858
}
850859

851860
private String getMyTown(Double pickupLatitude, Double pickupLongitude) {
861+
if (pickupLatitude == null || pickupLongitude == null) {
862+
return null;
863+
}
852864
return locationService.getLocation(Double.toString(pickupLatitude), Double.toString(pickupLongitude));
853865
}
854866
}

src/main/java/ita/tinybite/domain/user/controller/UserController.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,17 @@ public APIResponse<RejoinValidationResponse> validateRejoin(
132132
})
133133
@GetMapping("/parties/hosting")
134134
public ResponseEntity<List<PartyCardResponse>> getHostingParties(
135-
@AuthenticationPrincipal Long userId) {
136-
List<PartyCardResponse> response = userService.getHostingParties(userId);
135+
@AuthenticationPrincipal Long userId,
136+
@Parameter(description = "사용자 위도") @RequestParam(required = false) Double latitude,
137+
@Parameter(description = "사용자 경도") @RequestParam(required = false) Double longitude) {
138+
List<PartyCardResponse> response = userService.getHostingParties(userId, latitude, longitude);
137139
return ResponseEntity.ok(response);
138140
}
139141

142+
@Operation(
143+
summary = "참가 중인 파티 목록 조회",
144+
description = "현재 사용자가 참가자로 있는 활성 파티 목록을 조회합니다. (호스트 제외)"
145+
)
140146
@ApiResponses({
141147
@ApiResponse(
142148
responseCode = "200",
@@ -153,8 +159,10 @@ public ResponseEntity<List<PartyCardResponse>> getHostingParties(
153159
})
154160
@GetMapping("/parties/participating")
155161
public ResponseEntity<List<PartyCardResponse>> getParticipatingParties(
156-
@AuthenticationPrincipal Long userId) {
157-
List<PartyCardResponse> response = userService.getParticipatingParties(userId);
162+
@AuthenticationPrincipal Long userId,
163+
@Parameter(description = "사용자 위도") @RequestParam(required = false) Double latitude,
164+
@Parameter(description = "사용자 경도") @RequestParam(required = false) Double longitude) {
165+
List<PartyCardResponse> response = userService.getParticipatingParties(userId, latitude, longitude);
158166
return ResponseEntity.ok(response);
159167
}
160168

0 commit comments

Comments
 (0)