-
Notifications
You must be signed in to change notification settings - Fork 3
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
[BE] refactor: 발자국 리팩터링 #92
Changes from 7 commits
9dbc53a
1c73276
f4eb4df
51fb137
feec061
117b737
cd088ae
e1b21fb
9eff84d
af6464b
b7ec36e
231cc29
d4e8569
a4b9402
504b713
a12912a
39baf3c
4e350b1
451caa7
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 | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,7 @@ | ||||||
package com.woowacourse.friendogly.footprint.domain; | ||||||
|
||||||
import static java.lang.Math.*; | ||||||
|
||||||
import jakarta.persistence.Embeddable; | ||||||
import lombok.AccessLevel; | ||||||
import lombok.AllArgsConstructor; | ||||||
|
@@ -12,32 +14,19 @@ | |||||
@AllArgsConstructor | ||||||
public class Location { | ||||||
|
||||||
private static final int BOUNDARY_RADIUS_METER = 1000; | ||||||
|
||||||
private double latitude; | ||||||
private double longitude; | ||||||
Comment on lines
22
to
23
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. 약어만 사용하거나, 정확한 표현만 사용하거나 둘 중 하나로 통일하면 좋겠어요. 추가로 약어를 사용하는게 과연 좋을지 잘 모르겠어요. 또 여러 개발자들과 협업하는 상황에서는 인지 비용을 줄이기 위해서라도 정확한 표현을 사용하는 것이 좋지 않을까 생각합니다. 쿼리 파라미터에서도 사용될 표현이기 때문에 안드로이드 크루들도 인지해야 한다는 점 또한 고려해야겠네요. 개인적으로, 적어도 협업에 있어서는 개발의 간편함 보다는 이해하기 쉬운 코드를 작성하는 것이 더 높은 우선순위를 가져야하지 않나 싶습니다. 투기장 오픈, 아무나 참전 가능(1/8) 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. query parameter를 짧게 가져가고 싶은 욕심이 있었는데, 일관성까지 챙기기는 확실히 어렵네요. |
||||||
|
||||||
public boolean isNear(Location other) { | ||||||
return distance(this.latitude, this.longitude, other.latitude, other.longitude) <= BOUNDARY_RADIUS_METER; | ||||||
public boolean isWithin(Location other, int radius) { | ||||||
return distanceAsMeter(other) <= radius; | ||||||
} | ||||||
|
||||||
private double distance(double lat1, double lon1, double lat2, double lon2) { | ||||||
double theta = lon1 - lon2; | ||||||
double dist = Math.sin(degToRad(lat1)) * Math.sin(degToRad(lat2)) + | ||||||
Math.cos(degToRad(lat1)) * Math.cos(degToRad(lat2)) * Math.cos(degToRad(theta)); | ||||||
|
||||||
dist = Math.acos(dist); | ||||||
dist = radToDeg(dist); | ||||||
dist = dist * 60 * 1.1515 * 1609.344; | ||||||
|
||||||
return Math.abs(dist); | ||||||
} | ||||||
|
||||||
private double degToRad(double deg) { | ||||||
return (deg * Math.PI / 180.0); | ||||||
} | ||||||
private double distanceAsMeter(Location other) { | ||||||
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.
Suggested change
메서드명은 동사로 시작하는게 좋겠습니당 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. 동사로 통일!! 👍 |
||||||
double theta = this.longitude - other.longitude; | ||||||
double dist = sin(toRadians(this.latitude)) * sin(toRadians(other.latitude)) + | ||||||
cos(toRadians(this.latitude)) * cos(toRadians(other.latitude)) * cos(toRadians(theta)); | ||||||
|
||||||
private double radToDeg(double rad) { | ||||||
return (rad * 180 / Math.PI); | ||||||
dist = toDegrees(acos(dist)); | ||||||
return abs(dist * 60 * 1.1515 * 1609.344); | ||||||
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. 이 부분은 어차피 공식이 워낙 복잡해서 하나의 메서드로 가져가도 될 것 같아요...! |
||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
package com.woowacourse.friendogly.footprint.dto.request; | ||
|
||
public record FindNearFootprintRequest(double latitude, double longitude) { | ||
public record FindNearFootprintRequest(double lat, double lng) { | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ public class FootprintCommandService { | |
|
||
public Long save(SaveFootprintRequest request) { | ||
Member member = memberRepository.findById(request.memberId()) | ||
.orElseThrow(() -> new IllegalArgumentException("멤버 없음")); | ||
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사용자 ID입니다.")); | ||
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. #93 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. 이 부분도 저희 커스텀 예외 만들어둔걸로 대체해주세요.! 예외처리 repo로 내리는건 추후에 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. 반영했습니다 👍 |
||
|
||
Footprint footprint = footprintRepository.save( | ||
Footprint.builder() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,15 +16,15 @@ | |
@RequiredArgsConstructor | ||
public class FootprintQueryService { | ||
|
||
private static final int HOURS_AGO = 24; | ||
private static final int FOOTPRINT_REMAIN_HOURS = 24; | ||
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 FootprintRepository footprintRepository; | ||
|
||
public List<FindNearFootprintResponse> findNear(FindNearFootprintRequest request) { | ||
LocalDateTime since = LocalDateTime.now().minusHours(HOURS_AGO); | ||
List<Footprint> recentFootprints = footprintRepository.findByCreatedAtAfter(since); | ||
LocalDateTime startTime = LocalDateTime.now().minusHours(FOOTPRINT_REMAIN_HOURS); | ||
List<Footprint> recentFootprints = footprintRepository.findByCreatedAtAfter(startTime); | ||
|
||
Location currentLocation = new Location(request.latitude(), request.longitude()); | ||
Location currentLocation = new Location(request.lat(), request.lng()); | ||
|
||
return recentFootprints.stream() | ||
.filter(footprint -> footprint.isNear(currentLocation)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package com.woowacourse.friendogly.footprint.controller; | ||
|
||
import static org.mockito.BDDMockito.given; | ||
import static org.springframework.http.HttpHeaders.LOCATION; | ||
import static org.springframework.http.MediaType.APPLICATION_JSON; | ||
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; | ||
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; | ||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; | ||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; | ||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; | ||
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; | ||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; | ||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; | ||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; | ||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; | ||
import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.woowacourse.friendogly.footprint.dto.request.FindNearFootprintRequest; | ||
import com.woowacourse.friendogly.footprint.dto.request.SaveFootprintRequest; | ||
import com.woowacourse.friendogly.footprint.dto.response.FindNearFootprintResponse; | ||
import com.woowacourse.friendogly.footprint.service.FootprintCommandService; | ||
import com.woowacourse.friendogly.footprint.service.FootprintQueryService; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
|
||
@AutoConfigureRestDocs | ||
@WebMvcTest(FootprintController.class) | ||
class FootprintControllerTest { | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@Autowired | ||
private ObjectMapper objectMapper; | ||
|
||
@MockBean | ||
private FootprintCommandService footprintCommandService; | ||
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. 이거 RestDocs Base 코드 있어요. 추상 클래스라서 예시 Member 문서 테스트 참고해서 다시 작성해주시면 감사하겠습니다. |
||
|
||
@MockBean | ||
private FootprintQueryService footprintQueryService; | ||
|
||
@DisplayName("발자국 저장") | ||
@Test | ||
void save() throws Exception { | ||
SaveFootprintRequest request = new SaveFootprintRequest(1L, 37.5173316, 127.1011661); | ||
|
||
given(footprintCommandService.save(request)) | ||
.willReturn(1L); | ||
|
||
mockMvc | ||
.perform(post("/footprints") | ||
.content(objectMapper.writeValueAsString(request)) | ||
.contentType(APPLICATION_JSON)) | ||
.andDo(print()) | ||
.andDo(document("footprints/save", | ||
preprocessRequest(prettyPrint()), | ||
preprocessResponse(prettyPrint()), | ||
requestFields( | ||
fieldWithPath("memberId").description("사용자 ID"), | ||
fieldWithPath("latitude").description("현재 위치의 위도"), | ||
fieldWithPath("longitude").description("현재 위치의 경도") | ||
), | ||
responseHeaders( | ||
headerWithName(LOCATION).description("Location") | ||
) | ||
)) | ||
.andExpect(status().isCreated()) | ||
.andExpect(header().string(LOCATION, "/footprints/1")); | ||
} | ||
|
||
@DisplayName("주변 발자국 조회") | ||
@Test | ||
void findNear() throws Exception { | ||
FindNearFootprintRequest request = new FindNearFootprintRequest(37.5173316, 127.1011661); | ||
|
||
given(footprintQueryService.findNear(request)) | ||
.willReturn( | ||
List.of( | ||
new FindNearFootprintResponse(1L, 37.5136533, 127.0983182, LocalDateTime.now().minusMinutes(10)), | ||
new FindNearFootprintResponse(3L, 37.5131474, 127.1042528, LocalDateTime.now().minusMinutes(20)), | ||
new FindNearFootprintResponse(6L, 37.5171728, 127.1047797, LocalDateTime.now().minusMinutes(30)), | ||
new FindNearFootprintResponse(11L, 37.516183, 127.1068874, LocalDateTime.now().minusMinutes(40)) | ||
) | ||
); | ||
|
||
mockMvc | ||
.perform(get("/footprints/near") | ||
.param("lat", "37.5173316") | ||
.param("lng", "127.1011661")) | ||
.andDo(print()) | ||
.andDo(document("footprints/near", | ||
preprocessRequest(prettyPrint()), | ||
preprocessResponse(prettyPrint()), | ||
queryParameters( | ||
parameterWithName("lat").description("현재 위치의 위도"), | ||
parameterWithName("lng").description("현재 위치의 경도") | ||
), | ||
responseFields( | ||
fieldWithPath("[].memberId").description("발자국을 찍은 사용자 ID"), | ||
fieldWithPath("[].latitude").description("발자국 위치의 위도"), | ||
fieldWithPath("[].longitude").description("발자국 위치의 경도"), | ||
fieldWithPath("[].createdAt").description("발자국 생성 시간") | ||
) | ||
)) | ||
.andExpect(status().isOk()); | ||
} | ||
} |
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.
reformat 단축키 누르니까 잘 되네요 ,...!