티스토리 뷰
KH 정보교육원 [ Java ]
KH 129일차 - Spring ( Open API / Dom4j / jaxen ) (*****)
monimoni 2022. 8. 31. 15:07
[ 1. Open API ] (*****)
[ 1 - 1. 네이버에서 응답 받아와 보기 ]
더보기
[ + 코드 보기 ]
package org.zerock.myapp.javastd;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class HttpURLConnectionExample {
public static void main(String[] args) throws Exception {
log.trace("main({}) invoked.", Arrays.toString(args));
// ========================================
// 1. 지정된 url 주소로 URL 객체 생성하기
// ========================================
URL url = new URL("https://www.naver.com/");
log.info("\t + 1. url : {}", url);
// + 1. url : https://www.naver.com/
// + URL을 잘못입력할 경우 MalformedURLException 예외가 발생한다.
// ==========================================
// 2. URL 객체에서 URLConnection 객체를 획득
// ==========================================
URLConnection conn = url.openConnection();
log.info("\t + 2. conn type : {}", conn.getClass().getName());
// + 2. conn type : sun.net.www.protocol.https.HttpsURLConnectionImpl
// =================================================
// 3. URLConnection 객체를 자식타입으로 강제형변환
// =================================================
HttpURLConnection httpConn = (HttpURLConnection) conn; // + HTTP Client 역할을 한다.
// =======================================================================================================
// 4. HttpURLConnection 객체를 통해서, HTTP request(요청메세지)를 보내고 HTTP response(응답메세지)를 받자
// =======================================================================================================
// + 이때 요청과 응답은 InputStream과 OutputStream을 통해서 수행한다.
// =======================================================================================================
InputStream is = httpConn.getInputStream(); // + 바이트 기반의 입력스트림 획득
// httpConn.getOutputStream();
// + 나로부터 응답 메세지를 보내는 것이 아니라, url에서 받기만 할 예정이기에 InputStream만 필요
int b;
while ( ( b = is.read() ) != -1 ) { // + EOF : ( End Of File )
System.out.print( (char) b);
// + url에서 보내오는 것은 거대한 문자열이기에 char타입으로 변환하여 받아야 한다.
} // while
is.close(); // + 자원 해제
} // main
} // end class
[ 1 - 2. 공공 데이터 포털의 Open API 활용 1 ]
더보기
[ + 코드 보기 ]
package org.zerock.myapp.javastd;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Arrays;
import lombok.Cleanup;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class HttpURLConnectionExample2 {
public static void main(String[] args) throws Exception {
log.trace("main({}) invoked.", Arrays.toString(args));
// =======================================================================================================
// 1. 지정된 url 주소로 URL 객체 생성하기
// =======================================================================================================
// + 승인받은 공공데이터 포털의 endpoint로 URL을 생성하고, 전송파라미터도 쿼리 String 형태로 붙여준다.
// =======================================================================================================
// ===============================================
// 1 ) 방법 1
// ===============================================
String endPoint = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson";
String params = "?serviceKey=k%2FpKmqc79MTVkMiYnlv2rLFvpKZ12SLF5sbbTZhIZM135W7670MN9Oz89apgMp%2FGWnzhH1js2Yw%39D%3D"+
"&pageNo=1"+
"&numOfRows=10"+
"&startCreateDt=20220801"+
"&endCreateDt=20220830";
String apiUrl = endPoint + params;
// ===============================================
// 2 ) 방법 2
// ===============================================
StringBuffer sb = new StringBuffer();
sb.append("http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson");
sb.append("?serviceKey=k%2FpKmqc79MTVkMiYnlv2rLFvpKZ12SLF5sbbTZhIZM135W7670MN9Oz89apgMp%2FGWnzhH1js2Yw%39D%3D");
sb.append("&pageNo=1");
sb.append("&numOfRows=10");
sb.append("&startCreateDt=20220801");
sb.append("&endCreateDt=20220830");
// + 만약, 전송파라미터 값 중에 다국어 문자 등이 있을 경우에는 반드시! URL Encoding을 해서 넣어줘야 한다.
// + ex. sb.append(URLEncoder.encode("값", "utf8")); (****)
String apiUrl2 = sb.toString();
URL url = new URL(apiUrl2);
log.info("\t + 1. url : {}", url);
// ==========================================
// 2. URL 객체에서 URLConnection 객체를 획득
// ==========================================
URLConnection conn = url.openConnection();
// ==========================================
// + 추가적인 설정
// ==========================================
conn.setConnectTimeout(1000 * 1); // 연결시간 - 밀리세컨드 단위
conn.setReadTimeout(1000*2); // 읽어오는 시간 - 밀리세컨드 단위
conn.setDoInput(true); // InputStream을 사용할 것이다
conn.setDoOutput(false); // OutputStream을 사용하지 않을 것이다.
// =================================================
// 3. URLConnection 객체를 자식타입으로 강제형변환
// =================================================
@Cleanup("disconnect")
HttpURLConnection httpConn = (HttpURLConnection) conn; // + HTTP Client 역할을 한다.
// ==========================================
// + 추가적인 설정 (***)
// ==========================================
httpConn.setRequestMethod("GET"); // + GET 방식으로 요청 메세지를 보내겠다.
httpConn.setConnectTimeout(1000 * 1); // + 연결시간 - 밀리세컨드 단위
httpConn.setReadTimeout(1000*2); // + 읽어오는 시간 - 밀리세컨드 단위
httpConn.setDoInput(true); // + InputStream을 사용할 것이다
httpConn.setDoOutput(false); // + OutputStream을 사용하지 않을 것이다.
// =======================================================================================================
// 4. HttpURLConnection 객체를 통해서, HTTP request(요청메세지)를 보내고 HTTP response(응답메세지)를 받자
// =======================================================================================================
// + 이때 요청과 응답은 InputStream과 OutputStream을 통해서 수행한다.
// + 이 단계에서 자동으로 request
// =======================================================================================================
if ( httpConn.getResponseCode() == HttpURLConnection.HTTP_OK ) {
log.info("\t + >>>> httpConn.getResponseCode : {} <<<< ", httpConn.getResponseCode());
// ===========================================================================
// + HttpURLConnection과 InputStream을 차례대로 닫게 하기 위해서,
// + InputStream을 블록 안에 넣어, 블록의 끝에 도달하면 먼저 닫히게 하였다.
// ===========================================================================
@Cleanup
InputStream is = conn.getInputStream();
// + 바이트 기반의 입력스트림 획득
// + InputStream을 얻는 동시에 요청을 보내게 된다.
int b;
while ( ( b = is.read() ) != -1 ) { // + EOF : ( End Of File )
System.out.print( (char) b);
// + url에서 보내오는 것은 거대한 문자열이기에 char타입으로 변환하여 받아야 한다.
} // while
} // if : 상태코드가 OK일때만 읽어 들인다.
} // main
} // end class
[ 2. XML 문서 parsing하기 - Dom4j ] (***)
[ 2 - 1. pom.xml 파일에 디펜던시 추가 ]
더보기
[ + 코드 보기 ]
<!-- ================ XML Parsing ================= -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
[ 2 - 2. resources 폴더 밑에 xml 파일 넣기 ]
[ 2 - 3. Dom4j 활용하기 ]
더보기
[ + 코드 보기 ]
package org.zerock.myapp.dom4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@NoArgsConstructor
@Log4j2
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Dom4jTests {
// @Disabled
@Test
@Order(1)
@DisplayName("Step 1. readXML")
@Timeout(value = 3, unit = TimeUnit.SECONDS)
void readXML() throws DocumentException {
log.trace("readXML() invoked.");
// ========================================
// 1. XML SAX Parser 생성
// ========================================
SAXReader reader = new SAXReader();
log.info("\t + 1. SAXReader : {}", reader);
// ====================================================
// 2. XML 파일 읽어오기
// + XML SAX Parser을 통해 파싱 수행 -> DOM tree 생성
// ====================================================
reader.setEncoding("utf8");
// + 최근에는 기본으로 utf8로 지정되어있으나, 혹시 모르니 지정해줘야 한다.
Document doc = reader.read("src/main/resources/Covid19DailyState.xml");
// + 파일의 경로( = systemId )를 url형태로 작성해 준다.
log.info("\t + 2. Document : {}", doc);
// + 2. Document : org.dom4j.tree.DefaultDocument@efde75f [Document: name src/main/resources/Covid19DailyState.xml]
// + 실제 타입이 다른 것을 보아 Document는 인터페이스임을 알 수 있다.
// + 어느 경로의 파일을 읽고 있는지도 출력해 준다.
// ========================================
// 3. 문서 객체에 대한 정보 출력
// ========================================
log.info("\t + 3-1. docType : {}",doc.getDocType());
// + 3-1. docType : null
log.info("\t + 3-2. name : {}", doc.getName());
// + 3-2. name : src/main/resources/Covid19DailyState.xml
log.info("\t + 3-3. XMLEncoding : {}", doc.getXMLEncoding());
// + 3-3. XMLEncoding : UTF8
// ========================================
// 4. DOM 순회
// ========================================
Element root = doc.getRootElement();
log.info("\t + 4. root : {}", root);
// + DOM은 node의 계층 구조로 구성되어 있으며, Element는 node의 종류 중 하나이다.
// + Element는 HTML에서 태그로 적은 노드들을 의미한다.
// + Element 또한 실제타입을 찍어보니 다른 것을 보아 인터페이스임을 알 수 있다.
// + 4. root : org.dom4j.tree.DefaultElement@3b220bcb [Element: <response attributes: []/>]
log.info("\t + 4-1. root : {}", root.getName());
// + 엘리먼트(태그)의 이름을 알려준다.
// + 4-1. root : response
log.info("\t + 4-2. root Node Type : {}", root.getNodeTypeName());
// + 어떤 노드 타입인지 알아본다.
// + 4-2. root Node Type : Element
log.info("\t + 4-3. root text : {}", root.getText());
// ==============================================================
// 5. DOM의 순회 및 데이터 획득
// + 찾고자 하는 데이터가 들어가 있는 Element(태그)를 지정한다.
// + 단, 태그를 찾을 때에는 차근차근 겉에서 안으로 들어가야 한다.
// ==============================================================
Element body = root.element("body");
log.info("\t + 5. body : {}",body);
// + 먼저, 가장 밭에 있는 body 태그에 접근한다.
Element items = body.element("items");
log.info("\t + 5. items : {}", items);
// + body 태그 내에 있는 items 태그에 접근한다.
@Cleanup("clear")
List<Element> item = items.elements("item");
// + items 태그 밑의 item 엘리먼트(태그)를 리스트에 넣기
for ( Element e : item ) {
// + item 태그에서 필요한 데이터 추출
Element createDtElement = e.element("createDt");
Element deathCntElement = e.element("deathCnt");
Element decideCntElement = e.element("decideCnt");
Element seqElement = e.element("seq");
Element stateDtElement = e.element("stateDt");
Element stateTimeElement = e.element("stateTime");
Element updateDtElement = e.element("updateDt");
// + String 형태로 변환
String createDt = createDtElement.getStringValue();
String deathCnt = deathCntElement.getStringValue();
String decideCnt = decideCntElement.getStringValue();
String seq = seqElement.getStringValue();
String stateDt = stateDtElement.getStringValue();
String stateTime = stateTimeElement.getStringValue();
String updateDt = updateDtElement.getStringValue();
// + item에 attr 속성을 넣어서 출력할 수도 있다.
String attr = e.attributeValue("attr");
log.info("[{}]. createDt : {}, deathCnt : {}, decideCnt : {}, stateDt : {}, stateTime : {}, updateDt : {}, attr : {}",
seq, createDt, deathCnt, decideCnt, stateDt, stateTime, updateDt, attr );
} // for : 리스트에서 넣은 것을 출력
} // readXML
} // end class
[ 3. XML 문서 parsing하기 XPath engine ( jaxen ) 이용 버전 ] (*****)
[ 3 - 1. pom.xml 파일에 디펜던시 추가하기 ]
더보기
[ + 코드 보기 ] : jaxen의 이 버전의 경우 취약점이 있으니 조심
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
[ 3 - 2. Jaxen 활용하기 ]
더보기
[ + 코드 보기 ]
package org.zerock.myapp.dom4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import lombok.Cleanup;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
@NoArgsConstructor
@Log4j2
@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JaxenTests {
// @Disabled
@Test
@Order(1)
@DisplayName("Step 1. readXML")
@Timeout(value = 3, unit = TimeUnit.SECONDS)
void readXML() throws DocumentException {
log.trace("readXML() invoked.");
// ========================================
// 1. XML SAX Parser 생성
// ========================================
SAXReader reader = new SAXReader();
// ====================================================
// 2. XML 파일 읽어오기
// + SAX Parser를 통해 파싱 수행 -> DOM tree 생성
// ====================================================
reader.setEncoding("utf8");
// + 최근에는 기본으로 utf8로 지정되어있으나, 혹시 모르니 지정해줘야 한다.
Document doc = reader.read("src/main/resources/Covid19DailyState.xml");
// + 파일의 경로( = systemId )를 url형태로 작성해 준다.
// ===================================================
// 3. XPath로 우리가 얻고자 하는 노드들 한번에 선택
// ===================================================
String xpath = "/response/body/items/item";
@Cleanup("clear")
List <Node> list = doc.selectNodes(xpath);
log.info("\t + list size : {}", list.size() );
// ==============================================================
// 4. DOM의 순회 및 데이터 획득
// + 찾고자 하는 데이터가 들어가 있는 노드를 지정한다.
// ==============================================================
for ( Node node : list ) {
Element e = (Element) node;
// + Element는 Node의 자식 타입이기에 형변환이 가능하다.
// + item 태그에서 필요한 데이터 추출 + String 형태로 변환 ( 메소드 체이닝 )
String createDt = e.element("createDt").getStringValue();
String deathCnt = e.element("deathCnt").getStringValue();
String decideCnt = e.element("decideCnt").getStringValue();
String seq = e.element("seq").getStringValue();
String stateDt = e.element("stateDt").getStringValue();
String stateTime = e.element("stateTime").getStringValue();
String updateDt = e.element("updateDt").getStringValue();
// + item에 attr 속성을 넣어서 출력할 수도 있다.
String attr = e.attributeValue("attr");
log.info("[{}]. createDt : {}, deathCnt : {}, decideCnt : {}, stateDt : {}, stateTime : {}, updateDt : {}, attr : {}",
seq, createDt, deathCnt, decideCnt, stateDt, stateTime, updateDt, attr );
} // for : 리스트에서 넣은 것을 출력
} // readXML
} // end class
728x90
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 131일차 - Git / Git Hub (0) | 2022.09.02 |
---|---|
KH 130일차 - Spring ( Java <-> JSON Serialize / Deserialize ) (****) (0) | 2022.09.01 |
KH 128일차 - Spring ( 트랜잭션 / 패스워드 암호화 / open API ) (******) (0) | 2022.08.30 |
KH 127일차 - Spring( AOP 2 / 트랜잭션[미완성] ) (******) (0) | 2022.08.29 |
KH 126일차 - Spring ( AOP ) (***) (0) | 2022.08.26 |
댓글