Hello

카카오 지도 API - 지도에 위치 표시하기

by 볼빵빵오춘기

토이 프로젝트를 진행하면서 동물 보호소 정보를 데이터베이스에 저장한 후, 해당 보호소의 주소를 지도에 표시하는 기능을 구현하게 되었다.

페이지가 로드될 때 전체 보호소 데이터를 모두 가져와 자바스크립트에 좌표 정보를 일일이 넣어줄 수도 있지만, 많은 데이터를 한 번에 불러오면 서버에 부담이 될 수 있다.

이를 해결하기 위해 API를 수정하여, 지도가 보여지는 위치에 포함된 보호소만을 서버에서 가져오도록 했다.

이 과정은 Ajax를 이용해 필요한 위치의 보호소 정보를 JSON 데이터로 요청하여 처리다.

또한, 보호소 위치를 지도 API에 표시하기 위해서는 해당 보호소의 좌표 정보가 필요했기에 사용자가 보호소 정보를 등록할 때, 다음 주소 API를 활용하여 자동으로 좌표가 입력되도록 구현했다.

 

카카오 개발자 사이트

  1. 카카오 개발자사이트 (https://developers.kakao.com)/) 접속
  2. 내 애플리케이션 등록
  3. 내 애플리케이션 > 플랫폼 > Web 플랫폼 등록
  4. 내 애플리케이션 > 요약정보 > JavaScript 키 복사

 

카카오 주소 API

카카오 맵스 API(https://apis.map.kakao.com/web/sample/)에는 다양한 예시가 제공되어 있다.
원하는 기능을 선택한 후, 필요에 맞게 커스터마이징하여 사용할 수 있다.

 

 

카카오 지도 API를 이용해서 지도에 보호소 위치 나타내기

html

  • 스크립트 연결하면서 자바스크립트 앱키를 넣어준다.
  • libraries 에는 사용할려는 기능을 넣어준다.

<div class="col-12 mb-30 mt-15">
    <div class="tab-pane fade show active" id="mapShelter">
        <div id="map" style="width:100%;height:350px;"></div>
    </div>
</div> 

<script type="text/javascript" th:src="@{/static/js/shelterList.js}"></script>
<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=자바스크립트 앱키를 넣어주세요.&libraries=services,clusterer,drawing"></script>

 

js

	
$(document).ready(function(){
	viewMarker(); 
});

// 처음 지도 중심을 둘 좌표 & 지도의 확대 레벨
var lat = 37.5663174209601; 
var lng = 126.977829174031;
var firstLevel = 9;


var mapContainer = document.getElementById('map'), // 지도를 표시할 div
mapOption = {
    center: new kakao.maps.LatLng(lat, lng), // 지도의 중심좌표
    level: firstLevel // 지도의 확대 레벨
};

var map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다

var markers = [];
var infowindows = [];

// 마커 클러스터러를 생성합니다
var clusterer = new kakao.maps.MarkerClusterer({
    map: map, // 마커들을 클러스터로 관리하고 표시할 지도 객체
    averageCenter: true, // 클러스터에 포함된 마커들의 평균 위치를 클러스터 마커 위치로 설정
    minLevel: 9 // 클러스터 할 최소 지도 레벨
});

kakao.maps.event.addListener(map,'zoom_changed',function(){
    chkArea();
});

kakao.maps.event.addListener(map,'dragend',function(){
    chkArea();
});


function chkArea(){
    removeMarker();
    viewMarker();
}

function removeMarker(){
    var cnt = markers.length;
    for(i=0;i<cnt;i++){
        markers[i].setMap(null);
    }
    clusterer.clear();

}


// 지도에 위치 찍기
function viewMarker(){

    removeMarker();
    // 화면의 영역값 가져오기
    var bounds = map.getBounds();
    var sw = bounds.getSouthWest();
    var ne = bounds.getNorthEast();
    var level = map.getLevel();

    lon1 = sw.La;
    lat1 = sw.Ma;
    lon2 = ne.La;
    lat2 = ne.Ma;
    console.log("lon1 : "+lon1);

    let data = {
        lon1 : lon1,
        lat1 : lat1,
        lon2 : lon2,
        lat2 : lat2
    };

    // ajax start
        // Ajax 요청으로 서버에서 위치 데이터 가져오기
        $.ajax({
            type: "POST",
            url: `/shelterMap/${data.lon1}/${data.lon2}/${data.lat1}/${data.lat2}`,

            data: JSON.stringify(data),
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        }).done(function(resp) {

            // 데이터에서 좌표 값을 가지고 마커를 표시합니다
            // 마커 클러스터러로 관리할 마커 객체는 생성할 때 지도 객체를 설정하지 않습니다
            var markers = $(resp).map(function(i, resp) {
                return new kakao.maps.CustomOverlay({
                    position : new kakao.maps.LatLng(resp.lat, resp.lon),
                    content: `<div class="ovr bg_03A3F1 shelterName" data-shelter-id="${resp.id}" data-toggle="modal" data-target="#shelterInfo"></div>`
                });
            });


            // 클러스터러에 마커들을 추가합니다
            clusterer.addMarkers(markers);

        }).fail(function(error) {
            console.log(JSON.stringify(error));
        });

		// ajax end
}

 

Controller

@PostMapping("/shelterMap/{lon1}/{lon2}/{lat1}/{lat2}")
public List<ShelterEntity> shelerMap(@PathVariable String lon1,@PathVariable String lon2,@PathVariable String lat1,@PathVariable String lat2){

    double dLon1 = Double.parseDouble(lon1);
    double dLon2 = Double.parseDouble(lon2);
    double dLat1 = Double.parseDouble(lat1);
    double dLat2 = Double.parseDouble(lat2);

    List<ShelterEntity> shelterEntityList = shelterService.findLonGreaterThanAndLonLessThanAndLatGreaterThanAndLatLessThan(dLon1,dLon2,dLat1,dLat2);

    return shelterEntityList;
}

 

Service

// 지도 범위에 따른 리스트 보기
public List<ShelterEntity> findLonGreaterThanAndLonLessThanAndLatGreaterThanAndLatLessThan(double lon1,double lon2,double lat1,double lat2){
    List<ShelterEntity> shelterEntityList = shelterRepository.findByLonGreaterThanAndLonLessThanAndLatGreaterThanAndLatLessThanAndApproval(lon1,lon2,lat1,lat2,1);
    return shelterEntityList;
}

 

Repository

public List<ShelterEntity> findByLonGreaterThanAndLonLessThanAndLatGreaterThanAndLatLessThanAndApproval(double lon1, double lon2, double lat1, double lat2, int isApproval);

 

 

위의 과정으로 카카오 주소 API를 활용하여 지도에 보호소 위치를 표시를 했다.

추가로, 지도에 표시된 보호소를 클릭하면 해당 보호소의 정보를 모달 창으로 보여주려고 생각했었다. 이를 위해 Ajax를 사용하여 지도에서 클릭한 보호소의 세부 정보를 모달에 표시하는 기능을 구현했다.

 

보호소 좌표 클릭 시 모달로 해당 보호소 정보 보여주기

html

<!-- Modal -->
<div class="modal fade" id="shelterInfo" tabindex="-1" role="dialog" aria-labelledby="infoTitle" aria-hidden="true">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="infoTitle">보호소명</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <div>
                    <span id="infoImg"></span>
                </div>
                <div>
                    <b>주소 :</b><br>
                    <span id="infoAddr"></span><span id="infoAddr2"></span>
                </div><br>
                <div>
                    <b>전화번호 :</b><br>
                    <span id="infoTel"></span>
                </div><br>
                <div>
                    <b>소개 :</b><br>
                    <span id="infoContent"></span>
                </div>
            </div>
        </div>
    </div>
</div>

 

js

let index = {

    init: function() {
        // 동적으로 생성된 .shelterName 요소에 클릭 이벤트를 바인딩
        $(document).on("click", ".shelterName", function() {

            var shelterId = $(this).attr("data-shelter-id");
            console.log(shelterId);
            index.shelterInfo(shelterId);
        });
    },

    shelterInfo: function(shelterId) {
        let data = {
            id: shelterId
        };

        console.log("shelterInfo data: " + JSON.stringify(data));
        $.ajax({
            type: "POST",
            url: `/shelterInfo/${data.id}`,
            data: JSON.stringify(data),
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        }).done(function(resp) {
            console.log("response: " + JSON.stringify(resp));

            let tmp = document.getElementById("infoTitle");
            tmp.innerHTML = resp.title;

            tmp = document.getElementById("infoAddr");
            tmp.innerHTML = resp.address;

            tmp = document.getElementById("infoAddr2");
            tmp.innerHTML = resp.address2;

            tmp = document.getElementById("infoTel");
            tmp.innerHTML = resp.tel;

            tmp = document.getElementById("infoContent");
            tmp.innerHTML = resp.content;

        }).fail(function(error) {
            console.log(JSON.stringify(error));
        });
    },
}

index.init();

 

Controller

map에 담은 이유는 보호소 정보 입력시 파일(이미지)도 받았는데 이 정보도 같이 한 번에 넘겨주기 위해 entity, dto가 아닌 map에 담아서 view에 넘겨주었다.

@PostMapping("/shelterInfo/{id}")
public Map<String,String> view(@PathVariable int id) {
    ShelterEntity shelterEntity = shelterService.view(id);

    Map<String,String> map = new HashMap<String,String>();
    String idStr = Integer.toString(id);
    map.put("id",idStr);
    map.put("title",shelterEntity.getTitle());
    map.put("content",shelterEntity.getContent());
    map.put("address",shelterEntity.getAddress());
    map.put("address2",shelterEntity.getAddress2());

    double lonVal = shelterEntity.getLon();
    String lonStr = Double.toString(lonVal);
    map.put("lon",lonStr);

    double latVal = shelterEntity.getLat();
    String latStr = Double.toString(latVal);
    map.put("lat",latStr);

    map.put("tel",shelterEntity.getTel());

    map.put("username",shelterEntity.getUsername());

    int fileAttacchedVal = shelterEntity.getFileAttached();
    String fileAttacchedStr = Integer.toString(fileAttacchedVal);
    map.put("fileAttached",fileAttacchedStr);


    int approvalVal = shelterEntity.getApproval();
    String approvalStr = Integer.toString(approvalVal);
    map.put("approval",approvalStr);

    List<BoardFileDto> boardFileDtos = shelterService.getFileList(id);
    for (BoardFileDto s : boardFileDtos) {
        String fileName = s.getStoredFileName();
        map.put("img",fileName);
    }

    return map;
}

 

Service

public ShelterEntity view(int id){
    return shelterRepository.findById(id).get();
}

 

'👩🏻‍💻 About 프로그래밍 > ect' 카테고리의 다른 글

다음 주소 API  (0) 2024.08.14
OAuth2.0 소셜 로그인  (0) 2024.08.13
인터페이스, UI, API  (0) 2024.07.22
REST, RESTful, REST API  (0) 2024.07.22
HTTP 메서드 - POST, PUT, GET, PATCH, DELETE  (0) 2024.07.20

블로그의 정보

Hello 춘기's world

볼빵빵오춘기

활동하기