공공데이터포털 XML을 읽어서 자바 오브젝트로 변환하는 방법

LeeKyoungChang·2022년 12월 18일
0
post-thumbnail

일주일동안 어떻게 하면 공공데이터포털에서 데이터를 가져올 수 있을까? 고민을 일주일 한 결과, okky 힌트를 보고 알게 되었다.

 

🧐 요약
(1) 공공데이터 포털에서 소스를 긁어온다.
(2) 조회하기 위해 JAXB를 사용하면 된다.
(3) 그리고 Controller에서 xml을 JAXBContext으로 받아와 처리한다.

 

📚 1. 공공데이터 포털에서 소스를 긁어오자!

나 같은 경우, 지역마다 아파트가 필요해서 국토교통부아파트매매실거래자료 을 이용했다.

📖 A. 국토교통부 아파트매매 실거래 사이트에서는?

✔️ 데이터 조회
스크린샷 2022-12-18 오후 9 45 21

  • 미리보기를 클릭해 샘플 데이터 조회가 가능하다.

조회 결과

스크린샷 2022-12-18 오후 9 46 28
  • xml 구조를 보면 : response, header, body, items, item 등을 볼 수 있다.

 

✔️ 데이터명 상세설명을 클릭해서 java 소스를 긁어오자

스크린샷 2022-12-18 오후 9 47 45
/* Java 1.8 샘플 코드 */  
  
  
import java.io.InputStreamReader;  
import java.net.HttpURLConnection;  
import java.net.URL;  
import java.net.URLEncoder;  
import java.io.BufferedReader;  
import java.io.IOException;  
  
public class ApiExplorer {  
    public static void main(String[] args) throws IOException {  
        StringBuilder urlBuilder = new StringBuilder("http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade"); /*URL*/  
        urlBuilder.append("?" + URLEncoder.encode("serviceKey","UTF-8") + "=서비스키"); /*Service Key*/  
        urlBuilder.append("&" + URLEncoder.encode("LAWD_CD","UTF-8") + "=" + URLEncoder.encode("11110", "UTF-8")); /*각 지역별 코드*/  
        urlBuilder.append("&" + URLEncoder.encode("DEAL_YMD","UTF-8") + "=" + URLEncoder.encode("201512", "UTF-8")); /*월 단위 신고자료*/  
        URL url = new URL(urlBuilder.toString());  
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
        conn.setRequestMethod("GET");  
        conn.setRequestProperty("Content-type", "application/json");  
        System.out.println("Response code: " + conn.getResponseCode());  
        BufferedReader rd;  
        if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {  
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));  
        } else {  
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));  
        }  
        StringBuilder sb = new StringBuilder();  
        String line;  
        while ((line = rd.readLine()) != null) {  
            sb.append(line);  
        }  
        rd.close();  
        conn.disconnect();  
        System.out.println(sb.toString());  
    }  
}
  • 여기서 sb에는 xml이 한줄로 입력되어 있다.

나는 여기서 어떻게 하면 xml을 json으로 바꿀 수 있을까? 라는 생각에 https://okky.kr/articles/1374024#note-1592484 에 질문을 드렸더니
xml -> dto -> json 순차적으로 적용보아라는 말을 읽고 그게 가능할까? 라는 생각에 구글링 해보니
JAXB를 사용하면 가능하다고 한다!

 

📝 JAXB을 사용하여 어떻게 XML 데이터를 자바로 변경할까?

  • JAXB api를 사용하여 XML 형식의 데이터를 자바 객체로 변환하는 방법이다! (언마샬링)
  • JAXB(Java Architecture for XML)는 자바 클래스를 XML로 표현하는 자바 API 이다.
  • 주 기능 : 자바 객체를 XML로 직렬화 하는 것과 XML에서 자바 객체로 역직렬화하는 것이다.
  • Spring Boot Starter Test는 jakarta.xml.bind를 포함하고 있기 때문에 따로 의존성을 추가할 필요 바로 사용할 수 있다.

 

📚 2. JAXB 적용

✔️ 현재 XML
스크린샷 2022-12-18 오후 9 46 28

 

✔️ XML에 대한 Response

  
import lombok.Data;  
import lombok.Getter;  
import lombok.Setter;  
  
import javax.xml.bind.annotation.XmlAccessType;  
import javax.xml.bind.annotation.XmlAccessorType;  
import javax.xml.bind.annotation.XmlElement;  
import javax.xml.bind.annotation.XmlRootElement;  
import java.util.List;  
  
@Getter  
@Setter  
@XmlAccessorType(XmlAccessType.FIELD)  
@XmlRootElement(name="response")  
public class Response {  
  
    @XmlElement(name = "header")  
    private Header header;  
  
    @XmlElement(name= "body")  
    private Body body;  
  
    @Getter  
    @Setter    @XmlRootElement(name = "header")  
    private static class Header{  
        private String resultCode;  
        private String resultMsg;  
    }  
    @Getter  
    @Setter    @XmlRootElement(name = "body")  
    public static class Body{  
        private Items items;  
        private String numOfRows;  
        private String pageNo;  
        private String totalCount;  
  
        @Getter  
        @Setter        @XmlRootElement(name = "items")  
        public static class Items{  
            private List<Item> item;  
  
            @Getter  
            @Setter            @XmlRootElement(name="item")  
            public static class Item{  
                private String 거래금액;  
                private String 건축년도;  
                private String;  
                private String 법점동;  
                private String 아파트;  
                private String;  
                private String;  
                private String 전용면적;  
                private String 지번;  
                private String 지역코드;  
                private String;  
            }        }    }  
}
  • @XmlAccessorType : XML 데이터를 어떤 방법으로 매핑할지를 선언해줄 수 있는 annotation
  • @XmlRootElement : Class에 사용하는 annotation으로 해당 클래스가 XML의 특정 노드의 루트라는 것을 뜻한다.
  • @XmlElement : 변수에 사용하는 annotation으로 해당 변수가 XML의 노드임을 뜻한다.

 

💡 참고
String에서 한글이름 변수 사용가능하다!

 

✔️ Controller에서 JAXB를 호출해주자


// ~는 위 소스를 참고하면 된다.
~
rd.close();  
conn.disconnect();  
  
// String 형식의 xmlString xml = sb.toString();  
  
// String 형식의 xml을 Java Object인 Response로 변환  
Map<String, Response> result = new HashMap<>();  
try{  
    JAXBContext jaxbContext = JAXBContext.newInstance(Response.class);  
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();  
    Response apiResponse = (Response)unmarshaller.unmarshal(new StringReader(xml));  
    result.put("response",apiResponse);  
    Response.Body.Items items = apiResponse.getBody().getItems();  
  
  
    log.info("item을 확인하겠습니다.");  
    for(Response.Body.Items.Item item : items.getItem()){  
        log.info("아파트 " + item.get아파트());  
    }  
    log.info("실행 완료!");  
  
}catch (JAXBException e){  
    e.printStackTrace();  
}  
  
return "/";
  • unmarshal : XML표현을 Source Schema 조건들에 따라 Binding Interfases & Classes의 Java Object로 비정렬화시키는것

JAXB 설명 잘되어 있는 곳 : https://madplay.github.io/post/jaxb-marshal-unmarshal

 

✔️ 실행 결과

스크린샷 2022-12-18 오후 9 31 49

 

📚 3. xml에 한글 태그 -> 영어 태그로 바꾸기

스크린샷 2022-12-18 오후 9 46 28

와 같은 곳을 보면 한글로 되어 있는 것을 볼 수 있다.

package com.toyproject.apartmentmeeting.dataportal;  
  
import jdk.jfr.Name;  
import lombok.Data;  
import lombok.Getter;  
import lombok.Setter;  
  
import javax.persistence.Column;  
import javax.xml.bind.annotation.*;  
import java.util.List;  
  
@Getter  
@Setter  
@XmlAccessorType(XmlAccessType.FIELD)  
@XmlRootElement(name="response")  
public class Response {  
  
    @XmlElement(name = "header")  
    private Header header;  
  
    @XmlElement(name= "body")  
    private Body body;  
  
    @Getter  
    @Setter    @XmlRootElement(name = "header")  
    private static class Header{  
        private String resultCode;  
        private String resultMsg;  
    }  
    @Getter  
    @Setter    @XmlRootElement(name = "body")  
    public static class Body{  
        private Items items;  
        private String numOfRows;  
        private String pageNo;  
        private String totalCount;  
  
        @Getter  
        @Setter        @XmlRootElement(name = "items")  
        public static class Items{  
            private List<Item> item;  
  
  
            @Getter @Setter  
            @XmlRootElement(name="item")  
            @XmlAccessorType(XmlAccessType.FIELD)  
            public static class Item{  
//                private String 거래금액;  
                @XmlElement(name="건축년도")  
                private String building_year; // build  
//                private String 년;  
//                private String 법점동;  
  
                @XmlElement(name="아파트")  
                private String apartment; // apartment  
//                private String 월;  
//                private String 일;  
//                private String 전용면적;  
                @XmlElement(name="지번")  
                private String land_number; // landNumber  
  
                @XmlElement(name="지역코드")  
                private String area_code; // areaCode  
//                private String 층;  
            }  
        }    }  
}
  • @XmlElement, @XmlAccessorType을 사용하면 해결된다.

 

 


참고자료 : https://wildeveloperetrain.tistory.com/62

profile
"야, (오류 만났어?) 너두 (해결) 할 수 있어"

0개의 댓글