Skip to content

Commit

Permalink
Merge pull request #154 from IT-Cotato/feature/153-implement-find-roa…
Browse files Browse the repository at this point in the history
…d-by-google-map-api

Feature/153 implement find road by google map api
  • Loading branch information
yooooonshine authored Jan 13, 2025
2 parents edd7937 + 7030ca6 commit 4ca5cba
Show file tree
Hide file tree
Showing 16 changed files with 461 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package middle_point_search.backend.common.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@ConfigurationProperties(prefix = "google")
public class GoogleProperties {

private String key;
private String keyName;
private String baseUrl;
private Map map;

@Getter
@Setter
public static class Map {

private String distanceMatrixUrl;
private String origin;
private String destination;
private String placeIdUrl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import middle_point_search.backend.common.properties.GoogleProperties;
import middle_point_search.backend.common.properties.JwtProperties;
import middle_point_search.backend.common.properties.KakaoProperties;
import middle_point_search.backend.common.properties.MarketProperties;
Expand All @@ -18,7 +19,8 @@
SecurityProperties.class,
MarketProperties.class,
KakaoProperties.class,
RedisProperties.class
RedisProperties.class,
GoogleProperties.class
})
public class PropertyConfig {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.DefaultUriBuilderFactory;

import io.netty.channel.ChannelOption;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import middle_point_search.backend.common.properties.GoogleProperties;
import middle_point_search.backend.common.properties.KakaoProperties;
import middle_point_search.backend.common.properties.MarketProperties;
import reactor.netty.http.client.HttpClient;
Expand All @@ -20,6 +23,7 @@ public class WebClientConf {

private final MarketProperties marketProperties;
private final KakaoProperties kakaoProperties;
private final GoogleProperties googleProperties;


private HttpClient httpClient = HttpClient.create()
Expand Down Expand Up @@ -48,4 +52,15 @@ public WebClient webClientForKakao() {
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}

@Bean
public WebClient webClientForGoogle() {
return WebClient.builder()
.baseUrl(googleProperties.getBaseUrl())
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
.codecs(configurer -> configurer.defaultCodecs()
.maxInMemorySize(2 * 1024 * 1024)) // 응답 payload가 클 경우 나는 에러 방지, 최대 2MB
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import lombok.RequiredArgsConstructor;
import middle_point_search.backend.common.exception.CustomException;
import middle_point_search.backend.common.properties.GoogleProperties;
import middle_point_search.backend.common.properties.KakaoProperties;
import middle_point_search.backend.common.properties.MarketProperties;
import reactor.core.publisher.Mono;
Expand All @@ -23,13 +24,17 @@ public class WebClientUtil {

private final KakaoProperties kakaoProperties;
private final MarketProperties marketProperties;
private final GoogleProperties googleProperties;

@Qualifier("webClientForMarket")
private final WebClient webClientForMarket;

@Qualifier("webClientForKakao")
private final WebClient webClientForKakao;

@Qualifier("webClientForGoogle")
private final WebClient webClientForGoogle;

// WebClient Conf 세팅을 이용하며, url과 응답 클래스 및 파라미터를 제공하여 요청을 해 Mono로 응답받는 메서드
public <T> T getMarket(String url, MultiValueMap<String, String> params, Class<T> response) {
return webClientForMarket
Expand Down Expand Up @@ -83,12 +88,15 @@ public <T> T getKakao(String url, MultiValueMap<String, String> params, Class<T>
.block();
}

// WebClient Conf 세팅을 이용하며, url과 응답 클래스를 제공하여 요청을 해 Mono로 응답받는 메서드
public <T> T getKakao(String url, Class<T> response) {
return webClientForKakao
// WebClient Conf 세팅을 이용하며, googleMap에 대해 url과 응답 클래스를 제공하여 요청을 해 Mono로 응답받는 메서드
public <T> T getGoogle(String url, MultiValueMap<String, String> params, Class<T> response) {
return webClientForGoogle
.method(HttpMethod.GET)
.uri(url)
.header(HttpHeaders.AUTHORIZATION, kakaoProperties.getKey())
.uri(uriBuilder -> uriBuilder
.path(url)
.queryParams(params)
.queryParam(googleProperties.getKeyName(), googleProperties.getKey())
.build())
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError,
clientResponse -> Mono.error(CustomException.from(BAD_REQUEST)))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package middle_point_search.backend.domains.google.dto;

import java.util.List;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class DistanceMatrixResponse extends GoogleApiResponse {

private List<String> destination_addresses;
private List<String> origin_addresses;
private List<Row> rows;

@Getter
@NoArgsConstructor
public static class Row {
private List<Element> elements;
}

@Getter
@NoArgsConstructor
public static class Element {
private Distance distance;
private Duration duration;
private String status;
}

@Getter
@NoArgsConstructor
public static class Distance {
private String text;
private int value;
}

@Getter
@NoArgsConstructor
public static class Duration {
private String text;
private int value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package middle_point_search.backend.domains.google.dto;

import lombok.Getter;

@Getter
public abstract class GoogleApiResponse {
private String status;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package middle_point_search.backend.domains.google.dto;

import java.util.List;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ReverseGeocodeResponse extends GoogleApiResponse {
private PlusCode plus_code;
private List<Result> results;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class PlusCode {
private String compound_code;
private String global_code;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Result {
private List<AddressComponent> address_components;
private String formatted_address;
private Geometry geometry;
private String place_id;
private List<String> types;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class AddressComponent {
private String long_name;
private String short_name;
private List<String> types;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Geometry {
private Location location;
private String location_type;
private Viewport viewport;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Location {
private Double lat;
private Double lng;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public static class Viewport {
private Location northeast;
private Location southwest;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package middle_point_search.backend.domains.google.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import lombok.RequiredArgsConstructor;
import middle_point_search.backend.common.exception.CustomException;
import middle_point_search.backend.common.exception.errorCode.UserErrorCode;
import middle_point_search.backend.common.properties.GoogleProperties;
import middle_point_search.backend.common.webClient.util.WebClientUtil;
import middle_point_search.backend.domains.google.dto.DistanceMatrixResponse;
import middle_point_search.backend.domains.google.dto.GoogleApiResponse;
import middle_point_search.backend.domains.google.dto.ReverseGeocodeResponse;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GoogleService {

private final WebClientUtil webClientUtil;
private final GoogleProperties googleProperties;

// 이동 시간 조회
public DistanceMatrixResponse findTravelTimes(String destPlaceId, List<String> originPlaceIds) {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add(googleProperties.getMap().getOrigin(), makePlaceIdsQuery(originPlaceIds));
params.add(googleProperties.getMap().getDestination(), makePlaceIdQuery(destPlaceId));
params.add("language", "ko");
params.add("mode", "transit");
params.add("region", "KR");

DistanceMatrixResponse response = webClientUtil.getGoogle(googleProperties.getMap().getDistanceMatrixUrl(),
params, DistanceMatrixResponse.class);

// 상태코드 체크
checkGoogleApiResponseStatus(response);

return response;
}

// id들을 |로 구분하여 query문을 만들어줌
private String makePlaceIdsQuery(List<String> placeIds) {
StringBuilder query = new StringBuilder();
// coordinate 사이에 |를 넣어줌, 마지막에 | 없음
for (int i = 0; i < placeIds.size(); i++) {
query.append("place_id:").append(placeIds.get(i));
if (i != placeIds.size() - 1) {
query.append("|");
}
}
return query.toString();
}

// 장소 ID 쿼리 파라미터 생성
private String makePlaceIdQuery(String placeId) {
return "place_id:" + placeId;
}

// 구글 placeId 찾기
public String findGooglePlaceId(Double latitude, Double longitude) {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("latlng", latitude + "," + longitude);
params.add("language", "ko");

ReverseGeocodeResponse response = webClientUtil.getGoogle(
googleProperties.getMap().getPlaceIdUrl(),
params,
ReverseGeocodeResponse.class
);

// 상태코드 체크
checkGoogleApiResponseStatus(response);

return response.getResults().get(0).getPlace_id();
}

// 상태코드 확인
public void checkGoogleApiResponseStatus(Object response) {
GoogleApiResponse googleApiResponse = (GoogleApiResponse) response;
if (!googleApiResponse.getStatus().equals("OK")) {
throw CustomException.from(UserErrorCode.API_INTERNAL_SERVER_ERROR);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -28,10 +26,6 @@ public class MarketController {
@PostMapping("/market")
@Operation(
summary = "중간 장소 리스트 업데이트",
parameters = {
@Parameter(name = "RoomId", description = "roomId 필요", in = ParameterIn.HEADER),
@Parameter(name = "RoomType", description = "roomType 필요. [TOGETHER, SELF] 중 하나", in = ParameterIn.HEADER)
},
description = """
중간 지점으로 선정될 장소를 업데이트 한다.
Expand Down
Loading

0 comments on commit 4ca5cba

Please sign in to comment.