[Spring Boot] Google Map API 사용하기

Wonjun Seo·2023년 9월 3일
0

프로젝트를 하다보니 구글 지도 API를 사용할 일이 생겨서 이 포스트를 작성하게 되었습니다.

스프링 부트 프로젝트에서는 다음과 같은 과정을 통해 Geocoding API를 사용할 수 있습니다.

우선, 이 포스트는 이미 Google Cloud에 Geocoder API 서비스가 등록되어 있다는 전제하에 작성 되었습니다.


HTML에서 아래 스크립트를 추가

<script src="https://maps.googleapis.com/maps/api/js?key=KEY_VALUE&callback=initMap"></script>

src 주소에서 마지막 부분에 있는 callback 뒤의 값은 지오코딩을 수행할 함수 이름으로 바꿔주어야 한다.


다음은 지오코딩을 수행하는 JS 메서드 코드입니다.

function initMap() {
    // Geocoder 객체를 선언
    const geocoder = new google.maps.Geocoder();

    // 지도에서 보여주고 싶은 장소의 주소 또는 이름
    const address = "Place address or name";

    geocoder.geocode({ address: address }, (results, status) => {
        if (status === 'OK') {
            // 해당 장소의 위도와 경도 가져오기
            const latitude = results[0].geometry.location.lat();
            const longitude = results[0].geometry.location.lng();
            console.log('위도:', latitude);
            console.log('경도:', longitude);

            // 장소의 위도와 경도 정보를 담은 객체 선언
            let hotel = {lat: latitude, lng: longitude};

            // 지도에 나타내고 싶은 장소의 마커 선언
            var mapOptions = {
                center: hotel, // 지도의 중심에 표시할 장소
                zoom: 16, // 몇 배 확대해서 보여줄 것인지
                disableDefaultUI:true,
                zoomControl: true // 지도 확대/축소 가능 여부
            };

            // 지도를 보여줄 div 영역의 id 값과 위에서 지정한 옵션을 map에 등록
            var map = new google.maps.Map(
                document.getElementById("googleMap"), mapOptions );
 
            // 지도에 표시할 마커를 생성
            var marker = new google.maps.Marker({position: hotel, map: map});

          	// 마커를 클릭했을 때 보여주고 싶은 문구가 있을 경우 추가
            var infoWindow = new google.maps.InfoWindow({
                content: `
                    <h6>${address}</h6>
                    <a href="#">Go to Hotel Details</a>
                `
        	});

          	// 마커 클릭 이벤트 등록
            marker.addListener('click', () => {
                infoWindow.open(map, marker);
            });
     	} else {
              console.error('지오코딩 실패:', status);
        }
    });
}

만약, 여러 개의 장소를 하나의 지도에 동시에 보여주고 싶은 경우에는 다음과 같이 JS 코드를 작성하면 됩니다.

// 전역 변수로 map을 선언합니다.
let map;

/**
 * myMap 함수 정의
 * @returns {Promise<void>}
 */
const myMap = async (city) => {
    // 도시에 있는 호텔 리스트를 불러오는 url 정의
    const url = `/api/v1/business/loadHotelList?city=${city}`;

    // 도시에 있는 호텔 리스트를 불러옴
    const response = await axios.get(url);

    const data = response.data;
    console.log(data);

    map = null;

    // GedCoder 변수 선언
    let geocoder = new google.maps.Geocoder();

    geocoder.geocode({ address: city }, (cityResults, cityStatus) => {
        if (cityStatus === 'OK') {
            // 검색된 도시의 위도와 경도 가져오기
            const cityLat = cityResults[0].geometry.location.lat();
            const cityLng = cityResults[0].geometry.location.lng();

            console.log('도시 위도:', cityLat);
            console.log('도시 경도:', cityLng);

            const cityLocation = {lat: cityLat, lng: cityLng};

            // 각 호텔의 위치를 마커로 표시
            for (let hotel of data) {
                let id = hotel.id;
                let hotelAddress = hotel.hotelName;

                geocoder.geocode({address: hotelAddress}, (results, status) => {
                    if (status === 'OK') {
                        // 위도와 경도 가져오기
                        let latitude = results[0].geometry.location.lat();
                        let longitude = results[0].geometry.location.lng();
                        console.log('위도:', latitude);
                        console.log('경도:', longitude);

                        let hotel = {lat: latitude, lng: longitude};
                        
                        // 지도의 중심을 검색된 도시로 설정
                        var mapOptions = {
                            center: cityLocation,
                            zoom: 10,
                            disableDefaultUI: true,
                            zoomControl: true
                        };

                        // map을 초기화합니다.
                        if (!map) {
                            map = new google.maps.Map(
                                document.getElementById("googleMap"), mapOptions);
                        }

                        var marker = new google.maps.Marker({position: hotel, map: map});

                        var infoWindow = new google.maps.InfoWindow({
                            content: `
                                <h6>${hotelAddress}</h6>
                                <a href="#">호텔 상세 정보로 이동</a>
                            `
                        });

                        marker.addListener('click', () => {
                            infoWindow.open(map, marker);
                        });
                    } else {
                        console.error('GeoCoding Failed: ', status);
                    }
                });
            }

        } else {
            console.error('GeoCoding Failed: ', cityStatus);
        }
    });


};

/**
 * Google Maps API 로드 후에 myMap 메서드를 호출
 */
function initMap() {
    console.log('initMap()');
    const city = document.querySelector('input#city').value;
    myMap(city);
}

/**
 * DOMContentLoaded 이벤트 핸들러에서 Google Maps 스크립트를 동적으로 로드합니다.
 */
document.addEventListener('DOMContentLoaded', () => {
    const googleMapsScript = document.createElement('script');
    googleMapsScript.src = 'https://maps.googleapis.com/maps/api/js?key=KEY_VALUE&callback=initMap';
    googleMapsScript.async = true;
    googleMapsScript.defer = true;
    document.head.appendChild(googleMapsScript);
});

const searchByCity = () => {
    const city = document.querySelector('input#city').value;
    initMap(city);
};

const searchBtn = document.querySelector('button#searchBtn');
searchBtn.addEventListener('click', searchByCity);

위의 코드는 사용자가 특정 도시를 검색했을 때 해당 도시에 있는 모든 호텔 리스트를 지도에 표시하기 위한 코드들입니다.

지도에 여러 개의 마커를 동시에 표시하기 위해서는 선언된 map 변수를 매번 초기화해서 사용해야 합니다.

또한, googleMapsScript에 하나의 callback 함수만 선언되어 있으므로, Google Map과 관련된 작업은 initMap 함수 내에서만 처리해야 합니다.

0개의 댓글