첫번째로 음식점 정보를 갖고오고자 할때 필수적인 파라미터로 위도, 경도 좌표가 필수가 된다
자동으로 인덱스페이지 접속시 위도 경도를 매핑하는 것을 생각했었는데 그 부분을 해결하지 못해 STACK OVERFLOW에 질문을 등록한 상태이다.
만약 방법이 있다 하더라도 현재 좌표가 아닌 다른 좌표 근처의 음식점 정보를 얻고자 하는 경우가 있기에 지오코딩을 이용한 주소값 불러오기를 테스트 후 적용시키고자 한다
지오코딩이란 고유 명칭(주소 등)을 가지고 위도와 경도의 좌표값을 얻는 것을 의미한다.
구글의 지오코딩과 카카오와 비교해보았는데 빌링 정보도 입력하여야 하는 구글은 다소 손이 갈것같아 카카오로 선택!
- Kakao Geocode API 활용
Query Parameter : 에 검색하고자 하는 도로명 주소를 입력 후
header
- key : Authorization
- value : KakaoAK (한칸띄고) {REST API키 or Admin키}
KakaoAk={key} 로 계속 실패해서 삽질을 다소 하였지만 잘 동작하는것을 확인
다만 걱정인것이 1:1 매핑이 되질 않는다는 점인데 이부분에 대해서는 도로명이 아닌 예전 주소로 해결할 수 있을지 모르겠다.
프론트 단에서 지도를 띄워 설정하도록 할것이니 이부분은 프론트 작업이후로 보류 해둘것 같다
Service
public interface RestaurantService {
void getRestaurantData(String url);
void getRestaurantDetail(String url);
void getXY(String query); // 지오코딩을 통한 x,y 좌표구하기
}
Properties
부트에서는 properties 의 이름을 application-xxx.properties 로 만들게 되면 xxx라는 이름의 profile 이 생성되어 이를 통해 관리 할 수 있습니다. 즉, profile = xxx 라는 식으로 호출하면 해당 properties의 설정들을 가져올 수 있습니다.
API KEY 와 같은 민감 정보들은 프로퍼티로 관리하여 git ignore 설정 후 타인이 접근하지 못하도록 막기위해 사용되었습니다
차후 OAuth 관련 프로퍼티들을 생성할때에 자주 사용될 예정입니다
Impl
@Override
public void getXY(String query) {
Float[] coordinate = new Float[2];
String apiUrl = "https://dapi.kakao.com/v2/local/search/address.json";
String jsonString = null;
try {
query = URLEncoder.encode(query, "UTF-8");
String address = apiUrl + "?query=" + query;
URL url = new URL(address);
URLConnection conn = url.openConnection();
conn.setRequestProperty("Authorization", authorization_key);
BufferedReader rd = null;
rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
StringBuffer docJson = new StringBuffer();
String line;
while ((line = rd.readLine()) != null) {
docJson.append(line);
}
jsonString = docJson.toString();
rd.close();
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray documentsArray = jsonObject.getJSONArray("documents");
JSONObject documentsObject = documentsArray.getJSONObject(0);
String longtitude = documentsObject.getString("x");
String latitude = documentsObject.getString("y");
coordinate[0] = Float.parseFloat(longtitude);
coordinate[1] = Float.parseFloat(latitude);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Test
보통 쿼리 param 으로 url을 통한 Request 시에 파라미터를 인코딩해주어야 합니다.
포스트맨에서 실험시
하지만 UriComponetsBuilder 를 통하여 생성된 파라미터는 자동으로 인코딩이 되기에 따로 인코딩하는 과정을 생략하였습니다
이전에 프로퍼티에 저장하였던 api key같은 경우 아래의 방법과 같이 불러올 수 있습니다
@Value("${kakaoAk.key}")
private String authorization_key;
디버깅 후 파싱을 진행
보통은 분기점을 걸어두고 파싱하기전에 입력창을 통하여 몇번 시도를 거치는 편입니다;;
파싱된 JsonObject 에서 x,y 좌표를 받아올 것입니다.
기존 네이버지도를 통한 좌표값은 소수점아래 7자리를 받는 것을 알 수 있기에 7자리만 받도록 합니다
마지막으로 최종 점검 Test
@Value("${kakaoAk.key}")
private String authorization_key;
private final Logger log = LoggerFactory.getLogger(this.getClass().getSimpleName());
@Test
public void givenRouteReturnXY() throws Exception{
//given
String route = "양덕로 60";
String url = "https://dapi.kakao.com/v2/local/search/address.json";
UriComponents uri = UriComponentsBuilder.newInstance()
.fromHttpUrl(url)
.queryParam("query",route)
.build();
//when
HttpHeaders httpHeaders = utility.getDefaultHeader();
httpHeaders.add("Authorization", String.format("KakaoAK %s",authorization_key));
HttpEntity requestMessage = new HttpEntity(httpHeaders);
ResponseEntity response = restTemplate.exchange(
uri.toUriString(),
HttpMethod.GET,
requestMessage,
String.class);
//then
JSONObject datas = new JSONObject(response.getBody().toString());
JSONObject addressData = datas.getJSONArray("documents").getJSONObject(0).getJSONObject("address");
double x = Math.round(Double.parseDouble(addressData.getString("x")) *10000000)/10000000.0;
double y = Math.round(Double.parseDouble(addressData.getString("y")) *10000000)/10000000.0;
log.info("x는 "+x);
log.info("y는 "+y);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}