[Spring] 카카오api를 이용해 주소 좌표로 변환하기

한지연·2024년 4월 6일

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

1. build.gradle에 JsonParser 추가해주기

	//JsonParser
	implementation 'com.googlecode.json-simple:json-simple:1.1.1'

2. 카카오 api키 발급받기 - 👉 KaKao Developers

  • 애플리케이션 추가를 해준다.

  • restapi키를 복사해준다.

  1. api키를 설정 파일에 숨겨준다.

👉 설정 파일에 api key값 적어 놓고 @Value로 가져오기

  1. 코드 작성

주소 -> 좌표 변환

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

Json 데이터 파싱

파싱할 땐 사용하고 싶은 라이브러리를 찾아 사용 방식에 맞게 사용하면 된다.

그리고 카카오 맵 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}

제가 잘못 알고 있거나 더 효율적인 코드가 있다면 불쌍한 중생에게 실력 성장을 하사하노라 하고 댓글 남겨주세요! 감사히 배우고 댓글 달아주신 분들의 적게 일하고 많이 벌기를 응원하겠습니다!

profile
배우고 활용하는 것을 즐기는 개발자, 한지연입니다!

0개의 댓글