오늘 내가 포스팅하는 건 카카오 맵api를 이용해 주소를 좌표로 변환해보는 것에 목적이 있지만 json 데이터를 파싱하는 것까지가 오늘의 할 일이다.

//JsonParser
implementation 'com.googlecode.json-simple:json-simple:1.1.1'
애플리케이션 추가를 해준다.

restapi키를 복사해준다.

private final static String MAP_URL = "http://dapi.kakao.com/v2/local/search/address.json?query=";
//api값을 코드에 직접 노출시키지 않고 사용하기 위한 방법
@Value("${api-key.kakao}")
private String key;
public Map<String, String> getGeoData(String address) {
try{
// 주소엔 공백값이 들어가기 때문에 인코딩 해주고 사용해야 한다.
String encodedAddr = URLEncoder.encode(address, "UTF-8");
URL findUrl = new URL(MAP_URL+encodedAddr);
// connection을 생성하고 get 방식으로 데이터를 불러온다.
HttpURLConnection conn = (HttpURLConnection) findUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "KakaoAK " + key);
conn.setRequestProperty("content-type", "application/json");
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
Charset charset = Charset.forName("UTF-8");
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
String readLine;
StringBuffer response = new StringBuffer();
while ((readLine = br.readLine()) != null) {
response.append(readLine);
}
//JsonParser로 파싱한 데이터를 리턴
return getXyCode(response);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
코드 참고: https://spatiumwdev.tistory.com/30
파싱할 땐 사용하고 싶은 라이브러리를 찾아 사용 방식에 맞게 사용하면 된다.
그리고 카카오 맵 api가 내려주는 json데이터 형태를 먼저 확인해야 한다.
우리가 사용할 데이터는 x,y값이다.
하지만 x,y 데이터를 뽑아내려면
documents를 JsonArray 객체에 담은 후 원하는 데이터를 뽑아내야 한다.
{
"documents": [
{
"address": {
"address_name": "전북특별자치도 익산시 창인동1가 11",
"b_code": "5214010100",
"h_code": "5214052000",
"main_address_no": "11",
"mountain_yn": "N",
"region_1depth_name": "전북특별자치도",
"region_2depth_name": "익산시",
"region_3depth_h_name": "중앙동",
"region_3depth_name": "창인동1가",
"sub_address_no": "",
"x": "126.947286987925",
"y": "35.9411244012712"
},
"address_name": "전북특별자치도 익산시 익산대로 165-1",
"address_type": "ROAD_ADDR",
"road_address": {
"address_name": "전북특별자치도 익산시 익산대로 165-1",
"building_name": "동대문엽기떡볶이 익산역점",
"main_building_no": "165",
"region_1depth_name": "전북특별자치도",
"region_2depth_name": "익산시",
"region_3depth_name": "창인동1가",
"road_name": "익산대로",
"sub_building_no": "1",
"underground_yn": "N",
"x": "126.947286987925",
"y": "35.9411244012712",
"zone_no": "54662"
},
"x": "126.947286987925",
"y": "35.9411244012712"
}
],
"meta": {
"is_end": true,
"pageable_count": 1,
"total_count": 1
}
}
private Map<String, String> getXyCode(StringBuffer jsonData) throws ParseException {
Map<String, String> xyMap = new HashMap<>();
// 변수로 받아온 jsonData를 JSONObject에 담아준다.
JSONObject obj = (JSONObject) new JSONParser().parse(String.valueOf(jsonData));
// documents를 JsonArray 객체에 담아준다.
JSONArray xyData = (JSONArray) obj.get("documents");
// 배열의 첫 번째 요소를 다시 Json 객체에 담아준다.
JSONObject jsonObject1 =(JSONObject) xyData.get(0);
// 선언 해놓은 map에 x, y값을 담는다.
xyMap.put("x", (String) jsonObject1.get("x"));
xyMap.put("y", (String) jsonObject1.get("y"));
return xyMap;
}
내가 위에 적은 코드는 스프링빈에 등록되어 관리되는 형식이기 때문에 FindGeoCode 클래스를 new 생성자로 만들어 사용한다면 key값에 값이 들어가지 않아 계속 401오류만 보게 되는 상황이 생긴다. 그냥 되나 안 되나만 확인하고자 한다면 2번까지만 실행한 후 아래의 코드를 적용해보면 좋을 듯 하다!
@RequiredArgsConstructor
public class FindGeoCodeStudy {
private final static String MAP_URL = "http://dapi.kakao.com/v2/local/search/address.json?query=";
private final static String key = "발급받은 키값을 넣어주세요!";
public static Map<String, String> getGeoData(String address) {
try{
String encodedAddr = URLEncoder.encode(address, "UTF-8");
URL findUrl = new URL(MAP_URL+encodedAddr);
HttpURLConnection conn = (HttpURLConnection) findUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "KakaoAK " + key);
conn.setRequestProperty("content-type", "application/json");
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
Charset charset = Charset.forName("UTF-8");
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
String readLine;
StringBuffer response = new StringBuffer();
while ((readLine = br.readLine()) != null) {
response.append(readLine);
}
return getXyCode(response);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static Map<String, String> getXyCode(StringBuffer jsonData) throws ParseException {
Map<String, String> xyMap = new HashMap<>();
System.out.println(jsonData);
JSONObject obj = (JSONObject) new JSONParser().parse(String.valueOf(jsonData));
JSONArray xyData = (JSONArray) obj.get("documents");
JSONObject jsonObject1 =(JSONObject) xyData.get(0);
xyMap.put("x", (String) jsonObject1.get("x"));
xyMap.put("y", (String) jsonObject1.get("y"));
System.out.println("geoData: " + xyMap);
return xyMap;
}
public static void main(String[] args) {
FindGeoCodeStudy.getGeoData("전북특별자치도 익산시 익산대로 165-1");
}
}
결과값:
{"documents":[{"address":{"address_name":"전북특별자치도 익산시 창인동1가 11","b_code":"5214010100","h_code":"5214052000","main_address_no":"11","mountain_yn":"N","region_1depth_name":"전북특별자치도","region_2depth_name":"익산시","region_3depth_h_name":"중앙동","region_3depth_name":"창인동1가","sub_address_no":"","x":"126.947286987925","y":"35.9411244012712"},"address_name":"전북특별자치도 익산시 익산대로 165-1","address_type":"ROAD_ADDR","road_address":{"address_name":"전북특별자치도 익산시 익산대로 165-1","building_name":"동대문엽기떡볶이 익산역점","main_building_no":"165","region_1depth_name":"전북특별자치도","region_2depth_name":"익산시","region_3depth_name":"창인동1가","road_name":"익산대로","sub_building_no":"1","underground_yn":"N","x":"126.947286987925","y":"35.9411244012712","zone_no":"54662"},"x":"126.947286987925","y":"35.9411244012712"}],"meta":{"is_end":true,"pageable_count":1,"total_count":1}}
geoData: {x=126.947286987925, y=35.9411244012712}
제가 잘못 알고 있거나 더 효율적인 코드가 있다면 불쌍한 중생에게 실력 성장을 하사하노라 하고 댓글 남겨주세요! 감사히 배우고 댓글 달아주신 분들의 적게 일하고 많이 벌기를 응원하겠습니다!