- https://developers.kakao.com/docs/latest/ko/local/dev-guide#address-coord
- 로컬 REST API를 활용해서 사용자가 주소 값을 입력하면 해당 주소를 db와 비교해서 지도 좌표로 변환해주는 코드를 작성
- 요청 형식에 맞는 uri 코드 작성 -> restTemplate 카카오 api호출
- 응답 객체 받아오기 -> 입력한 주소의 좌표
- 로컬에서 사용한 형식을 카카오 길찾기 api에 맞춰서 요청 -> 응답 객체 받아와서 해당 좌표를 프론트 상에서 폴리라인으로 경로 그려주기
private static final String KAKAO_LOCAL_SEARCH_ADDRESS_URL = "https://dapi.kakao.com/v2/local/search/address.json";
public URI buildUriByAddressSearch(String address) {
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(KAKAO_LOCAL_SEARCH_ADDRESS_URL);
uriBuilder.queryParam("query", address);
URI uri = uriBuilder.build().encode().toUri(); // encoding -> 브라우저에서 해석할 수 없는 것들-> UTF-8 로 인코딩해줌
log.info("*** 로그 [KakaoUriBuilderService buildUriByAddressSearch] address: {}, uri: {}", address, uri);
return uri;
}
// ->주소검색 api를 uri 형태로 빌더 해줌
public class KakaoAddressSearchService{
private final RestTemplate restTemplate;
private final KakaoUriBuilderService kakaoUriBuilderService;
@Value("${kakao.rest.api.key}")
private String kakaoRestApiKey;
// 해당 메서드를 호출 -> 입력한 주소값 -> 요청할 수 있는 uri + headers에 key값
// 요청한 것에 대한 응답 값 -> kakaoApiResponseDto 객체로 반환
public KakaoApiResponseDto requestAddressSearch(String address){ // 주소 -> 위도, 경도로 변환
if(ObjectUtils.isEmpty(address)) return null;
URI uri = kakaoUriBuilderService.buildUriByAddressSearch(address);
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "KakaoAK " + kakaoRestApiKey);
HttpEntity httpEntity = new HttpEntity(headers);
// kakao api 호출
return restTemplate.exchange(uri, HttpMethod.GET, httpEntity, KakaoApiResponseDto.class).getBody();
}
}
- 길찾기 요청에 맞는 형식으로 요청해서 응답값을 받아옴
- 기존에 사용한 api는 자동차 길찾기 api를 활용해서 구현
- 랜덤 길찾기는 다중 경유지 길찾기 api를 활용해서 응답값에 받아오는 경유지를 랜덤으로 설정해서 경로를 그려주는 식으로 구현
- 주소를 입력하고 좌표를 받아오고, uri를 만들어서 요청을 보내는 방식은 거의 동일
public KakaoRouteAllResponseDto requestAllRandomWay(String username, String originAddress, Integer redius) {
if (ObjectUtils.isEmpty(originAddress) || ObjectUtils.isEmpty(redius)) return null;
// 출발지와 도착지 주소를 각각 좌표로 변환
DocumentDto origin = kakaoAddressSearchService.requestAddressSearch(originAddress).getDocumentDtoList().get(0);
/***
목적지와 경유지 값을 반경으로 계산해서 가져오는 메소드
***/
KakaoApiResponseDto responses = kakaoCategorySearchService.requestAttractionCategorySearch(origin.getLatitude(), origin.getLongitude(), redius);
List<String> addressNames = responses.getDocumentDtoList().stream()
.map(DocumentDto::getAddressName)
.collect(Collectors.toList());
log.info("getDocumentDtoList addressNames : {} " , addressNames.toString());
// DocumentDto 리스트 확인
/***
랜덤으로 다중 목적지와 경유지 만들기 알고리즘
***/
int RandomLength = responses.getDocumentDtoList().size();
Random rd = new Random();
int destinationCnt = rd.nextInt(RandomLength);
int waypointsCnt = rd.nextInt(RandomLength);
if(destinationCnt == waypointsCnt){
if(destinationCnt == 0){
destinationCnt += 1;
}
waypointsCnt = destinationCnt - 1;
}
log.info("destinationCnt : {}",destinationCnt);
log.info("waypointCnt : {}",waypointsCnt);
DocumentDto destination = responses.getDocumentDtoList().get(destinationCnt);
DocumentDto waypoints = responses.getDocumentDtoList().get(waypointsCnt);
// 목적지 DB에 남김, 만일 동일 사용자가 이미 목적지를 저장해 놓았다면, 삭제
RandomDestination randomDestination = new RandomDestination(username, destination.getAddressName());
RandomDestination olderRandomDestination = randomDestinationRepository.findByUsername(username);
if (olderRandomDestination != null)
randomDestinationRepository.delete(olderRandomDestination);
randomDestinationRepository.save(randomDestination);
/***
요청 헤더 만드는 공식
***/
return makeRequestForm(origin,destination,waypoints);
}
requestAttractionCategorySearch
-> 를 활용해서 카카오 api의 카테고리 검색을 사용- 카테고리에 맞는 값을 입력하면 해당하는 범위의 카테고리를 찾아줌
- 현재는 관광명소로 설정해서 -> 사용자가 주소를 입력하면 그 좌표 주변의 반경을 기반으로 좌표를 받아와서 경유지,목적지로 설정 -> 길찾기 api에 요청
- 랜덤으로 받아온 경유지를 경유지, 목적지로 설정하고 있으므로 경로가 겹칠 수가 있다.
- 지나온 길을 다시 지나간다던가 하는 효율적인 경로를 생성하지 못한다.
- 정확한 지명, 정확한 관광명소에 대한 정보를 완벽하게 가져오지 못한다.(가져올때도 있고 없을때도 있다.)
- 출발지 검색 -> 도로명만을 검색 가능, 키워드 기반 검색도 가능하게 기능 추가
계양맛길 음식문화시범거리
-> 카카오맵에 정확한 주소지로 나온다.
-> 네이버 지도에서는 안나온다. 카카오맵에만 있는 주소이다. 네이버는"계양맛길"
독산
-> 독산동 전체가 나온다영월의숲
-> 영월의 숲도 전체지역을 아우르는 키워드- 정확한 장소 지명이 안되고 있다.
-> 인기순, 리뷰 많은 순 등의 작업은 어렵다. 이게 가능하게 할려면 따로 카테고리별에 맞는 데이터를 만들어서 비교하며 찾아줘야 할 듯 하다.
🤷♂️ 장소명과 지번의 주소가 불일치 하는 경우도 발생
place_name
: 장소명,업체명address_name
: 전체 지번
-> 위의 두 개의 주소가 일치하는 경우도 있지만, 밑에처럼 불일치 하는 경우도 발생
인천 계양구 방축동
과뒷동산
2 개의 키워드는 어찌보면 무관해 보이기까지 한다.
- 카테고리에 맞는 정확한 지명과 주소의 매칭
- 효율적인 길찾기 경로 생성
- 도로교통 정보를 반영 -> 거리가 더 멀어지더라도 정체 -> 서행으로 드라이브를 할 수 있게
- 출발지 도착지 명확하게 표시
- 키워드를 입력하면 해당 주소를 반환해주는 키워드 api 활용
address_name
의시, 구
+ 키워드 조합 -> 주소 요청 + 해당 카테고리 맞는지 검사- 해당 키워드
place_name
요청 ->address_name
가져와서 좌표로 변환
- 경유지 리스트들 중 2개를 랜덤으로 뽑아서 경유지, 목적지로 설정 -> 중복된 경로가 발생
- 효율적인 경로 생성이 어려움 -> 중복된 경로가 생성되지 않고 이어지는 경로 생성
- 반경이 제한적인 상황
- 하나의 경유지가 아닌 다양한 경유지(관광 명소 카테고리)를 잡아서 다채로운 경로 생성
효율적인 길찾기 -> 알고리즘을 구현해서 길찾기 해보기
- 키워드를 입력하면 해당 주소를 반환해주는 키워드 api 활용
address_name
의시, 구
+ 키워드 조합 -> 주소 요청 + 해당 카테고리 맞는지 검사- 해당 키워드
place_name
요청 ->address_name
가져와서 좌표로 변환
-링크
- 키워드를 입력하면 해당 주소를 반환해주는 키워드 api 활용
address_name
의시, 구
+ 키워드 조합 -> 주소 요청 + 해당 카테고리 맞는지 검사- 해당 키워드
place_name
요청 ->address_name
가져와서 좌표로 변환
-링크