ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JS]도로명주소API를 활용해서 주소 검색 솔루션 만들기
    Javascript 2020. 1. 15. 01:45

    최근 지도를 기반으로 서비스를 제공하는 플랫폼이 많아지고 있습니다.

    현재 저 역시, 지도를 기반으로 컨텐츠를 보여주는 서비스를 만들고 있습니다.

     

    이번 포스팅은, 도로명주소API를 통해 사용자가 입력한 값에 대한 결과값을 받아오는 과정을 남기고자 합니다.

    최근, 도로명주소API 말고 네이버나 카카오에서도 비슷한 서비스를 제공하고 있는데요.

     

    각각의 API에 따라 RESPONSE 값이 다르므로, 본인이 개발하고 있는 서비스에 맞는 API를 사용해야 합니다.

    먼저 각각의 서비스가 어떤 결과 값을 제공하는지 간단하게 알아봐야 합니다.

     

    가장 먼저 카카오의 지도/로컬 서비스는 여러가지가 있지만, 사용자의 텍스트를 입력해서 결과를 받아올 수 있는

    주소검색, 키워드로 장소 검색 두 가지를 대표적인데 각 서비스마다 응답 값이 다른 것을 확인해봅시다.

     

    // 주소검색 RESPONSE
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=UTF-8
    {
      "meta": {
        "total_count": 4,
        "pageable_count": 4,
        "is_end": true
      },
      "documents": [
        {
          "address_name": "전북 익산시 부송동 100",
          "y": "35.97664845766847",
          "x": "126.99597295767953",
          "address_type": "REGION_ADDR",
          "address": {
            "address_name": "전북 익산시 부송동 100",
            "region_1depth_name": "전북",
            "region_2depth_name": "익산시",
            "region_3depth_name": "부송동",
            "region_3depth_h_name": "삼성동",
            "h_code": "4514069000",
            "b_code": "4514013400",
            "mountain_yn": "N",
            "main_address_no": "100",
            "sub_address_no": "",
            "zip_code": "570972",
            "x": "126.99597295767953",
            "y": "35.97664845766847"
          },
          "road_address": {
            "address_name": "전북 익산시 망산길 11-17",
            "region_1depth_name": "전북",
            "region_2depth_name": "익산시",
            "region_3depth_name": "부송동",
            "road_name": "망산길",
            "underground_yn": "N",
            "main_building_no": "11",
            "sub_building_no": "17",
            "building_name": "",
            "zone_no": "54547",
            "y": "35.976749396987046",
            "x": "126.99599512792346"
          }
        },
        ...
      ]
    }
    
    https://developers.kakao.com/docs/restapi/local#주소-검색

     

    // 키워드 검색
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=UTF-8
    {
      "meta": {
        "same_name": {
          "region": [],
          "keyword": "카카오프렌즈",
          "selected_region": ""
        },
        "pageable_count": 14,
        "total_count": 14,
        "is_end": true
      },
      "documents": [
        {
          "place_name": "카카오프렌즈 코엑스점",
          "distance": "418",
          "place_url": "http://place.map.kakao.com/26338954",
          "category_name": "가정,생활 > 문구,사무용품 > 디자인문구 > 카카오프렌즈",
          "address_name": "서울 강남구 삼성동 159",
          "road_address_name": "서울 강남구 영동대로 513",
          "id": "26338954",
          "phone": "02-6002-1880",
          "category_group_code": "",
          "category_group_name": "",
          "x": "127.05902969025047",
          "y": "37.51207412593136"
        },
        ...
      ]
    }
    
    https://developers.kakao.com/docs/restapi/local#키워드로-장소-검색

    두 결과 값의 차이가 한 눈에 보입니다.

    주소 검색의 경우, 디테일한 주소에 대한 정보를 제공합니다.

    소재지에 대한 depth를 구분해서 제공해주며, 좌표, 법정동코드, 행정동코드, 우편번호를 받아 올 수 있습니다.

     

    하지만, 키워드 검색의 경우, 주소를 찾는 것 보다는 키워드에 해당하는 상가에 대한 정보를 위주로 받아오게 됩니다.

     

    개발 하고자 하는 시스템이 좌표를 기반으로 한다면 두 가지 서비스 중 어떤 것을 사용해도 상관이 없지만,

    법정동코드를 통해, DB를 조회하고 결과를 받아와야 한다면 주소검색 솔루션을 사용하는 것이 적합합니다.

     

    하지만 또 한가지 변수가 있는게, 카카오에서 제공하는 주소검색 서비스의 경우

    지역의 특정명칭 즉, '홍대입구' 로 검색했을 때 결과가 나오지 않는 단점이 존재합니다.

     

    따라서, 경우에 따라 키워드 검색과 주소검색 서비스를 혼용하여 원하는 정보를 받아올 수 있습니다.

     

     

    이야기가 잠시 산으로 갔는데, 다시 본론으로 돌아와서

    도로명주소API를 활용해서, 검색 결과를 받아오는 작업을 JS를 통해서 진행하겠습니다.

    도로명주소 개발자센터(https://www.juso.go.kr/addrlink/main.do?cPath=99MM)에서 API를 신청한 후 인증키를 발급받습니다.

     

    HTML,CSS 작업을 통해, 기본적인 세팅을 잡아줍니다.

    <form id="fsearch" name="fsearch" method="post" onsubmit="return false;">
    	<input type="text" name="keyword" style="ime-mode:active;" onchange="GetAddr();" onkeydown="enterSearch(); GetAddr();" id="fsearch_addr" placeholder="지번, 도로명, 지하철역 검색"/>
    	<button type="button" id="btn_search" onclick="GetAddr();"><img src="/public/images/btn_mapsearch.png" /></button>
    	<input type="hidden" name="currentPage" value="1"/>
    	<input type="hidden" name="countPerPage" value="10"/>
    	<input type="hidden" name="resultType" value="json"/> 
    	<input type="hidden" name="confmKey" value="도로명주소API KEY"/>
    </form>

     

    도로명주소API의 경우, 검색어필터링을 꼭! 적용해야 합니다.

    도로명주소 API 호출시 검색어에 특수문자 또는 OR, INSERT, UNION 등 SQL예약어가 포함될 경우 보안장비가 SQL INJECTION공격으로 간주하여 해당 IP를 차단시킬 수 있습니다. 사용자분들은 API호출시 검색어 필터링를 적용하여 주시기 바랍니다.

     

    때문에 검색어 필터링을 적용할 함수를 만들어 둡니다.

    <script>
    function checkSearchedWord(obj){
    	if(obj.value.length >0){
    		//특수문자 제거
    		var expText = /[%=><]/ ;
    		if(expText.test(obj.value) == true){
    			alert("특수문자를 입력 할수 없습니다.") ;
    			obj.value = obj.value.split(expText).join(""); 
    			return false;
    		}
    
    		//특정문자열(sql예약어의 앞뒤공백포함) 제거
    		var sqlArray = new Array(
    		//sql 예약어
    		"OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE", "DROP", "EXEC",
    		"UNION",  "FETCH", "DECLARE", "TRUNCATE" 
    		);
    
    		var regex;
    		for(var i=0; i<sqlArray.length; i++){
    			regex = new RegExp( sqlArray[i] ,"gi") ;
    
    			if (regex.test(obj.value) ) {
    				alert("\"" + sqlArray[i]+"\"와(과) 같은 특정문자로 검색할 수 없습니다.");
    				obj.value =obj.value.replace(regex, "");
    				return false;
    			}
    		}
    	}
    	return true ;
    }
    </script>

     

    이제 실제로 검색어를 도로명주소API에 접근을 요청하는 함수를 만듭니다.

    <script>
    function GetAddr()
    {
        // 도로명주소API 검색어 필터링 검사
        if(checkSearchedWord(document.fsearch.keyword) == false)
        {
            $("#fsearch_addr").val("");
            return false;
        }
        
        var txt = $("#fsearch_addr").val();
        
        if(txt.length >= 2)
        {
            $.ajax({
                url :"https://www.juso.go.kr/addrlink/addrLinkApiJsonp.do",
                type:"post",
                data:$("#fsearch").serialize(),
                dataType:"jsonp",
                crossDomain:true,
                success:function(r){
                    console.log(r);
                },
                fail:function(r)
                {
                    alert('알 수 없는 오류로 인해 실패하였습니다.');
                    return false;
                }
            });
        }
    }
    </script>

    이제 콘솔창에서 응답을 받고 있는지 확인해봅니다.

    '일산동구' 로 검색을 했을 때 나오는 결과값입니다.

    이 결과값을 입맛에 맞게 뽑아서 쓰면 되는겁니다.

     

    제가 작성한 코드의 부분입니다.

    참고하셔서 목적에 맞게 사용하시면 됩니다.

     

    <script>
    function GetAddr()
    {
        // 도로명주소API 검색어 필터링 검사
        if(checkSearchedWord(document.fsearch.keyword) == false)
        {
            $("#fsearch_addr").val("");
            return false;
        }
        
        var txt = $("#fsearch_addr").val();
        
        if(txt.length >= 2)
        {
            $.ajax({
                url :"https://www.juso.go.kr/addrlink/addrLinkApiJsonp.do",
                type:"post",
                data:$("#fsearch").serialize(),
                dataType:"jsonp",
                crossDomain:true,
                success:function(r){
                  // 결과 값 초기화
                  $('.search_result_title').remove();
                  $('.search_result_ul').remove();              
                  
                  // 에러코드
                  var errCode = data.results.common.errorCode;
                  var errDesc = data.results.common.errorMessage;
                  
                  // errorCode가 0인 경우 정상
                  if (errCode == '0') {
                  	// 받아온 결과가 1개 이상인 경우
                    if (data.results.common.totalCount > 0) {
                    $('.addr_list_inbox').append(
                      '<p class="search_result_title">검색 결과</p>'+
                      '<ul class="search_result_ul"></ul>'
                      );
                      $.each(data.results.juso, function(i, v) {                  
                        $('.search_result_ul').append(                  
                          "<li class='search_result_li'>"+
                            "<span class='search_result_addr'>"+
                              v['jibunAddr']+
                            "</span>"+
                          "</li>"                  
                          );
                        $('.search_result_addr').highlight(addr);
                      });
                    }
                    else {
                      $('.addr_list_inbox').append(
                        '<p class="search_result_title">검색 결과가 존재하지 않습니다.</p>'
                        );
                    }
                  }
                  else {
                    alert(errCode + '=' + errDesc);
                  }
                },
                fail:function(r)
                {
                    alert('알 수 없는 오류로 인해 실패하였습니다.');
                    return false;
                }
            });
        }
    }
    </script>

     

    위 코드의 결과입니다.

    도로명주소API 결과 화면

     

    댓글

Designed by Tistory.