ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • open api 로 우편번호 검색하기
    개발 2010.08.31 10:08
    우편번호 검색 api 는 인터넷 우체국사업자 홈페이지에서 회원가입없이 무료로 받을 수 있다.

    http://biz.epost.go.kr/eportal/custom/custom_9.jsp?subGubun=sub_3&subGubun_1=cum_17&gubun=m07

    아래는 간단하게 만든 우편번호 검색 메소드이다.

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.io.StringReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.Map;

    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.xml.sax.InputSource;
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;

    public ArrayList<String[]> getPostAndAddress(String name){
            final String apiurl = "http://biz.epost.go.kr/KpostPortal/openapi";
            String myApi = "발급받은 api 입력"
            ArrayList<String[]> addressInfo = new ArrayList<String[]>();
           
            HttpURLConnection conn = null;
            try{
                StringBuffer sb = new StringBuffer(3);
                sb.append(apiurl);
                sb.append("?regkey="+myApi+"&target=post&query=");
                sb.append(URLEncoder.encode(name,"EUC-KR"));
                String query = sb.toString();
               
                URL url = new URL(query);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestProperty("accept-language","ko");
               
                DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
                byte[] bytes = new byte[4096];
                InputStream in = conn.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                while(true){
                    int red = in.read(bytes);
                    if(red < 0)
                        break;
                    baos.write(bytes, 0, red);
                }
                String xmlData = baos.toString("euc-kr");
                baos.close();
                in.close();
                conn.disconnect();
               
                Document doc = docBuilder.parse(new InputSource(new StringReader(xmlData)));
                Element el = (Element)doc.getElementsByTagName("itemlist").item(0);
               
                for(int i=0; i<el.getChildNodes().getLength(); i++){
                    Node node = el.getChildNodes().item(i);
                    if(!node.getNodeName().equals("item")){
                        continue;
                    }
                    String address = node.getChildNodes().item(1).getFirstChild().getNodeValue();
                    String post = node.getChildNodes().item(3).getFirstChild().getNodeValue();
                   
                    addressInfo.add(new String[]{post.substring(0, 3), post.substring(4), address});
                }
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                try{if(conn != null) conn.disconnect(); } catch(Exception e){}
            }
           
            return addressInfo;
        }

    itemlist 태그의 자식노드들을 검색할때 자식노드가 item 인 경우만 체크해서 루프를 돌렸는데 왜냐하면 태그와 태그사이에 화이트문자(개행문자, 탭, 공백문자등) 이 있을 수 있기 때문이다. 이 문자들이 있으면 Text 타입의 노드로 인식을 하기 때문에 이런경우는 걸러내었다.

    이런 절차가 번거로우면 다음과 같이 화이트문자를 제거하고 파싱할 수 있다.
    기본값은 false 이다.

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setIgnoringElementContentWhitespace(true);



    위의 URL로 우편번호를 요청하게 되면 대략 다음과 같은 결과값을 가져온다.
           
    <?xml version="1.0" encoding="euc-kr" ?>
            <post>
              <itemlist>
                  <item>
                           <address><![CDATA[서울시 성동구 구의1동 1]]></address>
                           <postcd>111111</postcd>
                      </item>   
                      <item>        
                               <address><![CDATA[서울시 성동구 구의1동 2]]></address>        
                               <postcd>111112</postcd>      
                      </item>   
                      <item>        
                               <address><![CDATA[서울시 성동구 구의1동 3]]></address>        
                               <postcd>111113</postcd>      
                      </item> 
              </itemlist>
            </post>


    XML을 파싱해서 우편번호는 분리하고 주소값과 함께 문자열 배열에 넣는다. String[3]
    그리고 문자열 배열을 ArrayList 에 다시 넣는다.
    이 값은 JSP 에서 EL을 이용하여 쉽게 사용할 수 있다.

    소스가 완전하지는 않지만 이정도면 수정하여 사용가능할 듯 ㅋ

    '개발' 카테고리의 다른 글

    플리커 GPS 정보  (0) 2010.10.24
    엑셀함수 RATE()  (0) 2010.10.05
    open api 로 우편번호 검색하기  (8) 2010.08.31
    이미지에 워터마크 넣기  (0) 2010.08.30
    아이폰 웹개발시 팁  (0) 2010.07.29
    클래스 이름을 사용하여 요소찾기  (0) 2010.06.02

    댓글 8

    • 녹풍 2010.10.01 00:53

      안녕하세요. 이런 포스팅을 만나니 정말 반갑습니다. 우편번호 오픈API를 이용해 보려고 하고 있습니다. 저는 PHP예요.
      그런데 아무리 글자를 인코딩해서 쿼리를 날려 봐도 저쪽에서 인식을 못 합니다.
      다음 방법을 다 사용해 봤습니다.
      1) 파일 문자셋을 euc-kr 로 해서 보내 보기. 2)파일 문자셋을 euc-kr로 한 후 urlencode 함수로 보내 보기.
      3)파일 문자셋을 utf-8로 해서 inconv 함수로 euc-kr로 바꾼 후 보내 보기.
      4)파일 문자셋을 utf-8로 해서 inconv 함수로 euc-kr로 바꾼 후 urlencode 함수로 다시 인코딩해서 보내 보기.
      아무래도 컴퓨터쪽 전공을 안 해 놓으니 문자셋 관련한 부분은 무슨 말인지 알아먹을 수가 없습니다. 물론 인코딩 종류 정도야 알고 있지만 바이트 차원에서 무슨 일이 벌어지는 것인지 구체적으로 모르겠다는 것이죠. 왜 우편번호 오픈 API가 자바의 EUC-KR encode는 알아먹는데 php의 euc-kr 인코딩은 못 알아먹는지 이런 게 당췌 이해가 안 간다는 말씀입니다.
      혹시 짚히는 부분 있으시면 알려 주시면 감사하겠습니다.

      • 에드몽단테스 2010.10.02 04:04 신고

        간만에 php를 해보느라 고생좀 했네요 ㅎㅎ
        API에 한글주소를 파라메터로 넘길 때 헤더에 한글이라는 부분을 표시해주어야 한다고 들은 적이 있는 것 같네요.
        처음엔 fopen() 함수를 사용해봤는데, 안돼더군요. 녹풍님의 말씀처럼 서버쪽에서 파라메터를 인식하지 못하는 것 같습니다.
        그래서 헤더에 직접 값을 넣을 수 있는 fsocket() 함수를 사용해 보았습니다.

        <?
        $address = "괴정동";
        $api = "api";
        $fp = fsockopen("biz.epost.go.kr", 80, $errno, $errstr, 30);
        if (!$fp) {
        echo "$errstr ($errno)<br />\n";
        } else {
        $out = "GET /KpostPortal/openapi?regkey=".$api."&target=post&query=".$address." HTTP/1.1\r\n";
        $out .= "Host: biz.epost.go.kr\r\n";
        $out .= "Accept-language: ko\r\n";
        $out .= "Connection: Close\r\n\r\n";
        fwrite($fp, $out);
        while (!feof($fp)) {
        echo fgets($fp, 128);
        }
        fclose($fp);
        }
        ?>

        헤더에 한글정보를 세팅해주니 잘 되네요.
        우편번호 서버가 euc-kr이라 위처럼 했지만, 만드시는 페이지가 UTF-8이라면 iconv() 함수를 이용하여 euc-kr로 변경후 사용하면 될 것 같습니다.

        수신데이터는 XML 이니 적당히 파싱하여 사용하면 되겠습니다.

    • 에드몽단테스 2010.10.02 04:09 신고

      예제코드에서 몇몇 코드의 마지막에 라인피드와 캐리지리턴문자가 표시가 되지 않았네요. 웹상에서는 표기가 어려운부분이니 이부분은 어떤내용인지 아시겠죠?^^

    • 서보민 2012.02.02 11:11

      너무 좋은 내용 잘 보고 갑니다 / 도움 많이 되었습니다 ^^

    • sunilsunil 2012.12.09 17:25

      프로젝트파일을 얻을순없을까요?ㅠ

    • suroMind 2012.12.12 13:26

      이런 포스팅이 있다니..ㅎㅎ
      덕분에 우편번호 검색 API 작업이 수월하게 되었습니다..

      정말 감사합니다^^

    • 아라리요 2013.07.11 18:14

      @RequestMapping("/searchZipCode.do")
      public String searchZip()
      {
      return "/WEB-INF/view/popup_zipcode.jsp";
      }

      @RequestMapping(value = "/searchZipCode.do", method=RequestMethod.POST)
      위와 동일한 내용
      }



      HTML에서 호출을 아래처럼 합니다.
      function search(){
      var query = document.getElementById("query").value;
      if(query == "" || query == null){
      document.getElementById('checkMsg').innerHTML = "동을 입력하세요.";

      } else{
      var params = "query=" +query;
      sendRequest("/searchZipCode.do", params, displayResult, 'POST');
      }
      }
      function displayResult(){
      if(httpRequest.readyState == 4){
      if(httpRequest.status == 200){
      var resultText = httpRequest.responseText;
      alert(resultText);
      if(resultText != null){
      } else{
      }
      } else{
      alert("에러 발생 : "+httpRequest.status);
      }
      }
      }

      function getXMLHttpRequest() {
      if (window.ActiveXObject) {
      try {
      return new ActiveXObject("Msxml2.XMLHTTP");
      } catch(e) {
      try {
      return new ActiveXObject("Microsoft.XMLHTTP");
      } catch(e1) { return null; }
      }
      } else if (window.XMLHttpRequest) {
      return new XMLHttpRequest();
      } else {
      return null;
      }
      }
      var httpRequest = null;

      function sendRequest(url, params, callback, method) {
      httpRequest = getXMLHttpRequest();
      var httpMethod = method ? method : 'GET';
      if (httpMethod != 'GET' && httpMethod != 'POST') {
      httpMethod = 'GET';
      }
      var httpParams = (params == null || params == '') ? null : params;
      var httpUrl = url;
      if (httpMethod == 'GET' && httpParams != null) {
      httpUrl = httpUrl + "?" + httpParams;
      }
      httpRequest.open(httpMethod, httpUrl, true);
      httpRequest.setRequestHeader(
      'Content-Type', 'application/x-www-form-urlencoded');
      httpRequest.onreadystatechange = callback;
      httpRequest.send(httpMethod == 'POST' ? httpParams : null);
      }

      <input type="text" id="query" name="query" >
      <input type="button" value="확인" onclick="search()">


      디버그 찍어봤습니다.
      확인 누르고나서 xmlData에 제대로 데이터 들어가고 addressInfo에 제대로 add 되고 있었습니다.
      그런데 리턴이 된건지 안된건지는 모르겠습니다.
      일단 httpRequest에서 status를 404로 받아오고 있습니다.

      ArrayList 형식은 ajax형태로 리턴을 해줄 수가 없어서 그런 것인가요?

      혹시 그게 불가능한거라면 제가 어떤 방법을 사용해야 컨트롤러딴의 arrayList를 리턴받아서 사용할 수가 있는지 궁금합니다.

    • 에드몽단테스 2013.07.18 12:50 신고

      ajax 호출시 보통 위처럼 하지 않습니다. 초기에는 위처럼 했지만, 지금은 대부분 jquery로 호출합니다.
      코드 양과 브라우저 호환성면에서 jquery가 훨씬 낫습니다.

      ajax는 페이지를 호출합니다. 페이지에 문자열을 넣었으면 이를 파싱해서 사용할 수 있겠지만, 문자열만 가능합니다.
      만약 ArrayList나, List등과 같이 자바 타입의 리턴값을 찾으신다면 DWR 기법을 찾아보시기 바랍니다.

Designed by Tistory.