package com.example.playground.Controller;
import com.example.playground.Model.vo.Weather_vo;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Controller
@RequestMapping("/weather")
public class WeatherController {
WeatherController(){
}
@GetMapping("/getweather")
public String weather(Model model) throws IOException {
LocalDateTime t = LocalDateTime.now().minusMinutes(30); // 현재 시각 30분전
String apiurl = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst";
String serviceKey = "6S4u3U%2FUibanctkZBHz%2BeDGDzroxvL1RTCNvDovGn7J7JZSG4LoJCWXiTJl4x1mkElXI%2B1OQZ%2FS%2BKb6B5wldaQ%3D%3D";
String pageNo = "1";
String numOfRows = "1000";
String dataType = "JSON";
String base_date = t.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String base_time = t.format(DateTimeFormatter.ofPattern("HHmm"));
String nx = "99";
String ny = "75";
String basehour = base_time.substring(0,2);System.out.println("+++++basehour: "+ basehour);
StringBuilder urlBuilder = new StringBuilder(apiurl); /*단기예보조회 URL*/
urlBuilder.append("?" + URLEncoder.encode("ServiceKey","UTF-8") + "="+serviceKey); /*Service Key*/
urlBuilder.append("&" + URLEncoder.encode("pageNo","UTF-8") + "=" + URLEncoder.encode(pageNo, "UTF-8")); /*페이지번호*/
urlBuilder.append("&" + URLEncoder.encode("numOfRows","UTF-8") + "=" + URLEncoder.encode(numOfRows, "UTF-8")); /*한 페이지 결과 수*/
urlBuilder.append("&" + URLEncoder.encode("dataType","UTF-8") + "=" + URLEncoder.encode(dataType, "UTF-8")); /*요청자료형식(XML/JSON) Default: XML*/
urlBuilder.append("&" + URLEncoder.encode("base_date","UTF-8") + "=" + URLEncoder.encode(base_date, "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("base_time","UTF-8") + "=" + URLEncoder.encode(base_time, "UTF-8")); /*02시 발표(정시단위) */
urlBuilder.append("&" + URLEncoder.encode("nx","UTF-8") + "=" + URLEncoder.encode(nx, "UTF-8")); /*예보지점의 X 좌표값*/
urlBuilder.append("&" + URLEncoder.encode("ny","UTF-8") + "=" + URLEncoder.encode(ny, "UTF-8")); /*예보지점의 Y 좌표값*/
URL url = new URL(urlBuilder.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
conn.setRequestProperty("Accept", "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);
}
String temp = sb.toString();
JSONParser jp = new JSONParser();
JSONObject jo = null;
try{
jo = (JSONObject) jp.parse(temp);
}catch(ParseException e){
e.printStackTrace();
}
System.out.println(jo);
JSONObject response = (JSONObject) jo.get("response");
JSONObject body = (JSONObject)response.get("body");
JSONObject items = (JSONObject)body.get("items");
JSONArray item = (JSONArray)items.get("item");
Weather_vo PTY_vo = new Weather_vo();
Weather_vo T1H_vo = new Weather_vo();
Weather_vo SKY_vo = new Weather_vo();
Weather_vo REH_vo = new Weather_vo();
for(int i=0;i<item.size();i=i+6)
{
JSONObject temp2 = (JSONObject) item.get(i);
if( temp2.get("category").equals("PTY") )
{
PTY_vo.setCategory("PTY");
PTY_vo.setObsrValue(temp2.get("fcstValue")+"");
}
if( temp2.get("category").equals("T1H"))
{
T1H_vo.setCategory("T1H");
T1H_vo.setObsrValue(temp2.get("fcstValue")+"");
}
if( temp2.get("category").equals("SKY"))
{
SKY_vo.setCategory("SKY");
SKY_vo.setObsrValue(temp2.get("fcstValue")+"");
}
if( temp2.get("category").equals("REH") )
{
REH_vo.setCategory("REH");
REH_vo.setObsrValue(temp2.get("fcstValue")+"");
}
}
model.addAttribute("PTY",PTY_vo);
model.addAttribute("T1H",T1H_vo);
model.addAttribute("SKY",SKY_vo);
model.addAttribute("REH",REH_vo);
rd.close();
conn.disconnect();
String result= sb.toString();
model.addAttribute("weather_dataset", result);
return "weather/weather";
}
}
참고로 위에 URL 포멧 만들고 Connection 만드는건 API 설명페이지 밑에 샘플코드 보면 나와있다.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15084084
Json 형태로 넘어온 데이터를 살펴보자.
response key 안에 body key 안에 items key 안에 item key 안에 실제 데이터가 있는 모습이다. 따라서 아래와같이 실질적인 데이터를 추출해 주자.
근데 보면 강수상태를 나타내는 PTY데이터를 보면 6개가 있는게 보인다. 이는 현재 시간으로부터 이후 6시까지의 데이터를 나타낸 것이여서 그렇다. 우리는 현재의 시간이 필요함으로 각 첫번째 데이터를 취해야한다.
따라서 6개씩 건너뛰면서 데이터를 취하자.
난 강수상태(PTY), 온도(T1H), 하늘상태(SKY), 습도(REH)가 필요하다.
기상청에서 제공하는 데이터 형식
https://www.weather.go.kr/w/resources/pdf/dongnaeforecast_rss.pdf
모델에 넣어서 뷰쪽으로 전달해주자
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="cpath" value="${pageContext.request.contextPath}"/>
<c:set var="temper" value="${requestScope.T1H.obsrValue}" />
<!doctype html>
<html>
<head>
<!--글꼴 설정입니다-->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital
,wght@0,400;0,700;1,400&family=Moirai+One&display=swap" rel="stylesheet">
<link rel = "stylesheet"
href="${cpath}/resources/css/hello.css"
type="text/css" />
<title>Document</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<link rel = "stylesheet"
href="${cpath}/resources/css/weather.css"
type="text/css" />
</head>
<body>
<h1>weather folder</h1>
<div class="weather-info">
<div class="time-table">
<span class="month">00</span>.
<span class="date">00</span>.
<span class="year">0000</span>.
<span class="todayTimes">00000</span>
</div>
<br>
<hr>
<br>
<h1>오늘의 날씨</h1>
<br>
<div class="weather-status">
<c:choose>
<c:when test="${SKY.obsrValue eq 1}">
<img src="${cpath}/resources/WeatherIcon/img.png" alt="맑은 날씨 이미지">
</c:when>
<c:when test="${SKY.obsrValue eq 3}">
<img src="${cpath}/resources/WeatherIcon/img_1.png" alt="조금 흐린 날씨 이미지">
</c:when>
<c:when test="${SKY.obsrValue eq 6}">
<img src="${cpath}/resources/WeahtherIcon/img2.png" alt="많이 흐린 날씨 이미지">
</c:when>
<c:when test="${PTY.obsrValue eq 1}">
<img src="${cpath}/resources/WeatherIcon/img_3.png" alt="비오는 날씨 이미지">
</c:when>
<c:otherwise>
<p>날씨 정보를 가져오지 못했습니다.</p>
</c:otherwise>
</c:choose>
<div class="information">
온도 : ${T1H.obsrValue}°C
<hr>
습도 : ${REH.obsrValue}
</div>
</div>
</div>
<script>
setInterval(myTimer, 1000); // 1초마다 호출되게 한다.
function myTimer() {
let today = new Date(); //데이트객체생성
let y = today.getFullYear();
let m = today.getMonth() + 1; //0부터 시작하므로 +1을 더해야 현재 월 이 된다.
let d = today.getDate(); //일 값을 받아낸다.
let day = today.getDay(); // 요일의 값을 받아낸다.
let weekday = new Array(7); // 어레이의 각 요일을 할당하고
weekday[0] = "Sunday";
weekday[1] = "Monday";
weekday[2] = "Tuesday";
weekday[3] = "Wednesday";
weekday[4] = "Thursday";
weekday[5] = "Friday";
weekday[6] = "Saturday";
let t_time = today.toLocaleTimeString();
$(".time-table .year").text(y);
$(".time-table .month").text(m);
$(".time-table .date").text(d);
$(".day").text(weekday[today.getDay()]); //어레이의 요일의 값을 할당해 요일 출력
$(".time-table .todayTimes").text(t_time);
}
</script>
</body>
</html>
참조한 블로그들
https://kbcoding.tistory.com/53
https://velog.io/@jeongm2n/Spring-MVC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%EC%83%81-%EC%98%88%EB%B3%B4-API-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-JSON-%EA%B0%9D%EC%B2%B4%EC%97%90%EC%84%9C-%EC%9B%90%ED%95%98%EB%8A%94-%EA%B0%92-%EC%B6%94%EC%B6%9C%ED%95%98%EA%B8%B0