본문 바로가기
프로그래밍/API

[JAVA] 기상청 날씨 API - 초단기 예보

by 밍구몬 2019. 8. 22.

기존 (신)동네예보정보조회서비스 중기예보정보조회서비스는 2020년 4월 28일 폐기.

기상청 API는 아래의 링크 확인

https://ming9mon.tistory.com/151

 

[JAVA]변경된 기상청 날씨 API (동네예보, 중기예보)

기존에 사용하던 (신)동네예보정보조회서비스와 중기예보정보조회서비스는 2020년 4월 28일 완전히 폐기된다고 합니다. 새로운 API는 https://www.data.go.kr/dataset/15000099/openapi.do 에서 동네예보 조회서비..

ming9mon.tistory.com

 

공공데이터포털의 날씨 API를 이용한다.

https://www.data.go.kr/search/index.do 사이트에서 "동네에보정보조회서비스"를 검색하면 오픈 API를 찾을 수 있다.

 

링크에 들어가 활용신청을 해주면 자동 승인이 된다. 

신청을 한 뒤 마이페이지에 가보면 승인된 API가 보일 것이다.

동네예보정보조회 서비스에 들어가 키를 발급받아 준다.

아래에 내려보면 동네예보조회에 실행이 있고, 미리보기로 테스트가 가능하다.

ServiceKey 항목에는 발급받은 키값을 넣어주고(사이트에서 테스트 할때는 default로 입력되어 있는 key로 테스트 가능) base_date에는 날짜를 적어주어야 하는데 오늘이나 내일 날짜밖에 안된다. base_time은 조회를 원하는 시간이다 02시부터 3시간 단위로 조회를 할 수 있다.

 

x좌표값과 y좌표값을 얻는 방법은 

https://ming9mon.tistory.com/manage/newpost/83?type=post&returnURL=https%3A%2F%2Fming9mon.tistory.com%2F83 

여기에 정리해 두었다.

 

초단기 예보는 30분 단위로 발표하는데 매시각 45분 이후 호출할 수 있다고 한다.

왜 30분 단위로 발표하는데 매시각 45분 이후 발표인지 ..

예를 들어 10시 10분이면 9시나 9시 30분으로 base_time을 설정해야 하고,

10시 45분 이라면 10시꺼를 호출하면 된다.

 

아래의 이미지는 초단기 예보가 주는 값의 설명이다.

초단기 예보는 시간당 10개의 데이터를 주며, 아래와 같이 시간마다 주는 데이터 양이 다르다..

최대 4개의 시간에 대한 값(40개)을 주기 때문에 이 예제에서는 numOfRows를 40으로 설정해 주었다.

예제 소스

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.text.SimpleDateFormat;
import java.util.Date;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;


public class Test {
	public static void main(String[] args) throws IOException, ParseException {
	
		
		
		//String date=request.getParameter("date");
		Date d = new Date();
		SimpleDateFormat f1 = new SimpleDateFormat("yyyyMMdd");
		SimpleDateFormat f2 = new SimpleDateFormat("HH");
		String date = f1.format(d);
		String time = Integer.parseInt(f2.format(d))-1+"00";
		
		if(Integer.parseInt(time) < 1000) time="0"+time;
		
		String apiUrl = "http://newsky2.kma.go.kr/service/SecndSrtpdFrcstInfoService2/ForecastTimeData";
		// 홈페이지에서 받은 키
		String serviceKey = "홈페이지에서 받은 키";
		String nx = "60";	//위도
		String ny = "127";	//경도
		String baseDate = date;	//조회하고싶은 날짜
		String baseTime = time;	//API 제공 시간
		String type = "json";	//타입 xml, json 등등 ..
		String numOfRows = "40";	//한 페이지 결과 수 

		StringBuilder urlBuilder = new StringBuilder(apiUrl);
		urlBuilder.append("?" + URLEncoder.encode("ServiceKey","UTF-8") + "="+serviceKey);
		urlBuilder.append("&" + URLEncoder.encode("nx","UTF-8") + "=" + URLEncoder.encode(nx, "UTF-8")); //경도
		urlBuilder.append("&" + URLEncoder.encode("ny","UTF-8") + "=" + URLEncoder.encode(ny, "UTF-8")); //위도
		urlBuilder.append("&" + URLEncoder.encode("base_date","UTF-8") + "=" + URLEncoder.encode(baseDate, "UTF-8"));  //조회하고싶은 날짜
		urlBuilder.append("&" + URLEncoder.encode("base_time","UTF-8") + "=" + URLEncoder.encode(baseTime, "UTF-8"));  //조회하고싶은 시간 AM 02시부터 3시간 단위 
		urlBuilder.append("&" + URLEncoder.encode("_type","UTF-8") + "=" + URLEncoder.encode(type, "UTF-8"));	 //타입 
		urlBuilder.append("&" + URLEncoder.encode("numOfRows","UTF-8") + "=" + URLEncoder.encode(numOfRows, "UTF-8"));	 //한 페이지 결과 수 
		
		
		//GET방식으로 전송해서 파라미터 받아오기
		URL url = new URL(urlBuilder.toString());
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.setRequestProperty("Content-type", "application/json");
		
		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();
		String data= sb.toString();
		
		// Json parser를 만들어 만들어진 문자열 데이터를 객체화 
		JSONParser parser = new JSONParser(); 
		JSONObject obj = (JSONObject) parser.parse(data); 
		// response 키를 가지고 데이터를 파싱 
		JSONObject parse_response = (JSONObject) obj.get("response"); 
		// response 로 부터 body 찾기
		JSONObject parse_body = (JSONObject) parse_response.get("body"); 
		// body 로 부터 items 찾기 
		JSONObject parse_items = (JSONObject) parse_body.get("items");

		// items로 부터 itemlist 를 받기 
		JSONArray parse_item = (JSONArray) parse_items.get("item");
			
			
			
		JSONObject weather = new JSONObject();
		Object fcstTime;
		Object category;
		Object value;
			
		/**
		 * parse_item.size()/10 : 몇 개의 시간 데이터를 받아 왔는지
		 * 받아온 데이터의 갯수 / 시간당 데이터 갯수 = 
		 */
		int dataSize = parse_item.size()/10;
		
		for(int i=0;i<dataSize;i++) {
			for(int k=0;k<10;k++) {
				weather = (JSONObject) parse_item.get((i*dataSize)+k);
				fcstTime = weather.get("fcstTime");
				category = weather.get("category");
				value = weather.get("fcstValue");
				System.out.println(fcstTime+" : " +category+"  "+value);
			}
		}
		
	}
}

이 예제에서 홈페이지에서 받은 서비스 키만 입력해주면 바로 사용할 수 있게 28번라인까지는 시간 계산을 대충 해두었다.

69번 라인까지는 JSON 데이터를 가져오는 과정이고, 82번 라인까지는 받아온 JSON data를 파싱하는 부분이다.

JSON데이터가 어떻게 넘어왔는지 궁금하다면 69번라인의 data를 출력해 보면 된다.

 

초단기 예보는 동네예보와 다르게,

n시에 대한 category1번 값 n+1시에 대한 category1번 값

n시에 대한 category2번 값 n+1시에 대한 category2번 값 

이런식으로 데이터를 준다 ..

(동네예보는 시간당 category와 value값)

 

이 예제에서는 시간당 category와 value값으로 출력하도록 하였다.

(이렇게 시간당 category와 value값으로 해야 동네예보와 합쳐서 쓰기 편하기 때문...)