본문 바로가기
개발 공부 Today I Learned

[국비 76일차 TIL] 공공데이터포털 API, jsoup, JPA

by 개발자신입 2024. 3. 13.
반응형

APIController

package com.example.web.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class APIController {
	
	// 에어코리아 접속해서 데이터 불러오기.
	@GetMapping("/airKorea")
	public String airKorea(Model model) throws IOException {
		StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMinuDustFrcstDspth");
		urlBuilder.append("?serviceKey=wqF25IkSZaAdvYJHuzn8tR5NGdWuqjgFMBASZn3LEimWCQmEjFVNj1cLxPdEg4j8wowdCf%2BcGRuwy1Ci7kth4g%3D%3D");
		urlBuilder.append("&returnType=json"); // xml, json 다르게 출력됨.
		urlBuilder.append("&numOfRow=100");
		urlBuilder.append("&pageNo=1");
		urlBuilder.append("&searchDate=2024-03-11");
		urlBuilder.append("&informCode=PM10");
		
		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()); // Response code : 200
		
		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말고 StringBuilder
		String line;
		while((line = rd.readLine()) != null) {
			sb.append(line);
		}
		rd.close();
		conn.disconnect();
		
		System.out.println(sb.toString());
		
		return "airKorea";
	}
}

build.gradle

implementation 'com.googlecode.json-simple:json-simple:1.1.1'

 

BufferedReader부터 disconnect()까지 주석 처리

//		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말고 StringBuilder
//		String line;
//		while((line = rd.readLine()) != null) {
//			sb.append(line);
//		}
//		rd.close();
//		conn.disconnect();
//		
//		System.out.println(sb.toString());



		// json -> 자바 데이터 형식으로 변환
		JSONParser parser = new JSONParser(); // org.json.simple
		JSONObject jsonObject = (JSONObject) parser.parse(new InputStreamReader(url.openStream())); 
								// -> cast 추가 및 throw

		Map<String, Object> map = (Map<String, Object>) jsonObject.get("response");
		System.out.println("response :: " + map);

		map = (Map<String, Object>) map.get("body");
		System.out.println("body :::::: " + map);
		
		JSONArray jsonArray = (JSONArray) map.get("items");
		System.out.println("items ::::: " + jsonArray);
		
		model.addAttribute("data", jsonArray);
		
		return "airKorea";
	}
}

airKorea.html

<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AIR KOREA</title>
<th:block th:insert="~{menu.html :: head}" />
</head>
<body>
	<th:block th:insert="~{menu.html :: menu}" />

	<aside class="text-center">
		<div class="container px-5">
			<h2>공공데이터포털에서 데이터 가져오기!</h2>
			<div class="text-center">
				<table>
					<tr>
						<th>dataTime</th>
						<th>informCause</th>
						<th>informData</th>
						<th>informGrade</th>
						<th>informCode</th>
						<th>informOverall</th>
						<th>imageUrl1</th>
						<th>imageUrl2</th>
						<th>imageUrl3</th>
						<th>imageUrl4</th>
						<th>imageUrl5</th>
						<th>imageUrl6</th>
					</tr>
					<tr th:each="row : ${data}">
						<td th:text="${row.dataTime}"></td>
						<td th:text="${row.informCause}"></td>
						<td th:text="${row.informData}"></td>
						<td th:text="${row.informGrade}"></td>
						<td th:text="${row.informCode}"></td>
						<td th:text="${row.informOverall}"></td>
						<td><img th:src="${row.imageUrl1}" alt=""></td>
						<td><img th:src="${row.imageUrl2}" alt=""></td>
						<td><img th:src="${row.imageUrl3}" alt=""></td>
						<td><img th:src="${row.imageUrl4}" alt=""></td>
						<td><img th:src="${row.imageUrl5}" alt=""></td>
						<td><img th:src="${row.imageUrl6}" alt=""></td>
					</tr>
				</table>
			</div>
		</div>
	</aside>

 

/airKorea 출력화면

APIController.java

	// XML
	@GetMapping("/airKoreaXML")
	public String airKoreaXML(Model model) throws IOException, ParserConfigurationException, SAXException {
		StringBuilder urlBuilder = new StringBuilder(
				"http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMinuDustFrcstDspth");
		urlBuilder.append(
				"?serviceKey=wqF25IkSZaAdvYJHuzn8tR5NGdWuqjgFMBASZn3LEimWCQmEjFVNj1cLxPdEg4j8wowdCf%2BcGRuwy1Ci7kth4g%3D%3D");
		urlBuilder.append("&returnType=xml");
		urlBuilder.append("&numOfRow=100");
		urlBuilder.append("&pageNo=1");
		urlBuilder.append("&searchDate=2024-03-11");
		urlBuilder.append("&informCode=PM10");

		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()); // Response code : 200

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 먼저 공장을 만들어라.
		DocumentBuilder documentBuilder = factory.newDocumentBuilder();
		Document document = documentBuilder.parse(conn.getInputStream()); // 파싱 (Document = org.w3c.dom)
		document.getDocumentElement().normalize(); // 파싱 결과

		System.out.println("response : " + document.getDocumentElement().getNodeName()); // node nodeName == DOM

		NodeList list = (NodeList) document.getDocumentElement().getChildNodes().item(3);// body
		System.out.println(list.getLength());
		System.out.println(list.item(1).getNodeName());// items

		NodeList list2 = list.item(1).getChildNodes();// items
		// System.out.println("items :: " + list2.getLength());
		// System.out.println("items :: " + list2.item(0).getNodeName());

		// List
		List<Map<String, Object>> listMap = new ArrayList<>(); // 20개를 list에 담아보자
		for (int i = 1; i < list2.getLength(); i++) {
			NodeList list3 = list2.item(i).getChildNodes(); // item == 13개

			// Map
			Map<String, Object> ele = new HashMap<>();
			for (int j = 1; j < list3.getLength(); j++) {
				Node node = list3.item(j);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
//					System.out.println(j + " : " + list3.item(j).getNodeName() + " : " + list3.item(j).getTextContent());
//					System.out.println("");
					
					ele.put(list3.item(j).getNodeName(), list3.item(j).getTextContent());
				}
			}
			listMap.add(ele);
		}
		model.addAttribute("data", listMap);
		
		return "airKorea";
	}
}

airKoreaXML.html

<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>AIR KOREA</title>
<th:block th:insert="~{menu.html :: head}" />
</head>
<body>
	<th:block th:insert="~{menu.html :: menu}" />

	<aside class="text-center">
		<div class="container px-5">
			<h2>공공데이터포털에서 데이터 가져오기!</h2>
			<div class="text-center">
				<table>
					<tr>
						<th>dataTime</th>
						<th>informCause</th>
						<th>informData</th>
						<th>informGrade</th>
						<th>informCode</th>
						<th>informOverall</th>
						<th>imageUrl1</th>
						<th>imageUrl2</th>
						<th>imageUrl3</th>
						<th>imageUrl4</th>
						<th>imageUrl5</th>
						<th>imageUrl6</th>
					</tr>
					<tr th:each="row : ${data}"> 
 						<td th:text="${row.dataTime}"></td>
 						<td th:text="${row.informCause}"></td>
						<td th:text="${row.informData}"></td>
						<td th:text="${row.informGrade}"></td>
						<td th:text="${row.informCode}"></td>
						<td th:text="${row.informOverall}"></td>
						<td><img th:src="${row.imageUrl1}" alt=""></td>
						<td><img th:src="${row.imageUrl2}" alt=""></td>
						<td><img th:src="${row.imageUrl3}" alt=""></td>
						<td><img th:src="${row.imageUrl4}" alt=""></td>
						<td><img th:src="${row.imageUrl5}" alt=""></td>
						<td><img th:src="${row.imageUrl6}" alt=""></td>
					</tr>
				</table>
			</div>
		</div>
	</aside>

	<!-- footer -->
	<th:block th:insert="~{menu.html :: footer}" />

	<!-- Add Bootstrap JS and Popper.js scripts (required for Bootstrap functionality) -->
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

	<!-- Feedback Modal-->
	<!-- Bootstrap core JS-->
	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
	<!-- Core theme JS-->
	<script src="js/scripts.js"></script>
	<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *-->
	<!-- * *                               SB Forms JS                               * *-->
	<!-- * * Activate your form at https://startbootstrap.com/solution/contact-forms * *-->
	<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *-->
	<script src="https://cdn.startbootstrap.com/sb-forms-latest.js"></script>
</body>
</html>

/airKoreaXML 출력화면


jsoup

build.gradle

	implementation 'org.jsoup:jsoup:1.17.2'

APIController

System.out.println(doc); 출력되는지 확인

 

html.html 파일 생성

   
   @GetMapping("/html")
   public String html() throws IOException {
      String html="http://www.naver.com";
      org.jsoup.nodes.Document doc = Jsoup.connect("http://www.naver.com").get();
      System.out.println(doc);
      return "html";
   }

 

	@GetMapping("/htmlhtml")
	   public String html() throws IOException {
	      
	      org.jsoup.nodes.Document doc = Jsoup.connect("https://www.clien.net/service/").get();
	      
	      Elements element = doc.select("a.menu-list.somoim");
	      
	      System.out.println(element.size()); //몇 개?
	      
	      for (Element ele : element) {
	         System.out.println(ele.text());
	      }
	      
	      //System.out.println(doc);
	      return "htmlhtml";
	   }

JPA

  • Spring Boot DevTools
  • Lombok
  • Spring Data JPA
  • MariaDB Driver
  • Thymeleaf
  • Spring Web

 

application.properties

// DB
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://guro.-----:3308/---
spring.datasource.username=-------
spring.datasource.password=------

# jpa 방언 설정
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDB106Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true

#-------------------------   ddl-auto -------------------------#
# create	  : 실행할 때마다 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
# create-drop : create와 같으나 애플리케이션 종료 시점에 테이블 삭제
# update 	  : 엔티티 매핑 정보를 비교하여 변경된 내용만 반영
# validate    : 엔티티와 테이블이 정상적으로 매핑되었는지만 확인
# none 		  : 사용하지 않음
#--------------------------------------------------------------#

// port
server.port=80

BoardController.java

package com.example.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class BoardController {

	@Autowired
	private JPABoardService jpaBoardService;

	@GetMapping("/")
	public String index() {
		return "redirect:/board";
	}
	
	@GetMapping("/board")
	public String board() {
		return "board";
	}
}

JPABoardService.java

package com.example.web.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.web.repository.JPABoardRepository;

@Service
public class JPABoardService {
	
	@Autowired
	private JPABoardRepository jpaBoardRepository;

}

JPABoardRepository.java (인터페이스)

package com.example.web.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.web.entity.JPABoard;

public interface JPABoardRepository extends JpaRepository<JPABoard, Integer>{

}

JPABoard.java (엔티티)

package com.example.web.entity;

import java.time.LocalDateTime;

import org.hibernate.annotations.ColumnDefault;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

//------------------- JPA 설정 -------------------// 

@Getter
@Setter
@Entity // DTO랑 비슷. 중요함. 
public class JPABoard {

	@Id // P키 : primary key(기본 키)
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int jbno; // jpa board no
	
	@Column(columnDefinition = "TEXT")
	private String jbtitle;
	
	@Column(columnDefinition = "LONGTEXT")
	private String jbcontent;
	
	@ColumnDefault("CURRENT_TIMESTAMP")
	private LocalDateTime jbdate = LocalDateTime.now();
	
	@ColumnDefault("1")
	private int jbread;
	
	@ColumnDefault("0")
	private int jblike;
	
}
반응형

댓글