일주일동안 어떻게 하면 공공데이터포털에서 데이터를 가져올 수 있을까? 고민을 일주일 한 결과, okky 힌트를 보고 알게 되었다.
🧐 요약
(1) 공공데이터 포털에서 소스를 긁어온다.
(2) 조회하기 위해 JAXB를 사용하면 된다.
(3) 그리고 Controller에서 xml을 JAXBContext으로 받아와 처리한다.
나 같은 경우, 지역마다 아파트가 필요해서 국토교통부아파트매매실거래자료 을 이용했다.
✔️ 데이터 조회
조회 결과
✔️ 데이터명 상세설명을 클릭해서 java 소스를 긁어오자
/* 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());
}
}
나는 여기서 어떻게 하면 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를 포함하고 있기 때문에 따로 의존성을 추가할 필요 바로 사용할 수 있다.
✔️ 현재 XML
✔️ 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 "/";
JAXB 설명 잘되어 있는 곳 : https://madplay.github.io/post/jaxb-marshal-unmarshal
✔️ 실행 결과
와 같은 곳을 보면 한글로 되어 있는 것을 볼 수 있다.
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
을 사용하면 해결된다.