주니어 기초 코딩공부/JSP 기초

[jsp] 네이버 지역 api 소스코드에 적용하기

jju_developer 2024. 7. 22. 23:50
728x90

안녕하세요 jju_developer입니다.

 

지역 검색 api를 네이버 지도에 연동해보도록 하겠습니다.

 

연동신청 바로가기

 

[jsp] 네이버 지도 api 연동 신청방법

안녕하세요~ jju_developer입니다. 오늘도 퇴근 후 돌아왔습니다! 하루를 돌아보며... 네이버 지도 api 연동에 대해 기록하고자 합니다! 회사 코드에서는 이미 네이버 지도 api는 있지만 네이버 지

jju240.tistory.com

 

 

 

1, 검색창 생성 & 네이버 지도 영역 생성

<input type="text" id="addressInput" placeholder="주소를 입력하세요" >
<input type="button" id="searchAddressBtn" value="검색">
</div>
<label for="map">지도&nbsp;&nbsp;&nbsp;</label>
<div id="map" style="width:100%;height:400px;"></div>
<input type="text" id="zoom" name="zoom" value="<c:out value="${uifunc:nullConvertDefault(custBizDetail.zoom, 10)}"/>" style="border:none;width:25px">)

영역은 id ="map"

주소를 입력하는 부분의 id는 addressInput입니다.

 

2. 처음 페이지가 준비될때, 초기 값 세팅

초기 위경도는 네이버로 지정.

<script>

    $(document).ready(function(){

       infoWindow = new naver.maps.InfoWindow({
           anchorSkew: true
       });

       var position = new naver.maps.LatLng(37.3595704, 127.105399);
       map = new naver.maps.Map("map", {
           center: position,
           zoom: 10
       });

       map.setCursor('pointer');

       // 엔터로 검색
       $("#addressInput").keyup(function(e)  {
           if(e.keyCode == 13) {
               var address = $("#addressInput").val();
               searchAddressToCoordinate(address);
               return false;
           }
       });
       
       // 검색 버튼 클릭시 
       $("#searchAddressBtn").on('click', function(){
            var address = $("#addressInput").val();
            searchAddressToCoordinate(address);
       });

        initMarker();

        naver.maps.Event.addListener(map, 'zoom_changed', function (zoom) {
            $("#zoom").val(zoom);
        });


    if ("update" == $("#cmd").val()) {

        setDistrictCombo();
    }

    map.addListener('click', function(e) {
        var latlng = e.coord;
        $("#lat").val(latlng.lat());
        $("#lng").val(latlng.lng());
        //createMarker(e.coord);
        searchCoordinateToAddress(e.coord);  // 좌표로 주소 검색
    });

});

 

addressInput를 엔터로 검색 및 검색 버튼 클릭 했을때

address에 검색한 주소의 값을 저장하고, searchAddressToCoordinate에 해당 주소를 넘깁니다.

 

 

 

3. searchAddressToCoordinate

 

해당 address를 naver.maps.Service.geocode에 쿼리를 키값으로 넘겨줍니다.

 

geocode라는 펑션으로 쿼리에 주소를 넣었을때 오류가 나면 something Wrong!이라는 알림이 뜹니다.

 

만약 도로명 주소의 결과 값이 없으면, 주소를 찾을 수 없습니다가 뜨는것이 아니라

지역을 검색하는 ajax를 호출하여 지역의 address를 가져올 수 있도록 구현하였습니다.

 

url: "/admin/monitoring/selectGpsInfo.do" 이며, 해당 ajax 컨트롤러도 아래에 다루겠습니다.

function searchAddressToCoordinate(address) {

        console.log('String searchAddressToCoordinate  '+ address);
        naver.maps.Service.geocode({
            query: address
        }, function(status, response) {
            if (status === naver.maps.Service.Status.ERROR) {
                return alert('Something Wrong!');
            }

            // 도로명 검색의 결과 값이 없으면 지역 검색 ajax 호출
            if (response.v2.meta.totalCount === 0) {
                // return alert('주소를 찾을 수 없습니다.');

                $.ajax({
                    url: "/admin/monitoring/selectGpsInfo.do",
                    type: "POST",
                    data: "address="+address,
                    dataType: "JSON",
                    async: false,
                    success: function(data){

                        if (!data || !data.items || !data.items.myArrayList || !data.items.myArrayList[0] ||
                            typeof data.items.myArrayList[0].map === "undefined" ||
                            data.items.myArrayList[0].map === null ||
                            data.items.myArrayList[0].map === "") {
                            return alert('주소를 찾을 수 없습니다.');
                        }

                        var addressJsonObject = data.items.myArrayList[0].map;
                        // 네이버 지역검색 api의 위경도 값이 반대로 되어 있으니 주의
                        var latitude = addressJsonObject.mapy / 10000000;
                        var longitude = addressJsonObject.mapx / 10000000;

                        var htmlAddresses = [],
                        point = new naver.maps.Point(longitude, latitude);
                        $("#lat").val(latitude);
                        $("#lng").val(longitude);

                        if (addressJsonObject.roadAddress) {
                            htmlAddresses.push('[도로명 주소] ' + addressJsonObject.roadAddress);
                        }

                        if (addressJsonObject.address) {
                            htmlAddresses.push('[지번 주소] ' + addressJsonObject.address);
                        }

                        var searchedAddress = address; // 검색한 주소를 그대로 사용
                        $("#addressResult").html('<h4>검색 결과</h4><p>' + searchedAddress + '</p>'); // 검색 결과를 화면에 표시

                        infoWindow.setContent([
                            '<div style="padding:10px;min-width:200px;line-height:150%;">',
                            '<h4 style="margin-top:5px;">검색 주소 : '+ address +'</h4><br />',
                            htmlAddresses.join('<br />'),
                            '</div>'
                        ].join('\n'));

                        map.setCenter(point);
                        map.setZoom(15);
                        infoWindow.open(map, point);

                    },
                    error: function(request, status, error){
                        alert("error:"+error+"\n"+"code:"+request.status+"\n"+"message:"+request.responseText+"\n");
                    }
                });
            } else {
                var htmlAddresses = [],
                item = response.v2.addresses[0],
                point = new naver.maps.Point(item.x, item.y);

                $("#lat").val(item.y);
                $("#lng").val(item.x);

                if (item.roadAddress) {
                    htmlAddresses.push('[도로명 주소] ' + item.roadAddress);
                }

                if (item.jibunAddress) {
                    htmlAddresses.push('[지번 주소] ' + item.jibunAddress);
                }

                if (item.englishAddress) {
                    htmlAddresses.push('[영문명 주소] ' + item.englishAddress);
                }

                var searchedAddress = address; // 검색한 주소를 그대로 사용
                $("#addressResult").html('<h4>검색 결과</h4><p>' + searchedAddress + '</p>'); // 검색 결과를 화면에 표시

                infoWindow.setContent([
                    '<div style="padding:10px;min-width:200px;line-height:150%;">',
                    '<h4 style="margin-top:5px;">검색 주소 : '+ address +'</h4><br />',
                    htmlAddresses.join('<br />'),
                    '</div>'
                ].join('\n'));

                map.setCenter(point);
                map.setZoom(15);
                infoWindow.open(map, point);
            }


        });
    }

 

 

4. url: "/admin/monitoring/selectGpsInfo.do" 

Ajax 컨트롤러

/**
	 * 네이버 지도 지역검색 api ajax 호출 controller
	 * @author gjoh
	 * @param commandMap
	 * @param model
	 * @return List
	 * @exception Exception
	 */
	@ResponseBody
	@RequestMapping(value = "/admin/monitoring/selectGpsInfo.do", method = RequestMethod.POST, produces="text/plain;charset=UTF-8")
	public String selectAddressInfo(@RequestParam Map<String, Object> commandMap, ModelMap model) throws Exception {

		Gson gson = new Gson();
		HashMap<String, Object> map = new HashMap<String, Object>();

		String clientId = "jju12345678954654654"; //애플리케이션 클라이언트 아이디
		String clientSecret = "비밀키 제공받은거 쓰세요"; //애플리케이션 클라이언트 시크릿

		String text = "";
		String address = String.valueOf(commandMap.get("address"));

		try {
			text = URLEncoder.encode(address, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("검색어 인코딩 실패",e);
		}

		String apiURL = "https://openapi.naver.com/v1/search/local.json?query=" + text;    // 지역 검색 JSON 결과
		//String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + text;    // 블로그 검색 JSON 결과
		//String apiURL = "https://openapi.naver.com/v1/search/blog.xml?query="+ text; // XML 결과

		Map<String, String> requestHeaders = new HashMap<>();
		requestHeaders.put("X-Naver-Client-Id", clientId);
		requestHeaders.put("X-Naver-Client-Secret", clientSecret);

		// 지역 검색 결과값을 string 으로 가져옴.
		String responseBody = HttpUtil.get(apiURL,requestHeaders);
		System.out.println(responseBody);

		// string을 jsonObject로 변환
		JSONObject jsonObject = new JSONObject(responseBody);
		System.out.println("jsonObject ::: " +jsonObject);

		// jsonObject중에 items 키값을 jsonArray로 가져온 후 map에 넣는다.
		JSONArray jsonArray = jsonObject.getJSONArray("items");
		System.out.println("jsonArray ::: " + jsonArray);
		map.put("items", jsonArray);

		// map을 string으로 변환 하여 return
		String jsonString = gson.toJson(map);

		return jsonString;
	}

 

 

//String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + text;    // 블로그 검색 JSON 결과
//String apiURL = "https://openapi.naver.com/v1/search/blog.xml?query="+ text; // XML 결과

위 두 라인은 주석처리 하였습니다.

해보니까 /blog로 하면 최신 블로그 글들이 json으로 불러오더라구요!

 

여기서는 블로그 글 검색은 필요 없어서 지웠습니다.

 

저는 여기서 String apiURL = "https://openapi.naver.com/v1/search/local.json?query=" + text;    // 지역 검색 JSON 결과 이것을 활용했습니다.

 

처음에 네이버 

// 지역 검색 결과값을 string 으로 가져옴.
String responseBody = HttpUtil.get(apiURL,requestHeaders);
System.out.println(responseBody);

// string을 jsonObject로 변환
JSONObject jsonObject = new JSONObject(responseBody);
System.out.println("jsonObject ::: " +jsonObject);

// jsonObject중에 items 키값을 jsonArray로 가져온 후 map에 넣는다.
JSONArray jsonArray = jsonObject.getJSONArray("items");
System.out.println("jsonArray ::: " + jsonArray);
map.put("items", jsonArray);

// map을 string으로 변환 하여 return
String jsonString = gson.toJson(map);

호출해서 가져온 responseBody를 string으로 변환하여 jsp에 넘겨주었습니다.

 

 

위에서 정의한 apiURL 를 http get 방식으로 호출하는 클래스를 따로 만들어 주었습니다.

한 클래스에 다 있어도 되지만, 저는 util 클래스가 따로 있어서 코드의 재사용과

가독성을 위해서 따로 만들게 되었습니다.

 

5. Http get방식으로 api 서버를 호출

public class HttpUtil {
public static String get(String apiUrl, Map<String, String> requestHeaders){
		HttpURLConnection con = connect(apiUrl);
		try {
			con.setRequestMethod("GET");
			for(Map.Entry<String, String> header :requestHeaders.entrySet()) {
				con.setRequestProperty(header.getKey(), header.getValue());
			}


			int responseCode = con.getResponseCode();
			if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출
				return readBody(con.getInputStream());
			} else { // 오류 발생
				return readBody(con.getErrorStream());
			}
		} catch (IOException e) {
			throw new RuntimeException("API 요청과 응답 실패", e);
		} finally {
			con.disconnect();
		}
	}


	public static HttpURLConnection connect(String apiUrl){
		try {
			URL url = new URL(apiUrl);
			return (HttpURLConnection)url.openConnection();
		} catch (MalformedURLException e) {
			throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
		} catch (IOException e) {
			throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
		}
	}


	public static String readBody(InputStream body){
		InputStreamReader streamReader = new InputStreamReader(body);


		try (BufferedReader lineReader = new BufferedReader(streamReader)) {
			StringBuilder responseBody = new StringBuilder();


			String line;
			while ((line = lineReader.readLine()) != null) {
				responseBody.append(line);
			}


			return responseBody.toString();
		} catch (IOException e) {
			throw new RuntimeException("API 응답을 읽는 데 실패했습니다.", e);
		}
	}
}

 

 

질문이나 수정사항은 언제나 댓글 환영입니다!! ^.^

 

오늘도 수고하셨습니다~!

728x90