Develop/Spring 공략

[Spring] 카카오맵 API를 활용하여 GeoCoding

쿼카홀릭 2025. 4. 25. 01:01

 

지난 게시글에 이어 카카오맵 API를 활용해서 주소를 위도/경도(좌표)로 변환하는 코드를 작성했다.

탑-다운 방식으로 개발하는 것을 선호하여, 컨트롤러 - 서비스 순으로 코드를 나열할 예정이다.

 


응답 DTO 생성

@Getter
@RequiredArgsConstructor
public class GeoCoordinate {
    private final Double longitude; // x값(경도)
    private final Double latitude; // y값(위도)
}

 

카카오맵 API는 x값이 경도, y값이 위도로 추출됨으로 이에 유의하면서 코드를 작성해야 한다.


 

Controller 생성

카카오맵 문서 중 일부

 

카카오맵 API를 활용해서 GeoCoding을 하려면, HttpMethod는 GET으로 해주어야 한다.

@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/v1/location", method = RequestMethod.GET)
public class GeoController {

    private final GeoService geoService;

    @GetMapping("/coordinates")
    public ResponseDto<GeoCoordinate> getGeoData(@RequestParam String address) {
        GeoCoordinate geoCoordinate = geoService.getGeoData(address);
        return ResponseDto.success(geoCoordinate);
    }
}

 

변환할 주소를 RequestParam으로 넣어주고, 반환은 프로젝트 내에서 공통 ResponseDto를 사용하고 있었음으로 위와 같이 반환하였다. 상황에 맞게 반환 타입을 적용해주면 될 것 같다.

 


Service 생성

@Service
@RequiredArgsConstructor
public class GeoService {

    @Value("${api-key.kakao}")
    private String key;

    private final static String MAP_URL = "http://dapi.kakao.com/v2/local/search/address.json?query=";

    //GeoCoding(주소를 위도/경도로 변환)
    public GeoCoordinate getGeoData(String address) {
        try {
            // 주소에 공백과 한글이 있어서 깨짐 방지용 인코딩 작업
            String encodedAddr = URLEncoder.encode(address, StandardCharsets.UTF_8);
            URL url = new URL(MAP_URL + encodedAddr);

            // HttpURLConnection 객체 생성 및 GET 방식 설정
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            // Kakao API 인증을 위해 요청 헤더에 Authorization 추가
            connection.setRequestProperty("Authorization", "KakaoAK " + key);

            // 응답 데이터를 읽어오기 위한 BufferedReader 생성
            try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                // 응답을 한 줄로 이어붙여 JSON 문자열로 변환
                String response = br.lines().collect(Collectors.joining());
                // JSON 문자열을 JSONObject로 파싱
                JSONObject obj = (JSONObject) new JSONParser().parse(response);
                // 'documents' 키에 해당하는 JSON 배열 추출 (여기에 주소 결과들이 담겨 있음)
                JSONArray docs = (JSONArray) obj.get("documents");
                //자료가 비어 있으면, 커스텀 예외처리  
                if (docs.isEmpty()) throw new AddressResponseEmptyException();

                // 첫 번째 검색 결과를 기준으로 경도(x), 위도(y) 값 추출
                JSONObject first = (JSONObject) docs.get(0);
                // 추출한 좌표를 Double 타입으로 변환하여 객체 생성
                return new GeoCoordinate(Double.parseDouble((String) first.get("x")),Double.parseDouble((String) first.get("y")));
            }
        } catch (Exception e) {
            //커스텀 예외처리
            throw new CoordinateConversionFailedException();
        }
    }
}

 

중요한 부분은 conn.setRequestProperty로 Authorization을 제공하는 방식이며, 위의 코드처럼 작성하면 JSON 데이터로 데이터를 지역 정보를 받아올 수 있다.

 

예외처리 같은 경우는 팀 내에서 커스텀 예외처리를 해주는 것으로 약속을 했기에 위와 같이 적용하였다.

그 외의 코드는 주석으로 해당 코드에 대한 설명을 작성 해두었으니, 추가적으로 부연설명은 기재하지 않을 것이다.

 

위 코드에서 'documents' 키에 해당하는 JSON 배열을 추출하는 이유는 아래 자료를 참고하면 될 것이다.

 

@Value 어노테이션을 사용해서, 앞전 게시글에서 언급했던 REST API KEY를 넣어주었다.

REST API KEY는 지난 게시글에 자세하게 설명해두었음으로 참고하면 될 것 같다.

2025.04.22 - [Develop/Spring 공략] - [Spring] 카카오맵 API 사용 초기 세팅

Key와 같은 민감하고 주요한 정보는 환경변수나 설정파일의 값을 주입하는 방식을 선택해야 한다.

나는 아래와 같이 yml 파일에 작성해주었다.

 

api-key:
  kakao: 나의 REST API Key 넣어주기

 

API Key는 get 방식의 주소에 파라미터를 적는 방식으로는 적용이 불가하고, URLConnection의 setRequestProperty를 통해 제공해야 한다. 이렇게 작성해야 헤더에 Authorization을 추가해서 Key를 적용해줄 수 있다.


나의 고난과 역경

다른 분들은 나와 같은 고생을 하지 않게 하기 위하여...
혹시 프로젝트에서 Spring Security를 사용하고 있다면, 401 에러에 주의해야한다.

AuthUser의 토큰 값도 헤더에 Authorization으로 넣어줘야하고, KakaoMap Key도 헤더에 Authorization으로 넣어줘야한다.
이렇게 되면 헤더에 중복으로 들어가게 되고, 둘 중 하나는 무시될 가능성이 높다.
그러면 401으로 권한의 문제가 생긴다.
사실상 생각해보면, 카카오맵 서버를 통해 요청하는 것임으로 유저의 정보를 굳이 확인하지 않아도 된다.

따라서, 해결 방법은 Spring Security에서 해당 요청을 permitAll 해주는 방법이다.
SecurityConfig에 아래와 같이 추가만 해주면 쉽게 해결된다.
					(...)
.authorizeHttpRequests(auth -> auth
	.requestMatchers(new AntPathRequestMatcher("/api/v1/location/**").permitAll()
    	.anyRequest().authenticated())​


이렇게 작성해두면, Security 에러에서 해방될 수 있다.
이제 헤더에 API Key만 넣어주면 된다.


 

PostMan으로 테스트

Param에 Key-Value값 작성

 

위도/경도로 변환할 주소를 위와 같이 param에 작성해준다. 망원동을 위도/경도로 변환 해볼것이다.

 

Authorization에 key값 넣어줘야 한다.

이때 주의할 것은 REST API Key값 작성할 때, [KakaoAK + 공백 + key값] 이렇게 작성해 주어야한다!

띄어쓰기 있으니까 꼭 주의!!

 

 

그러면 위와 같이 경도와 위도로 추출된 결과를 확인할 수 있다.

 

구글맵에서 위도/경도로 위치 검색 해보기

 

카카오맵으로는 좌표 검색이 되지 않아, 구글맵으로 진행하였다.

앞서 추출한 경도와 위도를 구글맵에 검색해보면, 이렇게 망원동 일대가 나오는 것을 확인할 수 있다.

구글맵에서 검색할 때는 위도,경도 순으로 검색해야 한다!

 


이렇게 카카오맵 API를 통해서 주소를 좌표로 변환하는 코딩을 해보았다.

나는 백엔드 공부를 하고 있기에 따로 프론트는 구현하지 않았지만, 카카오 개발자 페이지에 프론트 구현 예제가 있으니

활용 해봐도 좋을 것 같다.

'Develop > Spring 공략' 카테고리의 다른 글

[Spring] 카카오맵 API 사용 초기 세팅  (0) 2025.04.22
[Spring] Spring JPA - Page 와 Slice  (0) 2025.04.01
[Kiosk] 트러블슈팅  (0) 2025.01.21
[Calculator] Lv.2 트러블슈팅  (0) 2025.01.10
[Calculator] Lv.1 트러블슈팅  (0) 2025.01.10