diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoApiController.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoApiController.java index 32acd9c6..d86769de 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoApiController.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/controller/KakaoApiController.java @@ -1,7 +1,10 @@ package com.back.web7_9_codecrete_be.domain.location.controller; +import com.back.web7_9_codecrete_be.domain.location.dto.KakaoRouteFeResponse; +import com.back.web7_9_codecrete_be.domain.location.dto.KakaoRouteSectionFeResponse; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoLocalResponse; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoMobilityResponse; +import com.back.web7_9_codecrete_be.domain.location.dto.request.KakaoRouteTransitRequest; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoRouteTransitResponse; import com.back.web7_9_codecrete_be.domain.location.service.KakaoLocalService; import com.back.web7_9_codecrete_be.global.error.code.LocationErrorCode; @@ -16,6 +19,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.List; @Tag(name = "Location - Kakao", description = "카카오 로컬 API 연동(주변 음식점 조회, 좌표→주소 변환) 관련 엔드포인트") @@ -97,6 +101,8 @@ public List navigateGuides( .flatMap(section -> section.getGuides().stream()) .toList(); } + + @GetMapping("/navigate/summary") public KakaoMobilityResponse.Summary navigateSummary( @RequestParam double startX, @@ -119,27 +125,53 @@ public KakaoMobilityResponse.Summary navigateSummary( } + //카카오 자동차 api인데, 경유지가 존재하는 경우에 사용 @PostMapping("/navigate/onlyguide") - public List navigateOnlyGuides( - @RequestParam double startX, - @RequestParam double startY, - @RequestParam double endX, - @RequestParam double endY, - @RequestParam double wayX, - @RequestParam double wayY + public KakaoRouteSectionFeResponse navigateOnlyGuides(@RequestBody KakaoRouteTransitRequest req ) { - KakaoRouteTransitResponse res = kakaoLocalService.NaviSearchTransit(startX, startY, endX, endY, wayX, wayY); - if (res == null || res.getRoutes() == null || res.getRoutes().isEmpty()) { - return List.of(); - } + KakaoRouteTransitResponse res = kakaoLocalService.NaviSearchTransit(req); + KakaoRouteTransitResponse.Route route = res.getRoutes().get(0); - KakaoRouteTransitResponse.Route route0 = res.getRoutes().get(0); + KakaoRouteTransitResponse.Summary summary = route.getSummary(); - return route0.getSections().stream() - .filter(section -> section.getGuides() != null && !section.getGuides().isEmpty()) - .flatMap(section -> section.getGuides().stream()) - .toList(); + List points = new ArrayList<>(); // 출발지, 경유지, 목적지 좌표를 저장 + + points.add(summary.getOrigin()); + points.addAll(summary.getWaypoints()); // Waypoints는 배열이니까 addAll 사용 + points.add(summary.getDestination()); + + + // 구간별 좌표, Distance, Duration 표현 + List sections = new ArrayList<>(); + + for (int i = 0; i < route.getSections().size(); i++) { + KakaoRouteTransitResponse.Section section = route.getSections().get(i); + + sections.add(new KakaoRouteFeResponse( //sections 리스트에 각각의 section 정보들을 추가 + i, + section.getDistance(), + section.getDuration(), + points.get(i), // 출발지 + points.get(i + 1) // 목적지 + )); + } + + // distance전체 합계 + int totalDistance = route.getSections().stream() + .mapToInt(KakaoRouteTransitResponse.Section::getDistance) + .sum(); + + // duration 전체 합계 + int totalDuration = route.getSections().stream() + .mapToInt(KakaoRouteTransitResponse.Section::getDuration) + .sum(); + + return new KakaoRouteSectionFeResponse( + totalDistance, + totalDuration, + sections + ); } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteFeResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteFeResponse.java new file mode 100644 index 00000000..3227877c --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteFeResponse.java @@ -0,0 +1,15 @@ +package com.back.web7_9_codecrete_be.domain.location.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class KakaoRouteFeResponse { //경유지까지의 인덱스, 거리, 시간, 좌표를 나타냄 + private int routeIndex; + private int distance; + private int duration; + private Object from; + private Object to; + +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteSectionFeResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteSectionFeResponse.java new file mode 100644 index 00000000..6b841e9d --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/KakaoRouteSectionFeResponse.java @@ -0,0 +1,13 @@ +package com.back.web7_9_codecrete_be.domain.location.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; +@Data +@AllArgsConstructor +public class KakaoRouteSectionFeResponse { //프론트에서 원하는 전체 거리, 시간, 좌표로, section에서는 경유지를 거치는 값들을 저장 + private int totalDistance; + private int totalDuration; + private List sections; +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/KakaoRouteTransitRequest.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/KakaoRouteTransitRequest.java new file mode 100644 index 00000000..8fbefaee --- /dev/null +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/request/KakaoRouteTransitRequest.java @@ -0,0 +1,43 @@ +package com.back.web7_9_codecrete_be.domain.location.dto.request; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; + +import java.util.List; + +@Data +public class KakaoRouteTransitRequest { //Kakao mobility api에서 경유지 추가 response + + private Origin origin; + private Destination destination; + private List waypoints; + + private String priority; + private String car_fuel; + private boolean car_hipass; + private boolean alternatives; + private boolean road_details; + private boolean summary; + + @Data + public static class Origin { + private double x; + private double y; + private int angle; + } + + @Data + public static class Destination { + private double x; + private double y; + } + + @Data + public static class Waypoint { + private String name; + private double x; + private double y; + } + +} diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoMobilityResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoMobilityResponse.java index c2c191c6..0ce6c998 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoMobilityResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoMobilityResponse.java @@ -6,7 +6,7 @@ import java.util.List; @Getter @AllArgsConstructor -public class KakaoMobilityResponse { +public class KakaoMobilityResponse { //Kakao mobility api에서 전체 response 구조 private List routes; diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoRouteTransitResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoRouteTransitResponse.java index 848a0199..f386508b 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoRouteTransitResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/KakaoRouteTransitResponse.java @@ -1,71 +1,98 @@ package com.back.web7_9_codecrete_be.domain.location.dto.response; -import lombok.Getter; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; + import java.util.List; -@Getter +@Data +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class KakaoRouteTransitResponse { + private String transId; private List routes; - @Getter + @Data + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public static class Route { + private int resultCode; + private String resultMsg; private Summary summary; private List
sections; } - @Getter + @Data + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public static class Summary { private Origin origin; private Destination destination; - private List waypoints; // ✅ 경유지(요청값) - + private List waypoints; private String priority; + private Bound bound; // optional일 수 있음 private Fare fare; - - private int distance; // meters - private int duration; // seconds + private int distance; + private int duration; } - @Getter + @Data public static class Origin { private String name; private double x; private double y; } - @Getter + @Data public static class Destination { private String name; private double x; private double y; } - @Getter + @Data public static class Waypoint { private String name; private double x; private double y; } - @Getter + @Data + public static class Bound { + private double minX; + private double minY; + private double maxX; + private double maxY; + } + + @Data public static class Fare { private int taxi; private int toll; } - @Getter + @Data + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public static class Section { - private List roads; - private List guides; + private int distance; + private int duration; + private Bound bound; // summary=false일 때만 올 수 있음 + private List roads; // summary=false일 때만 올 수 있음 + private List guides; // summary=false일 때만 올 수 있음 } - @Getter + @Data + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public static class Road { + private String name; + private int distance; + private int duration; + private double trafficSpeed; + private int trafficState; private List vertexes; } - @Getter + @Data + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public static class Guide { private String name; private double x; @@ -74,6 +101,6 @@ public static class Guide { private int duration; private int type; private String guidance; - private int road_index; + private int roadIndex; } } diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/TmapSummaryAllResponse.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/TmapSummaryAllResponse.java index 055662e2..33e44d4a 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/TmapSummaryAllResponse.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/dto/response/TmapSummaryAllResponse.java @@ -4,24 +4,21 @@ import java.util.List; @Getter -public class TmapSummaryAllResponse { +public class TmapSummaryAllResponse { // Tmap 대중교통 요약 api response dto private MetaData metaData; - // ===================== metaData ===================== @Getter public static class MetaData { private Plan plan; private RequestParameters requestParameters; } - // ===================== plan ===================== @Getter public static class Plan { private List itineraries; } - // ===================== itineraries ===================== @Getter public static class Itinerary { @@ -35,20 +32,17 @@ public static class Itinerary { private Fare fare; // 요금 정보 } - // ===================== fare ===================== @Getter public static class Fare { private Regular regular; } - // ===================== regular ===================== @Getter public static class Regular { private Currency currency; private int totalFare; // 대중교통 요금 } - // ===================== currency ===================== @Getter public static class Currency { private String symbol; // ₩ @@ -56,11 +50,10 @@ public static class Currency { private String currencyCode; // KRW } - // ===================== requestParameters ===================== @Getter public static class RequestParameters { - private String reqDttm; // 요청 시각 (yyyymmddhhmiss) + private String reqDttm; // 요청 시각 private String startX; // 출발지 경도 private String startY; // 출발지 위도 diff --git a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java index f8d18b48..07df40b7 100644 --- a/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java +++ b/src/main/java/com/back/web7_9_codecrete_be/domain/location/service/KakaoLocalService.java @@ -3,13 +3,14 @@ import com.back.web7_9_codecrete_be.domain.location.dto.KakaoCoordinateResponse; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoLocalResponse; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoMobilityResponse; +import com.back.web7_9_codecrete_be.domain.location.dto.request.KakaoRouteTransitRequest; +//import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoRouteTransitFeResponse; import com.back.web7_9_codecrete_be.domain.location.dto.response.KakaoRouteTransitResponse; import com.back.web7_9_codecrete_be.global.error.code.LocationErrorCode; import com.back.web7_9_codecrete_be.global.error.exception.BusinessException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; -import org.springframework.web.reactive.function.client.WebClient; import java.util.List; @@ -20,6 +21,7 @@ public class KakaoLocalService { private final RestClient kakaoRestClient; private final RestClient kakaoMobilityClient; + // 해당 좌표의 1km 근방에 존재하는 음식점를 거리순으로 나타냄 public List searchNearbyRestaurants(double lat, double lng) { return kakaoRestClient.get() @@ -37,6 +39,8 @@ public List searchNearbyRestaurants(double lat, dou .body(KakaoLocalResponse.class) .getDocuments(); } + + // 해당 좌표의 1km 근방에 존재하는 카페를 거리순으로 나타냄 public List searchNearbyCafes(double lat, double lng) { return kakaoRestClient.get() @@ -55,6 +59,7 @@ public List searchNearbyCafes(double lat, double ln .getDocuments(); } + //좌표를 주소로 변환해주는 api 연동 public String coordinateToAddressName(double lat, double lng) { KakaoCoordinateResponse response = kakaoRestClient.get() @@ -87,6 +92,7 @@ public String coordinateToAddressName(double lat, double lng) { return addressName; } + //카카오 모빌리티에서 전체 응답값 가져오기 public KakaoMobilityResponse NaviSearch(double startX, double startY, double endX, double endY) { KakaoMobilityResponse response = kakaoMobilityClient.get() @@ -109,6 +115,7 @@ public KakaoMobilityResponse NaviSearch(double startX, double startY, double end return response; } + //카카오 자동차에서 summary부분만 가져오기 public KakaoMobilityResponse NaviSearchSummary(double startX, double startY, double endX, double endY) { KakaoMobilityResponse response = kakaoMobilityClient.get() @@ -131,20 +138,27 @@ public KakaoMobilityResponse NaviSearchSummary(double startX, double startY, dou return response; } - public KakaoRouteTransitResponse NaviSearchTransit(double startX, double startY - , double endX, double endY, double wayX, double wayY){ + + //Kakao mobility api에서 경유지가 있을때 + public KakaoRouteTransitResponse NaviSearchTransit(KakaoRouteTransitRequest transitRequest){ + + + //카카오가 원하는 요청값을 만들어주고 보내야함 (필수값들) + KakaoRouteTransitRequest transit = new KakaoRouteTransitRequest(); + transit.setOrigin(transitRequest.getOrigin()); + transit.setDestination(transitRequest.getDestination()); + transit.setWaypoints(transitRequest.getWaypoints()); + + transit.setPriority("TIME"); + transit.setSummary(false); + transit.setCar_fuel("GASOLINE"); + transit.setCar_hipass(false); + KakaoRouteTransitResponse response = kakaoMobilityClient.post() - .uri(uriBuilder -> uriBuilder - .path("/v1/waypoints/directions") - .queryParam("origin", startX + "," + startY) - .queryParam("destination", endX + "," + endY) - .queryParam("waypoints", wayX + "," + wayY) - .queryParam("priority", "TIME") - .queryParam("summary", "false") - .build() - ) + .uri("/v1/waypoints/directions") + .body(transit) .retrieve() - .body(KakaoRouteTransitResponse.class); + .body(KakaoRouteTransitResponse.class); //KakaoRouteTransitResponse로 카카오 자동차 api에서 주는 응답값 return response; } } \ No newline at end of file