Skip to content

Commit

Permalink
[BE] feat: 놀이터 등록, 전체 놀이터 위치 조회 API 구현 (#618)
Browse files Browse the repository at this point in the history
  • Loading branch information
ehtjsv2 authored Oct 10, 2024
1 parent f3c00c3 commit 4ee8360
Show file tree
Hide file tree
Showing 19 changed files with 207 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.happy.friendogly.common.ApiResponse;
import com.happy.friendogly.pet.dto.request.SavePetRequest;
import com.happy.friendogly.pet.dto.request.UpdatePetRequest;
import com.happy.friendogly.pet.dto.response.FindPetExistenceResponse;
import com.happy.friendogly.pet.dto.response.FindPetResponse;
import com.happy.friendogly.pet.dto.response.SavePetResponse;
import com.happy.friendogly.pet.service.PetCommandService;
Expand Down Expand Up @@ -72,4 +73,10 @@ public void update(
) {
petCommandService.update(memberId, petId, request, image);
}

@GetMapping("/exists/mine")
public ApiResponse<FindPetExistenceResponse> checkPetExistence(@Auth Long memberId) {
FindPetExistenceResponse response = petQueryService.checkPetExistence(memberId);
return ApiResponse.ofSuccess(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.happy.friendogly.pet.dto.response;

public record FindPetExistenceResponse(
boolean isExistPet
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.happy.friendogly.exception.FriendoglyException;
import com.happy.friendogly.pet.domain.Pet;
import com.happy.friendogly.pet.dto.response.FindPetExistenceResponse;
import com.happy.friendogly.pet.dto.response.FindPetResponse;
import com.happy.friendogly.pet.repository.PetRepository;
import java.util.List;
Expand Down Expand Up @@ -30,4 +31,8 @@ public List<FindPetResponse> findByMemberId(Long memberId) {
.map(FindPetResponse::new)
.toList();
}

public FindPetExistenceResponse checkPetExistence(Long memberId) {
return new FindPetExistenceResponse(petRepository.existsByMemberId(memberId));
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
package com.happy.friendogly.playground.domain;

import static java.lang.Math.abs;
import static java.lang.Math.acos;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;

import com.happy.friendogly.exception.FriendoglyException;
import com.happy.friendogly.utils.GeoCalculator;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
Expand Down Expand Up @@ -47,19 +41,25 @@ private void validate(double latitude, double longitude) {
}

public boolean isWithin(Location other, int radius) {
return calculateDistanceInMeters(other) <= radius;
double distance = GeoCalculator.calculateDistanceInMeters(latitude, longitude, other.latitude, other.longitude);
return distance <= radius;
}

public Location plusLatitudeByMeters(int meters) {
double diffLatitude = GeoCalculator.calculateLatitudeOffset(this.latitude, meters);
return new Location(diffLatitude, this.longitude);
}

private double calculateDistanceInMeters(Location other) {
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));
public Location minusLatitudeByMeters(int meters) {
return plusLatitudeByMeters(-meters);
}

dist = toDegrees(acos(dist));
return degreeToMeter(dist);
public Location plusLongitudeByMeters(int meters) {
double diffLongitude = GeoCalculator.calculateLongitudeOffset(this.latitude, this.longitude, meters);
return new Location(this.latitude, diffLongitude);
}

private double degreeToMeter(double dist) {
return abs(dist * 60 * 1.1515 * 1609.344);
public Location minusLongitudeByMeters(int meters) {
return plusLongitudeByMeters(-meters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,8 @@ public PlaygroundMember(
public boolean equalsMemberId(Long memberId) {
return member.getId().equals(memberId);
}

public boolean isSamePlayground(Playground playground) {
return this.playground.getId().equals(playground.getId());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.happy.friendogly.playground.dto.response;

import com.happy.friendogly.playground.domain.Playground;

public record FindPlaygroundLocationResponse(

Long id,
Expand All @@ -8,4 +10,12 @@ public record FindPlaygroundLocationResponse(
boolean isParticipating
) {

public FindPlaygroundLocationResponse(Playground playground, boolean isParticipating) {
this(
playground.getId(),
playground.getLocation().getLatitude(),
playground.getLocation().getLongitude(),
isParticipating
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public record FindPlaygroundSummaryResponse(
int totalPetCount,
int arrivedPetCount
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ public record SavePlaygroundResponse(
double longitude
) {

public static SavePlaygroundResponse from(Playground playground) {
return new SavePlaygroundResponse(
public SavePlaygroundResponse(Playground playground) {
this(
playground.getId(),
playground.getLocation().getLatitude(),
playground.getLocation().getLongitude()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static List<PlaygroundPetDetail> getListOf(
boolean isMyPet
) {
return pets.stream()
.map(pet -> PlaygroundPetDetail.of(
.map(pet -> new PlaygroundPetDetail(
playgroundMember.getMember().getId(),
pet,
playgroundMember.getMessage(),
Expand All @@ -36,14 +36,14 @@ public static List<PlaygroundPetDetail> getListOf(
.toList();
}

public static PlaygroundPetDetail of(
public PlaygroundPetDetail(
Long memberId,
Pet pet,
String message,
boolean isArrival,
boolean isMine
) {
return new PlaygroundPetDetail(
this(
memberId,
pet.getId(),
pet.getName().getValue(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.happy.friendogly.playground.domain.PlaygroundMember;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

Expand All @@ -13,4 +14,6 @@ public interface PlaygroundMemberRepository extends JpaRepository<PlaygroundMemb
boolean existsByPlaygroundIdAndMemberId(Long playgroundId, Long memberId);

boolean existsByMemberId(Long memberId);

Optional<PlaygroundMember> findByMemberId(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.happy.friendogly.playground.dto.response.SavePlaygroundResponse;
import com.happy.friendogly.playground.repository.PlaygroundMemberRepository;
import com.happy.friendogly.playground.repository.PlaygroundRepository;
import com.happy.friendogly.utils.GeoCalculator;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -19,7 +18,8 @@
@Transactional
public class PlaygroundCommandService {

public static final int PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD = 300;
private static final int PLAYGROUND_RADIUS = 150;
private static final int MAX_NON_OVERLAP_DISTANCE = PLAYGROUND_RADIUS * 2;

private final PlaygroundRepository playgroundRepository;
private final PlaygroundMemberRepository playgroundMemberRepository;
Expand All @@ -45,7 +45,7 @@ public SavePlaygroundResponse save(SavePlaygroundRequest request, Long memberId)
);
playgroundMemberRepository.save(new PlaygroundMember(savedPlayground, member));

return SavePlaygroundResponse.from(savedPlayground);
return new SavePlaygroundResponse(savedPlayground);
}

private void validateExistParticipatingPlayground(Member member) {
Expand All @@ -56,21 +56,21 @@ private void validateExistParticipatingPlayground(Member member) {

private void validateOverlapPlayground(double latitude, double longitude) {
Location location = new Location(latitude, longitude);
double startLatitude = GeoCalculator.calculateLatitudeOffset(latitude,
-PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD);
double endLatitude = GeoCalculator.calculateLatitudeOffset(latitude,
PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD);
double startLongitude = GeoCalculator.calculateLongitudeOffset(latitude, longitude,
-PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD);
double endLongitude = GeoCalculator.calculateLongitudeOffset(latitude, longitude,
PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD);
Location startLatitudeLocation = location.minusLatitudeByMeters(MAX_NON_OVERLAP_DISTANCE);
Location endLatitudeLocation = location.plusLatitudeByMeters(MAX_NON_OVERLAP_DISTANCE);
Location startLongitudeLocation = location.minusLongitudeByMeters(MAX_NON_OVERLAP_DISTANCE);
Location endLongitudeLocation = location.plusLongitudeByMeters(MAX_NON_OVERLAP_DISTANCE);

List<Playground> playgrounds = playgroundRepository.
findAllByLatitudeBetweenAndLongitudeBetween(startLatitude, endLatitude, startLongitude, endLongitude);
List<Playground> playgrounds = playgroundRepository.findAllByLatitudeBetweenAndLongitudeBetween(
startLatitudeLocation.getLatitude(),
endLatitudeLocation.getLatitude(),
startLongitudeLocation.getLongitude(),
endLongitudeLocation.getLongitude()
);

boolean isExistWithinRadius = playgrounds.stream()
.anyMatch(playground -> location.isWithin(playground.getLocation(),
PLAYGROUND_EXCEPTION_DISTANCE_THRESHOLD));
MAX_NON_OVERLAP_DISTANCE));

if (isExistWithinRadius) {
throw new FriendoglyException("생성할 놀이터 범위내에 겹치는 다른 놀이터 범위가 있습니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.happy.friendogly.playground.repository.PlaygroundRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -76,13 +77,18 @@ private int getArrivedPetCount(PlaygroundMember playgroundMember, List<Pet> pets

public List<FindPlaygroundLocationResponse> findLocations(Long memberId) {
List<Playground> playgrounds = playgroundRepository.findAll();
Optional<PlaygroundMember> playgroundMember = playgroundMemberRepository.findByMemberId(memberId);

if (playgroundMember.isPresent()) {
return playgrounds.stream()
.map(playground -> new FindPlaygroundLocationResponse(
playground,
playgroundMember.get().isSamePlayground(playground)
)).toList();
}

return playgrounds.stream()
.map(playground -> new FindPlaygroundLocationResponse(
playground.getId(),
playground.getLocation().getLatitude(),
playground.getLocation().getLongitude(),
playgroundMemberRepository.existsByPlaygroundIdAndMemberId(playground.getId(), memberId)
)).toList();
.map(playground -> new FindPlaygroundLocationResponse(playground, false))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package com.happy.friendogly.utils;

import static java.lang.Math.abs;
import static java.lang.Math.acos;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;

public class GeoCalculator {

private static final double ONE_DEGREE_LATITUDE_METER = 111000.0;
Expand All @@ -17,4 +24,22 @@ public static double calculateLongitudeOffset(double latitude, double longitude,
double longitudeOffset = distanceMeters / oneDegreeLongitudeMeter;
return longitude + longitudeOffset;
}

public static double calculateDistanceInMeters(
double latitude,
double longitude,
double otherLatitude,
double otherLongitude
) {
double theta = longitude - otherLongitude;
double dist = sin(toRadians(latitude)) * sin(toRadians(otherLatitude)) +
cos(toRadians(latitude)) * cos(toRadians(otherLatitude)) * cos(toRadians(theta));

dist = toDegrees(acos(dist));
return degreeToMeter(dist);
}

private static double degreeToMeter(double dist) {
return abs(dist * 60 * 1.1515 * 1609.344);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static com.epages.restdocs.apispec.ResourceDocumentation.parameterWithName;
import static com.epages.restdocs.apispec.ResourceDocumentation.resource;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
Expand All @@ -18,6 +19,7 @@
import com.happy.friendogly.pet.domain.SizeType;
import com.happy.friendogly.pet.dto.request.SavePetRequest;
import com.happy.friendogly.pet.dto.request.UpdatePetRequest;
import com.happy.friendogly.pet.dto.response.FindPetExistenceResponse;
import com.happy.friendogly.pet.dto.response.FindPetResponse;
import com.happy.friendogly.pet.dto.response.SavePetResponse;
import com.happy.friendogly.pet.service.PetCommandService;
Expand Down Expand Up @@ -403,6 +405,37 @@ void update_Success() throws Exception {
);
}

@DisplayName("내 반려견 유무 조회 문서화")
@Test
void findExistMine() throws Exception {

FindPetExistenceResponse response = new FindPetExistenceResponse(true);

Mockito.when(petQueryService.checkPetExistence(anyLong()))
.thenReturn(response);

mockMvc.perform(RestDocumentationRequestBuilders.get("/pets/exists/mine")
.accept(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, getMemberToken()))
.andExpect(status().isOk())
.andDo(MockMvcRestDocumentationWrapper.document("pet-exist-mine",
getDocumentRequest(),
getDocumentResponse(),
resource(ResourceSnippetParameters.builder()
.tag("Pet API")
.summary("내 반려견 유무 조회 API")
.requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("로그인한 회원의 accessToken")
)
.responseFields(
fieldWithPath("isSuccess").type(JsonFieldType.BOOLEAN).description("요청 성공 여부"),
fieldWithPath("data.isExistPet").description("내 반려견 존재 유무")
)
.responseSchema(Schema.schema("FindExistMyPetResponse"))
.build()))
);
}

@Override
protected Object controller() {
return new PetController(petQueryService, petCommandService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void find() throws Exception {
0,
false,
List.of(
PlaygroundPetDetail.of(
new PlaygroundPetDetail(
1L,
dummyPet1,
null,
Expand Down
Loading

0 comments on commit 4ee8360

Please sign in to comment.