<
kakao map
>

❄최신 포스팅❄
☄이전 포스팅☄

Wrapper 클래스란?
카카오 맵

프로젝트 준비

Spring Boot 환경에서 개발

카카오 에서는 카테고리로 지역검색 api를 지원해 주고있다.

다음과 같은 조건으로 개발을 시작한다.

  1. kakao api를 사용할 것
  2. 접속한 사용자의 위치 정보를 획득하여 반경(2000m) 이내의 충전소 정보를 제공한다.
  3. 사용자와 목표 지점까지의 거리를 계산하여 표시한다.

✖ 문제 발생 ✖ - 충전소 현황 웹 파싱 불가

api 호출은 문제가 없었지만 좌표를 지도에 표시하고 디테일 정보를 추가하는 과정에서 문제가 발생했다.

카카오 에서 제공하는 detail 페이지는 완전하게 불러올 수 없다는 것이다.

해당 방법에 대해 kakao 포럼에 질문 했지만 자신들도 외부 CP를 사용하기 때문에 정보를 제공할 수 없다는 문제였다.

직접문의 - https://devtalk.kakao.com/t/kakao-map-jsoup/123707/3 image

그 즉은 어떤 언어로든지 파싱은 불가능 하다는 것이였다.

POSTMan으로 url를 직접호출할 경우

<!DOCTYPE html>
<html lang="ko">

...

<body>
	<div id="kakaoIndex">
		<a href="#kakaoBody">본문 바로가기</a>
		<a href="#kakaoGnb">메뉴 바로가기</a>
	</div>
	<div id="kakaoWrap" class="wrap_mapdetail">
		<!-- 스크롤이 내려 왔을 때 클래스 lbar_on  -->
		<div id="wrapMinidaum"></div>
	</div>
	<div id="daumWrap" style="display:none;">
		<div id="daumContent">
			<div id="shareContainer"></div>
		</div>
	</div>
	<script type="text/javascript" src="//ssl.daumcdn.net/dmaps/map_js_init/v3.js"></script>
	<script type="text/javascript" src="//t1.daumcdn.net/tiara/js/v1/tiara.min.js"></script>
	<script type="text/javascript" src="//t1.daumcdn.net/daumtop_deco/socialshare/socialshare_pc-2.4.3.js"></script>
	<script>
		window.ENV = 'PROD';
        window.browserversion = 'none0';
        
        // 티아라 초기화
        try {
            TiaraTracker.getInstance().init({
                svcDomain: 'place.map.kakao.com',
                deployment: window.ENV === 'PROD' ? 'production' : 'dev'
            });
        } catch(e) {}
        window.placeRestrictType = 'NONE'
        window._cp = '';
	</script>



	<script type="text/javascript" src="//s1.daumcdn.net/svc/attach/U0301/cssjs/mm/1482483925476/Chart.min.js"></script>
	<script type="text/javascript" src="//t1.daumcdn.net/kakaomapweb/place/jscss/pc.cade37dd.js"></script>

</body>
</html>

결과적으로 당장 구현할 수 있는 방법은 window.open(url) 방식으로 충전소 현황을 불러오는 방식이였고 나름 만족한다.

My Code

Spring Restcontroller


@GetMapping("/kakao_url/{lat}/{lng}")
public JSONArray kakao_charge(@PathVariable("lat") String lat, @PathVariable("lng") String lng) throws IOException, ParseException {

        /*
        lat( x 좌표 ) lng( y 좌표 ) 가 카카오에서는 두 값을 바꾸어 입력해야 정상값이 도출된다.
         */
        StringBuilder urlBuilder = new StringBuilder(url); /*URL*/
        urlBuilder.append("?" + URLEncoder.encode("page", "UTF-8") + "=" + 1);
        urlBuilder.append("&" + URLEncoder.encode("sort", "UTF-8") + "=" + "accuracy");
        urlBuilder.append("&" + URLEncoder.encode("query", "UTF-8") + "=" + URLEncoder.encode("전기차충전소", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("x", "UTF-8") + "=" + lng);
        urlBuilder.append("&" + URLEncoder.encode("y", "UTF-8") + "=" + lat);
        urlBuilder.append("&" + URLEncoder.encode("radius", "UTF-8") + "=" + 2000); // 1km
        urlBuilder.append("&" + URLEncoder.encode("size", "UTF-8") + "=" + 15); // 0< x < 15


        return kakaoservice.getMap(urlBuilder);
        }

위에서 제시한 조건에서 반경 2000m 이내의 충전소 위치를 불러오는 방식은 kakao api 입력 정보 문서에 잘 나와 있으니 확인하자.

JS Geolocation

    function onGeoError() {
        alert("Can't find you. No weather for you.");
    }
    
    function init() {
        navigator.geolocation.getCurrentPosition(fetchData, onGeoError);
    }
    
    async function fetchData(position) {
        
        var mapContainer = document.getElementById('map'), // 지도를 표시할 div
        mapOption = {
        center: new kakao.maps.LatLng(position.coords.latitude, position.coords.longitude), // 지도의 중심좌표
        level: 3 // 지도의 확대 레벨
        };
        
        
        var map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다
        
        const lat = position.coords.latitude;
        const lng = position.coords.longitude;
        var url = "/kakao_url/" + lat + "/" + lng
        
        const response = await fetch(url);
    }

View

                for (let i = 0; i < len; i++) {

                    var iwContent =
                        `
                        <div class="info-wrap bg-primary w-100 p-md-5 p-4">
                            <h3>` + itemlist[i].place_name + `</h3>
                            <p class="mb-4">실시간 충전소 현황은 아래 링크를 클릭해주세요.</p>
                            <div class="dbox w-100 d-flex align-items-start">
                                <div class="icon d-flex align-items-center justify-content-center">
                                    <span class="fa fa-map-marker"></span>
                                </div>
                                <div class="text pl-3">
                                    <p>` + itemlist[i].road_address_name + `</p>
                                </div>
                            </div>
		
                            <div class="dbox w-100 d-flex align-items-center">
                                <div class="icon d-flex align-items-center justify-content-center">
                                    <span class="fa fa-phone"></span>
                                </div>
                                <div class="text pl-3">
                                    <p>+ ` + itemlist[i].phone + `</p>
                                </div>
                            </div>

                            <div class="dbox w-100 d-flex align-items-center">
                                <div class="icon d-flex align-items-center justify-content-center">
                                    <span class="fa fa-car"></span>
                                </div>
                                <div class="text pl-3">
                                    <p> `+ itemlist[i].distance + ` 미터</p>
                                </div>
                            </div>

                            <div class="dbox w-100 d-flex align-items-center">
                                <div class="icon d-flex align-items-center justify-content-center">
                                    <span class="fa fa-globe"></span>
                                </div>
                                <div class="text pl-3">
                                    <p><a href="`+ itemlist[i].place_url + `" onclick="window.open(this.href, '_blank', 'width=930, height=700'); return false;">` + itemlist[i].place_url + `</a></p>
                                </div>
                            </div>
	                    </div>`,

                        iwRemoveable = true;
                    position = {
                        content: iwContent,
                        removable: iwRemoveable,
                        latlng: new kakao.maps.LatLng(itemlist[i].y, itemlist[i].x),
                    }


                    positions.push(position)
                }

controller 에서 불러온 데이터를 마커에 주입하여 화면에 노출시키면 깔끔하게 적용된 모습을 볼 수 있다. 마커 이벤트의 겨우 html 태그또한 문자열로 지원되어 custom html 을 제작하여 데이터를 입력해 주면 된다.

image

종종 나오지 않는 정보는 api에서 존재하지 않기 때문이니 문제는 없다.

모든 코드는 나의 Github 을 확인하면 된다.

👨‍💻 Result 👨‍💻

image

image

후기

🍳 과거의 결과물

image

이 프로젝트는 2020년에 실패했던 github - kakao Map 를 다시 살려보고 싶어서 시작한 프로젝트이다.

빈약한 코드는 리팩토링하고 웹 디자인에 신경을 써가며 개발하며 느낀것은 지금 까지의 개발 공부가 헛되지 않았다는 것이였다.

kakao api에 대해서는 과거의 실패 경험으로 api를 다루는 것에 두려움이 있었지만 이번을 계기로 조금 익숙해진것 같다.

Reference

Top
Foot