프로그래밍/개발

spring에서 api 요청하기

b1ackhand 2024. 2. 12. 00:05

현재 개발하는 프로젝트에서 지도 api를 사용하게 될일이 생겼다. 정확히는 출발지와 목적지가 주어졌을때, 얼마나 걸리는지를 계산해서 거리와 시간을 가지고 비용 측정 및 차량을 추천해줘야 하는 상황이다. 우선, 이런저런 리서치를 해봤는데 spring에서 api를 요청할 일이 거의 없었나 자료들이 많지는 않았다. front에서 요청하듯이 하면 되겠지? 라는 생각 정도 였다.

 

https://github.com/googlemaps/google-maps-services-java

 

GitHub - googlemaps/google-maps-services-java: Java client library for Google Maps API Web Services

Java client library for Google Maps API Web Services - GitHub - googlemaps/google-maps-services-java: Java client library for Google Maps API Web Services

github.com

우선은 프론트에서 구글맵을 쓴다고해서 이런 걸 찾아서 세팅하고 읽어보던 중 갑자기 카카오맵으로 변경한다는 소식을 듣게 되었고 카카오 api를 발급받고 문서를 쭉 읽어봤다.

 

https://developers.kakaomobility.com/docs/navi-api/directions/

 

카카오모빌리티 디벨로퍼스

카카오모빌리티 디벨로퍼스

developers.kakaomobility.com

우리에게 필요한 요청은 위 주소에 해당하는 api였다. 그리고 내가 작성한 코드는 아래와 같다.

 

public DistanceDurationInfo KaKaoCarDirections(Location src, Location dst){
		String source = src.toString();
		String destination = dst.toString();
		String url = "https://apis-navi.kakaomobility.com/v1/directions";

		String params = "origin=" + source +
			"&destination=" + destination +
			"&waypoints=" +
			"&priority=RECOMMEND" +
			"&car_fuel=GASOLINE" +
			"&car_hipass=false" +
			"&alternatives=false" +
			"&road_details=false";

		String fullUrl = url + "?" + params;

		HttpHeaders headers = new HttpHeaders();
		headers.set("Authorization", "KakaoAK " + apiKey);
		HttpEntity<String> entity = new HttpEntity<>(headers);

		RestTemplate restTemplate = new RestTemplate();
		ResponseEntity<String> response = restTemplate.exchange(fullUrl, HttpMethod.GET, entity, String.class);

		if (response.getStatusCode() == HttpStatus.OK) {
			try {
				ObjectMapper objectMapper = new ObjectMapper();
				JsonNode rootNode = objectMapper.readTree(response.getBody());

				JsonNode routesNode = rootNode.get("routes");
				JsonNode routeNode = routesNode.get(0); // 첫 번째 루트 선택
				JsonNode summaryNode = routeNode.get("summary");

				int distance = summaryNode.get("distance").asInt();
				int duration = summaryNode.get("duration").asInt();

				return new DistanceDurationInfo(distance, duration);
			} catch (Exception e) {
				logger.error(e.getMessage());
				e.printStackTrace();
			}
		} else {
			logger.error("kakaoMap Response Error");
		}
		return new DistanceDurationInfo(0,0);
	}

 

나 같은 경우에 필요한 정보가 거리와 걸리는 시간이었기 때문에 Jackson 라이브러리를 통해 해당내용만 뽑아내어 내가 지정한 사설 Class에 넣어줬다. 여기서 조금 고생했던 부분은 Authorization 부분에 apiKey를 넣는부분이었다. 이러한 보안 사항들은 application.yml에 보관하고 아래와 같이 사용한다.

 

@Value("${kakao.maps.apikey}")
private String apiKey;




kakao:
  maps:
    apikey: asdf

 

yml에 가보면 위 처럼 key가 적혀있고 apiKey에 주입이된다. 하지만 나는 key는 바뀌지 않을 것이기 때문에 다른 class에서 static으로 선언하면 더 안전하지 않을까? 라는 생각을 하였고 이를 처리하기 위해 이런저런 시도를 해봤었다. 하지만 계속해서 값을 null로만 받아와서 검색을 해봤었다.

 

https://badstorage.tistory.com/69

 

[spring boot] yml로 값 가져와서 static 클래스변수에 값넣기

프로젝트 도중 properties에 있는 값을 가져와 java static 변수로 초기화 해서 사용해야 하는 상황이 왔습니다. 하지만 아직도 저는 @value로 가져오는 값 초기화와 static 클래스 변수 초기화의 순서 차

badstorage.tistory.com

 

위 블로그에서 이를 처리할 수 있는 여러 방법들에 대해서 소개해 주었고 이걸 보고 도움을 받았다. 사실 이걸 알아보면서 알게 된 것이 Java에서 static변수의 초기화 순서이다. 위의 방법들을 보면 이 static변수들이 초기화 되기 전에 어노테이션 등으로 이를 처리하려고 하는것 같다.

  1. static 변수 선언: static 키워드로 선언된 변수가 클래스 내부에 정의됩니다.
  2. static 블록: static 블록 내에서 static 변수들의 초기화와 추가적인 초기화 로직이 수행됩니다.
  3. 클래스 로딩: 클래스가 로딩될 때 static 변수들이 메모리에 할당되고 초기화됩니다. 클래스 로딩은 해당 클래스가 처음 사용될 때 발생하며, JVM에 의해 수행됩니다.
  4. static 변수 초기화: static 변수들이 선언된 순서대로 초기화됩니다. 만약 static 변수가 초기값으로 선언되어 있다면 그 값으로 초기화됩니다. 초기화되지 않은 경우 해당 변수의 타입에 따라 기본값으로 초기화됩니다.

 

하지만 나는 결국 static한 key를 사용하지 않았다. 이유로는 원래 이러한 application.yml에서 불러오는 변수들을 한 class에 몰아넣고 @postConstruct로 처리할려고 했는데 오버헤드인것 같아서 그냥 기존의 방식대로 할려고한다.