목차

Kakao 지도 API 신청 (앱 키 발급)

애플리케이션 추가하기

Web 플랫폼 등록

앱 키 발급

프로젝트 생성

기본 설정

application.yml 설정

Kakao 지도 API 연동, 위치 찾기 구현

컨트롤러, 프론트 페이지 추가

컨트롤러 생성

메인 페이지 생성

Kakao 지도 API 가이드 링크

프로젝트 구조

GitHub 링크

실행화면

Kakao 지도 API 신청 (카카오 앱 키 발급)

kakao developers 사이트에 접속하여 로그인을 합니다.

사이트 링크 : https://developers.kakao.com

상단 메뉴 "내 애플리케이션" 항목을 누릅니다.

참고사진_1

애플리케이션 추가하기

"애플리케이션 추가하기" 버튼을 누릅니다.

참고사진_2

앱 이름, 회사명, 카테고리 항목을 입력 및 선택 후 "저장" 버튼을 누릅니다.

참고사진_3

추가한 애플리케이션을 선택합니다.

참고사진_4

왼쪽 메뉴에서 "플랫폼" 메뉴를 선택 후 하단 "Web 플랫폼 등록" 버튼을 누릅니다.

참고사진_5

Web 플랫폼 등록

로컬에서 API 요청 할 경우 "http://localhost:8080" 입력하시면 됩니다.

사이트 도메인을 입력 후 "저장" 버튼을 누릅니다.
참고사진_6

카카오 앱 키 발급

Kakao 지도 API는 JavaScript 키를 사용합니다.

왼쪽 메뉴에서 "앱 키" 메뉴에서 발급된 앱 키를 확인하실 수 있습니다.

참고사진_7

프로젝트 생성

STS 상단 메뉴 > File > New > Spring Starter Project 선택합니다.

참고사진_8

New Spring Starter Project

Name, Java Version, Group, Artifact, Description, Package 항목을 입력한 후 아래 "Next" 버튼을 누릅니다.

참고사진_9

New Spring Starter Dependencies

검색란에 의존성 키워드를 입력하여 의존성을 추가합니다. (녹색 영역 참조)

필수 의존성 [Lombok, Mustache, Spring Web] 추가 후 아래 "Finish" 버튼을 누릅니다.

참고사진_10

기본 설정

application.yml 설정

application.properties파일의 확장자를 application.yml 확장자로 변경합니다.

application.yml
spring:
  application:
    name: map
    
#mustache UTF-8
server:
  servlet:
    encoding:
      force: true
 
---
#mustache 설정
spring:
  mustache:
    cache: false
    servlet:
      expose-request-attributes: true #mustache에서 csrf 토큰 변수 오류 발생 때문에 추가
      expose-session-attributes: true #세션

Kakao 지도 API 연동, 위치 찾기 구현

컨트롤러, 프론트 페이지 추가

컨트롤러 생성

controller 패키지를 생성 후 MainController 클래스 파일을 생성합니다.

패키지 위치 : com.example.map.controller

MainController.java
package com.example.map.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainController {

    /**
     * 메인 페이지
     * @return
     */
    @GetMapping("/")
    public String index() {
        return "index";
    }
    
}

메인 페이지 생성

templates에 index.mustache 파일을 생성합니다.

JavaScript 키 설정: <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=[JavaScript 키]&libraries=services"></script>

index.mustache
<!DOCTYPE html>
<html lang="ko"> 
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>메인 페이지</title>
        <style>
            .container {
                width: 800px !important;
            }
            
            .map_wrap {
                position:relative;
                width:100%;
                height:650px;
            }
            
            .title {
                font-weight:bold;
                display:block;
            }
            
            .hAddr {
                position:absolute;
                left:10px;
                top:10px;
                border-radius: 2px;
                background:#fff;
                background:rgba(255,255,255,0.8);
                z-index:1;
                padding:5px;
            }
            
            #centerAddr {
                display:block;
                margin-top:2px;
                font-weight: normal;
            }
            
            .bAddr {
                padding:5px;
                text-overflow: ellipsis;
                overflow: hidden;
                white-space: nowrap;
            }
        </style>
    </head>
    <body>
        
        <div class="container">
            <div class="row">
                <div class="col-md-12 pt-5">
                    <div class="card mb-4">
                        <h5 class="card-header text-center">메인 페이지</h5>
                        <div class="card-body">
                            <div>
                                찾기 : <input type="text" value="" id="keyword" size="15">
                                <button type="button" class="btn btn-outline-dark btn-sm" onclick="searchPlaces();">검색</button>
                            </div>
                            <div class="text-center">
                                <div class="map_wrap">
                                    <div id="map" style="width:100%;height:100%;position:relative;overflow:hidden;"></div>
                                    <div class="hAddr">
                                        <span class="title">지도중심기준 행정동 주소정보</span>
                                        <span id="centerAddr"></span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
        <script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=2442a1b67c88c27cf4ad4a7939973aa5&libraries=services"></script>
        <script>
            $(document).ready(function(){

                // 마커를 클릭하면 장소명을 표출할 인포윈도우 입니다
                var infowindow = new kakao.maps.InfoWindow({zIndex:1});

                var mapContainer = document.getElementById('map'), // 지도를 표시할 div 
                    mapOption = {
                        center: new kakao.maps.LatLng(37.56431006014851, 126.97672880129785), // 지도의 중심좌표
                        level: 3 // 지도의 축소, 확대 레벨 1 ~ 14
                    };  

                // 지도를 생성합니다    
                var map = new kakao.maps.Map(mapContainer, mapOption); 
                
                // 일반 지도와 스카이뷰로 지도 타입을 전환할 수 있는 지도타입 컨트롤을 생성합니다
                var mapTypeControl = new kakao.maps.MapTypeControl();

                // 지도에 컨트롤을 추가해야 지도위에 표시됩니다
                // kakao.maps.ControlPosition은 컨트롤이 표시될 위치를 정의하는데 TOPRIGHT는 오른쪽 위를 의미합니다
                map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);

                // 지도 확대 축소를 제어할 수 있는  줌 컨트롤을 생성합니다
                var zoomControl = new kakao.maps.ZoomControl();
                map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);

                // 장소 검색 객체를 생성합니다
                var ps = new kakao.maps.services.Places(); 

                // 기본값 장소 설정
                ps.keywordSearch('서울역', placesSearchCB);
                
                getInfo = function() {
                    // 지도의 현재 중심좌표를 얻어옵니다 
                    var center = map.getCenter(); 
                    
                    // 지도의 현재 레벨을 얻어옵니다
                    var level = map.getLevel();
                    
                    // 지도타입을 얻어옵니다
                    var mapTypeId = map.getMapTypeId(); 
                    
                    // 지도의 현재 영역을 얻어옵니다 
                    var bounds = map.getBounds();
                    
                    // 영역의 남서쪽 좌표를 얻어옵니다 
                    var swLatLng = bounds.getSouthWest(); 
                    
                    // 영역의 북동쪽 좌표를 얻어옵니다 
                    var neLatLng = bounds.getNorthEast(); 
                    
                    // 영역정보를 문자열로 얻어옵니다. ((남,서), (북,동)) 형식입니다
                    var boundsStr = bounds.toString();
                                        
                    var message = '지도 중심좌표는 위도 ' + center.getLat() + ', <br>';
                    message += '경도 ' + center.getLng() + ' 이고 <br>';
                    message += '지도 레벨은 ' + level + ' 입니다 <br> <br>';
                    message += '지도 타입은 ' + mapTypeId + ' 이고 <br> ';
                    message += '지도의 남서쪽 좌표는 ' + swLatLng.getLat() + ', ' + swLatLng.getLng() + ' 이고 <br>';
                    message += '북동쪽 좌표는 ' + neLatLng.getLat() + ', ' + neLatLng.getLng() + ' 입니다';
                    
                    //console.log(message);
                }
                 
                // 검색
                searchPlaces = function() {
                   if (!$("#keyword").val().replace(/^\s+|\s+$/g, '')) {
                        alert('키워드를 입력하세요.');
                        $("#keyword").val("");
                        $("#keyword").focus();
                        return false;
                    }

                    // 장소검색 객체를 통해 키워드로 장소검색을 요청합니다
                    ps.keywordSearch($("#keyword").val(), placesSearchCB);
                    
                    getInfo();
                }
                
                $("#keyword").keyup(function(e){
                    if (e.keyCode == 13) {
                        searchPlaces();
                    }
                });

                // 키워드 검색 완료 시 호출되는 콜백함수 입니다
                function placesSearchCB (data, status, pagination) {
                    if (status === kakao.maps.services.Status.OK) {

                        // 검색된 장소 위치를 기준으로 지도 범위를 재설정하기위해
                        // LatLngBounds 객체에 좌표를 추가합니다
                        var bounds = new kakao.maps.LatLngBounds();

                        for (var i=0; i<data.length; i++) {
                            displayMarker(data[i]);    
                            bounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
                        }       

                        // 검색된 장소 위치를 기준으로 지도 범위를 재설정합니다
                        map.setBounds(bounds);
                        map.setLevel(6);
                    } 
                }

                // 지도에 마커를 표시하는 함수입니다
                function displayMarker(place) {
                    
                    // 마커를 생성하고 지도에 표시합니다
                    var marker = new kakao.maps.Marker({
                        map: map,
                        position: new kakao.maps.LatLng(place.y, place.x) 
                    });

                    // 마커에 클릭이벤트를 등록합니다
                    kakao.maps.event.addListener(marker, 'click', function() {
                        // 마커를 클릭하면 장소명이 인포윈도우에 표출됩니다
                        infowindow.setContent('<div style="padding:5px;font-size:12px;">' + place.place_name + '</div>');
                        infowindow.open(map, marker);
                    });
                }
                
                // 주소-좌표 변환 객체를 생성합니다
                var geocoder = new kakao.maps.services.Geocoder();

                var marker = new kakao.maps.Marker(), // 클릭한 위치를 표시할 마커입니다
                    infowindow = new kakao.maps.InfoWindow({zindex:1}); // 클릭한 위치에 대한 주소를 표시할 인포윈도우입니다

                // 현재 지도 중심좌표로 주소를 검색해서 지도 좌측 상단에 표시합니다
                searchAddrFromCoords(map.getCenter(), displayCenterInfo);

                // 지도를 클릭했을 때 클릭 위치 좌표에 대한 주소정보를 표시하도록 이벤트를 등록합니다
                kakao.maps.event.addListener(map, 'click', function(mouseEvent) {
                    searchDetailAddrFromCoords(mouseEvent.latLng, function(result, status) {
                        if (status === kakao.maps.services.Status.OK) {
                            var detailAddr = !!result[0].road_address ? '<div>도로명주소 : ' + result[0].road_address.address_name + '</div>' : '';
                            detailAddr += '<div>지번 주소 : ' + result[0].address.address_name + '</div>';
                            
                            var content = '<div class="bAddr">' +
                                            '<span class="title">법정동 주소정보</span>' + 
                                            detailAddr + 
                                        '</div>';

                            // 마커를 클릭한 위치에 표시합니다 
                            marker.setPosition(mouseEvent.latLng);
                            marker.setMap(map);

                            // 인포윈도우에 클릭한 위치에 대한 법정동 상세 주소정보를 표시합니다
                            infowindow.setContent(content);
                            infowindow.open(map, marker);
                        }   
                    });
                });

                // 중심 좌표나 확대 수준이 변경됐을 때 지도 중심 좌표에 대한 주소 정보를 표시하도록 이벤트를 등록합니다
                kakao.maps.event.addListener(map, 'idle', function() {
                    searchAddrFromCoords(map.getCenter(), displayCenterInfo);
                });

                function searchAddrFromCoords(coords, callback) {
                    // 좌표로 행정동 주소 정보를 요청합니다
                    geocoder.coord2RegionCode(coords.getLng(), coords.getLat(), callback);         
                }

                function searchDetailAddrFromCoords(coords, callback) {
                    // 좌표로 법정동 상세 주소 정보를 요청합니다
                    geocoder.coord2Address(coords.getLng(), coords.getLat(), callback);
                }

                // 지도 좌측상단에 지도 중심좌표에 대한 주소정보를 표출하는 함수입니다
                function displayCenterInfo(result, status) {
                    if (status === kakao.maps.services.Status.OK) {
                        var infoDiv = document.getElementById('centerAddr');

                        for(var i = 0; i < result.length; i++) {
                            // 행정동의 region_type 값은 'H' 이므로
                            if (result[i].region_type === 'H') {
                                infoDiv.innerHTML = result[i].address_name;
                                break;
                            }
                        }
                    }    
                }
                
            });
        </script>
    </body>
</html>

Kakao 지도 API 가이드 링크

https://apis.map.kakao.com/web/guide/

프로젝트 구조

참고사진_11

GitHub 링크

전체 소스 다운로드

실행화면

참고사진_12

©2024, DevDream