Skip to content
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

[Feature] 지하철 노선에 따라 정렬 방식 다르게 설정 #36

Merged
merged 1 commit into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ public class SpaceInfo extends BaseEntity {
@Schema(description = "S3 이미지 URL")
private List<String> imageURLs;

@Field("station_distance") //! [역이름: 역까지 도보거리]
@Schema(description = "서울 자치구 별 지하철역~공간 도보거리")
private Map<String, Object> walkTime;

public static SpaceInfo createSpaceInfo (PostPlaceRequest placeRequest) {
SpaceInfo spaceInfo = SpaceInfo.builder()
.space(Space.fromValue(placeRequest.getSpaceClass().toString()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface PlaceRepositoryCustom {

OnePlaceInfoResponse findByIdCustom(String id) throws PlaceNotFoundException ;

List<FilteringPlaceResponse> findSpaceByProperties(Space space, String area, String station,
CoordinateDTO stationCoord, FilteringPlaceRequest filteringPlaceRequest);
List<FilteringPlaceResponse> findSpaceByProperties(Space space, String area, String station,
Boolean isMainStation, CoordinateDTO stationCoord, FilteringPlaceRequest filteringPlaceRequest);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -78,35 +80,57 @@ public SpaceInfo savePlace(List<MultipartFile> multipartFile, PostPlaceRequest p
public OnePlaceInfoResponse findByIdCustom(String id) throws PlaceNotFoundException {
SpaceInfo spaceInfo = mongoTemplate.findById(id, SpaceInfo.class);
if (spaceInfo == null) throw new PlaceNotFoundException();
LOGGER.info(spaceInfo);

OnePlaceInfoResponse placeInfoResponse = OnePlaceInfoResponse.createOnePlaceInfoResponse(spaceInfo);
return placeInfoResponse;
}

@Override
public List<FilteringPlaceResponse> findSpaceByProperties(Space space, String area, String station,
CoordinateDTO stationCoord, FilteringPlaceRequest filteringPlaceRequest) {
//* DB에서 필터링 결과 가져오기
Pageable pageable = PageRequest.of(filteringPlaceRequest.getPage(), 100,
Sort.by(Sort.Direction.ASC, "name"));
Query query = new Query().with(pageable);
Boolean isMainStation, CoordinateDTO stationCoord, FilteringPlaceRequest filteringPlaceRequest) {
List<AggregationOperation> pipeline = new ArrayList<>();

List<Criteria> criteria = new ArrayList<>();

//! 1) 카페/무료회의룸/무료공간 필터링
criteria.add(Criteria.where("space").is(space));
pipeline.add(Aggregation.match(Criteria.where("space").is(space)));

//! 2) 지역 필터링
criteria.add(Criteria.where("area").is(area));

query.addCriteria(new Criteria().andOperator(criteria.toArray(new Criteria[criteria.size()])));
List<SpaceInfo> spaceList = mongoTemplate.find(query, SpaceInfo.class);
pipeline.add(Aggregation.match(Criteria.where("area").is(area)));

//! 3-1) station이 01~09호선에 포함되는 경우 도보거리 바로 가져와서 정렬
if (isMainStation) {
pipeline.add(Aggregation.project()
.and("station_distance."+station).as("walkTimeValue") //? 도보거리 정렬
.andInclude("_id", "space_name", "space_distance", "space_headCount", "space_hashTag", "space_roadName", "space_images")
);
pipeline.add(Aggregation.sort(Sort.Direction.ASC, "walkTimeValue"));

} else { //! 3-2) 그 외의 노선인 경우 도보거리 api 요청 후 정렬
pipeline.add(Aggregation.project()
.andInclude("_id", "space_name", "space_distance", "space_headCount", "space_hashTag", "space_roadName", "space_images")
);
pipeline.add(Aggregation.sort(Sort.Direction.ASC, "space_name"));
}

//! Pagination 설정
int page = filteringPlaceRequest.getPage();
int size = 100;
pipeline.add(Aggregation.skip((long) (page * size)));
pipeline.add(Aggregation.limit(size));


//! 거리순 정렬하기
List<SpaceInfo> sortedSpace = sortSpaceByDist(spaceList, station, stationCoord);
TypedAggregation<SpaceInfo> aggregation = Aggregation.newAggregation(SpaceInfo.class, pipeline);
AggregationResults<SpaceInfo> results = mongoTemplate.aggregate(aggregation, SpaceInfo.class);
List<SpaceInfo> spaceList = results.getMappedResults();

//! 1~9 이외의 노선인 경우 따로 API 호출해서 정렬
if (!isMainStation) {
List<SpaceInfo> sortedSpace = sortSpaceByDist2(spaceList, station, stationCoord);
spaceList = sortedSpace;
}

//! DTO 넣기
List<FilteringPlaceResponse> spaceReturnList = new ArrayList<>();
for (SpaceInfo spaceInfo : sortedSpace) {
for (SpaceInfo spaceInfo : spaceList) {
FilteringPlaceResponse placeReturnDTO = new FilteringPlaceResponse();
placeReturnDTO.setId(spaceInfo.getId());
placeReturnDTO.setPlace(spaceInfo.getName());
Expand All @@ -119,45 +143,23 @@ public List<FilteringPlaceResponse> findSpaceByProperties(Space space, String ar
spaceReturnList.add(placeReturnDTO);
}


return spaceReturnList;
}

public List<SpaceInfo> sortSpaceByDist(List<SpaceInfo> spaceList, String station, CoordinateDTO stationCoord) {
Collections.sort(spaceList, new Comparator<SpaceInfo>() {
@Override
public int compare(SpaceInfo space1, SpaceInfo space2) {
//! 각 공간의 위경도 가져오기
CoordinateDTO coordinate1;
CoordinateDTO coordinate2;

try {
coordinate1 = apiLocationToCoord.getCoordByLocation(space1.getLocationRoadName());
coordinate2 = apiLocationToCoord.getCoordByLocation(space2.getLocationRoadName());
} catch (URISyntaxException e) {
throw new KakaoAPIRequestException(ErrorCode.LOCATION_TO_COORDS_FAIL);
}

LOGGER.info("{} {}", coordinate1, coordinate2);
//! 공간과 역의 도보거리
int walkTime1;
int walkTime2;

//* Tmap API 활용해 도보거리 측정
public List<SpaceInfo> sortSpaceByDist2(List<SpaceInfo> spaceList, String station, CoordinateDTO stationCoord) {
return spaceList.stream()
.sorted(Comparator.comparingInt(space -> {
try {
walkTime1 = apiGetWalkingDist.getWalkingDistance(stationCoord, station, coordinate1, space1.getName());
walkTime2 = apiGetWalkingDist.getWalkingDistance(stationCoord, station, coordinate2, space1.getName());
LOGGER.info("{} {}", walkTime1, walkTime2);
CoordinateDTO coordinate = apiLocationToCoord.getCoordByLocation(space.getLocationRoadName());
int walkTime = apiGetWalkingDist.getWalkingDistance(stationCoord, station, coordinate, space.getName());
return walkTime;
} catch (URISyntaxException | JSONException e) {
throw new TmapAPIRequestException(ErrorCode.GET_WALK_DISTANCE_FAIL);
}

int compareResult = Integer.compare(walkTime1, walkTime2);

return compareResult;
// return 1;
}
});

return spaceList;
}))
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -60,11 +61,21 @@ public List<FilteringPlaceResponse> filteringPlace(String placeClass, FilteringP
throw new KakaoAPIRequestException(ErrorCode.COORDS_TO_LOCATION_FAIL);
}

//! 역이 1~9호선에 속하는지 확인
Boolean isMainStation = isStationHasWalkDistance(stations);

if (area == null) return new ArrayList<>(); //! 서울특별시 아닌 경우
return placeRepository.findSpaceByProperties(space, area, filteringPlaceRequest.getStation(),
return placeRepository.findSpaceByProperties(space, area, filteringPlaceRequest.getStation(), isMainStation,
stationCoord, filteringPlaceRequest);
}

public Boolean isStationHasWalkDistance(List<Station> stations) {
String line = stations.get(0).getLine();

return Arrays.asList("01호선", "02호선", "03호선", "04호선", "05호선", "06호선", "07호선", "08호선", "09호선")
.contains(line);
}

public PostPlaceResponse postPlace(List<MultipartFile> multipartFile, PostPlaceRequest placeRequest) throws IOException {
SpaceInfo space = placeRepository.savePlace(multipartFile, placeRequest);

Expand All @@ -84,10 +95,9 @@ public OnePlaceInfoResponse findPlaceInfo(String placeId) {
public String findPlaceLocation(String placeId, int isRoadName) {
SpaceInfo foundPlace = placeRepository.findById(placeId)
.orElseThrow(PlaceNotFoundException::new);
//! 지번 주소일 경우
if(isRoadName == 0) return foundPlace.getLocationRoadName();
//! 도로명 주소일 경우
else return foundPlace.getLocationLotNumber();
String address = (isRoadName == 0) ?
foundPlace.getLocationRoadName() : foundPlace.getLocationLotNumber();
return address;
}

}