-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
반경 내 주차장 조회 기능 구현 #13
Changes from 26 commits
f44658b
43ca5c9
85f7423
7674fc9
c1fa2c3
ba3c449
97ce588
c4fad88
0372e0d
d399ab5
3469889
7f49f6d
6288499
35a5747
2d059a8
592b1c7
f8b4dbd
d33ee40
44ae717
28ce548
6b7459f
d5ca66d
4c780fc
5f608cc
d008f2e
0035310
227cf26
a4dc6a1
84b1100
2973615
9d03477
1f31077
6c04212
b35c425
f1fa25b
3b9d046
9d5693e
dfac844
4528710
5362f5d
03dcdd3
fc15e7e
7b48ca1
4fe6e61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.example.parking.api.parking; | ||
|
||
import com.example.parking.application.parking.ParkingService; | ||
import com.example.parking.application.parking.dto.ParkingLotsResponse; | ||
import com.example.parking.application.parking.dto.ParkingQueryRequest; | ||
import com.example.parking.application.parking.dto.ParkingSearchConditionRequest; | ||
import com.example.parking.config.argumentresolver.parking.ParkingMemberId; | ||
import com.example.parking.config.argumentresolver.parking.ParkingQuery; | ||
import com.example.parking.config.argumentresolver.parking.ParkingSearchCondition; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
public class ParkingController { | ||
|
||
private final ParkingService parkingService; | ||
|
||
@GetMapping("/parkings") | ||
public ResponseEntity<ParkingLotsResponse> find( | ||
@ParkingQuery ParkingQueryRequest parkingQueryRequest, | ||
@ParkingSearchCondition ParkingSearchConditionRequest parkingSearchConditionRequest, | ||
@ParkingMemberId Long parkingMemberId | ||
) { | ||
ParkingLotsResponse parkingLots = parkingService.findParkingLots(parkingQueryRequest, | ||
parkingSearchConditionRequest, parkingMemberId); | ||
return ResponseEntity.ok(parkingLots); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.example.parking.application.parking; | ||
|
||
import com.example.parking.application.parking.dto.ParkingLotsResponse.ParkingResponse; | ||
import com.example.parking.domain.favorite.Favorite; | ||
import com.example.parking.domain.parking.Fee; | ||
import com.example.parking.domain.parking.FilterCondition; | ||
import com.example.parking.domain.parking.Location; | ||
import com.example.parking.domain.parking.Parking; | ||
import com.example.parking.domain.parking.ParkingFeeCalculator; | ||
import com.example.parking.support.Association; | ||
import java.time.LocalDateTime; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Component; | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
public class ParkingDomainService { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 조회 조건에 맞게 필터링하는 절차지향적인 로직이라 별도의 Service 를 만들어서 ParkingService 를 조금 더 간결하게 해보려고 했는데 ParkingService 내부 private 메서드로 수정하는게 더 나을까요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일단 제가 의도한건 Application Service 가 더 맞는거같아서 네이밍 수정할게요~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. List 을 응답 dto 로 만들기 위해서 예상 요금, 도보 시간 계산, 즐겨 찾기 유무 확인해서 만드는 로직이 절차지향적이라 이 메서드를 ParkingService 의 private 메서드로 옮길지 ParkingApplicationService 에 둘지 계속 고민되네여,, 뭐가 더 괜찮아보이시나여? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 새로 서비스를 나눠서 구현한건 좋은 거 같습니다. |
||
private final ParkingFeeCalculator parkingFeeCalculator; | ||
|
||
public List<Parking> filterByCondition(List<Parking> parkingLots, FilterCondition filterCondition) { | ||
return parkingLots.stream() | ||
.filter(parking -> parking.containsOperationType(filterCondition.getOperationTypes())) | ||
.filter(parking -> parking.containsParkingType(filterCondition.getParkingTypes())) | ||
.filter(parking -> parking.containsPayType(filterCondition.getPayTypes())) | ||
.toList(); | ||
} | ||
|
||
public List<ParkingResponse> calculateParkingInfo(List<Parking> parkingLots, int hours, | ||
Location destination, List<Favorite> memberFavorites) { | ||
Set<Long> favoriteParkingIds = extractFavoriteParkingIds(memberFavorites); | ||
return extractParkingInfo(parkingLots, destination, hours, favoriteParkingIds); | ||
} | ||
|
||
private List<ParkingResponse> extractParkingInfo(List<Parking> parkingLots, Location destination, int hours, | ||
Set<Long> favoriteParkingIds) { | ||
LocalDateTime now = LocalDateTime.now(); | ||
|
||
List<ParkingResponse> parkingResponses = new ArrayList<>(); | ||
for (Parking parking : parkingLots) { | ||
Fee fee = parkingFeeCalculator.calculateParkingFee(parking, now, now.plusHours(hours)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저의 사랑스러운 아이가 들어가 있군요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 야무지더라구요 |
||
int walkingTime = parking.calculateWalkingTime(destination); | ||
ParkingResponse parkingResponse = toParkingResponse( | ||
parking, | ||
fee, | ||
walkingTime, | ||
favoriteParkingIds.contains(parking.getId()) | ||
); | ||
parkingResponses.add(parkingResponse); | ||
} | ||
return parkingResponses; | ||
} | ||
|
||
private Set<Long> extractFavoriteParkingIds(List<Favorite> memberFavorites) { | ||
return memberFavorites.stream() | ||
.map(Favorite::getParkingId) | ||
.map(Association::getId) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
private ParkingResponse toParkingResponse(Parking parking, Fee fee, int walkingTime, boolean isFavorite) { | ||
return new ParkingResponse( | ||
parking.getId(), | ||
parking.getBaseInformation().getName(), | ||
fee.getFee(), | ||
walkingTime, | ||
parking.getBaseInformation().getParkingType().getDescription(), | ||
isFavorite, | ||
parking.getLocation().getLatitude(), | ||
parking.getLocation().getLongitude() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.example.parking.application.parking.dto; | ||
|
||
import java.util.List; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @NoArgsConstructor(access = AccessLevel.PRIVATE) |
||
public class ParkingLotsResponse { | ||
|
||
private List<ParkingResponse> parkingLots; | ||
|
||
private ParkingLotsResponse() { | ||
} | ||
|
||
public ParkingLotsResponse(List<ParkingResponse> parkingLots) { | ||
this.parkingLots = parkingLots; | ||
} | ||
|
||
@Getter | ||
public static class ParkingResponse { | ||
private Long parkingId; | ||
private String parkingName; | ||
private Integer estimatedFee; | ||
private Integer estimatedWalkingTime; | ||
private String parkingType; | ||
private Boolean isFavorite; | ||
private Double latitude; | ||
private Double longitude; | ||
|
||
private ParkingResponse() { | ||
} | ||
|
||
public ParkingResponse(Long parkingId, String parkingName, Integer estimatedFee, Integer estimatedWalkingTime, | ||
String parkingType, Boolean isFavorite, Double latitude, Double longitude) { | ||
this.parkingId = parkingId; | ||
this.parkingName = parkingName; | ||
this.estimatedFee = estimatedFee; | ||
this.estimatedWalkingTime = estimatedWalkingTime; | ||
this.parkingType = parkingType; | ||
this.isFavorite = isFavorite; | ||
this.latitude = latitude; | ||
this.longitude = longitude; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.example.parking.application.parking.dto; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class ParkingQueryRequest { | ||
|
||
private final Double latitude; | ||
private final Double longitude; | ||
private final Integer radius; | ||
|
||
public ParkingQueryRequest(Double latitude, Double longitude, Integer radius) { | ||
this.latitude = latitude; | ||
this.longitude = longitude; | ||
this.radius = radius; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.example.parking.application.parking.dto; | ||
|
||
import com.example.parking.domain.parking.OperationType; | ||
import com.example.parking.domain.parking.ParkingType; | ||
import com.example.parking.domain.parking.PayType; | ||
import java.util.List; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class ParkingSearchConditionRequest { | ||
|
||
private static final int BASE_HOURS = 1; | ||
private static final String NOT_FREE = "유료"; | ||
private static final String RECOMMEND_ORDER_CONDITION = "추천 순"; | ||
|
||
private final List<String> operationTypes; | ||
private final List<String> parkingTypes; | ||
private final String feeTypes; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 유료, 무료 주차장 둘 다 보는 방법은 없는거야? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요건 제가 놓쳤네염. 감사합니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 적용했습니다~ |
||
private final List<String> payTypes; | ||
private final Integer hours; | ||
private final String priority; | ||
|
||
public ParkingSearchConditionRequest(List<String> operationTypes, List<String> parkingTypes, String feeTypes, | ||
List<String> payTypes, int hours, String priority) { | ||
this.operationTypes = operationTypes; | ||
this.parkingTypes = parkingTypes; | ||
this.feeTypes = feeTypes; | ||
this.payTypes = payTypes; | ||
this.hours = hours; | ||
this.priority = priority; | ||
} | ||
|
||
public static ParkingSearchConditionRequest base() { | ||
return new ParkingSearchConditionRequest( | ||
OperationType.getAllValues(), | ||
ParkingType.getAllValues(), | ||
NOT_FREE, | ||
PayType.getAllValues(), | ||
BASE_HOURS, | ||
RECOMMEND_ORDER_CONDITION | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.example.parking.config.argumentresolver.parking; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.PARAMETER) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ParkingMemberId { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기존의 MemberAuth 는 잘못된 인증 정보면 예외를 던지는데 주차장 조회 기능에선 memberId 가 없으면 즐겨찾기 값을 전부 다 false 로 반환해야됩니다. 그래서 기존 MemberAuth의 잘못된 인증정보 시 예외던지는 코드를 주차장 조회 기능 때문에 null 을 반환하게 하면 MemberAuth 를 사용하고 있는 다른 로직에서 반환된 값의 null 체크를 하고 예외처리를 해야되기 때문에 예외 말고 null 을 반환하도록 새로 만들었습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 같은 목적의 어노테이션을 두개로 늘리기 보다는 @Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface MemberAuth {
boolean required() default true;
} 아규먼트 리졸버에서 required 값을 판단해서 아래처럼 내려주면 될 거 같습니다 @Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
MemberAuth memberAuth = memberAuthFrom(parameter);
if (memberAuth.required()) {
String sessionId = webRequest.getHeader(JSESSIONID);
MemberSession session = authService.findSession(sessionId);
return session.getMemberId();
}
return null;
}
private MemberAuth memberAuthFrom(MethodParameter parameter) {
return parameter.getParameterAnnotation(MemberAuth.class);
} 그러고 회원 정보가 필수가 아닌 컨트롤러에서 적용해주면 될 거 같습니다 @GetMapping("/parkings")
public ResponseEntity<ParkingLotsResponse> find(
@ParkingQuery ParkingQueryRequest parkingQueryRequest,
@ParkingSearchCondition ParkingSearchConditionRequest parkingSearchConditionRequest,
@MemberAuth(required = false) Long memberId
) {
ParkingLotsResponse parkingLots = parkingService.findParkingLots(parkingQueryRequest,
parkingSearchConditionRequest, memberId, LocalDateTime.now());
return ResponseEntity.ok(parkingLots);
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 이건 생각 못했는데 아이디어 감사합니다 ㅎ |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.example.parking.config.argumentresolver.parking; | ||
|
||
import org.springframework.core.MethodParameter; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.bind.support.WebDataBinderFactory; | ||
import org.springframework.web.context.request.NativeWebRequest; | ||
import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
import org.springframework.web.method.support.ModelAndViewContainer; | ||
|
||
@Component | ||
public class ParkingMemberIdArgumentResolver implements HandlerMethodArgumentResolver { | ||
@Override | ||
public boolean supportsParameter(MethodParameter parameter) { | ||
return parameter.hasParameterAnnotation(ParkingMemberId.class); | ||
} | ||
|
||
@Override | ||
public Long resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, | ||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { | ||
return Long.parseLong(webRequest.getParameter("JSESSIONID")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.example.parking.config.argumentresolver.parking; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.PARAMETER) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ParkingQuery { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
먼가 따로 분리해야했을까? 라는 생각이 들긴합니다 ! 이유가 있을까요 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
호이 리뷰에 커멘트 달았슴다~