Team Project/제주도 여행 프로젝트

기상청 날씨 api를 이용해 제주도의 실시간 날씨정보 띄워주기

ChoiDooSic 2021. 10. 28. 14:00

경로를 짤수있는 페이지를 만드는데 제주도의 날씨를 알수있으면 참 좋겠다 싶어서

기상청 날씨api를 이용하여 실시간 날씨정보를 받아왔다.

현재는 1일 분량의 정보를 가져오기만 하였는데 일주일치를 가져와서 띄워주는것은 조금더 생각해봐야겠다.

 

현재 제주도의 하늘상태에따라 이모티콘이 바뀌고 현재온도와 강수량을 띄워준다.

HTML의 코드
자바스크립트의 코드

weather-con : 이모티콘의 값, temp : 현재온도,  pty : 강수량의 값을

innerHTML을 통해서 넣어준다.

 

처음 코드를 구성할때에는 ajax 방식을 통해서 데이터를 주고받는것이 아닌

Controller에서 jsp페이지를 호출할때에 기상청 데이터의 값을 모두 들고넘어가는 방식을

사용하였었다. 하지만 이 방식에는 크나큰 문제가 있었다...

Controller에서 바로 데이터를 가져오는 경우에 Socket Timeout Exception이 발생하면

페이지를 로딩하지 못한다는 문제가 생겼었다.

Socket Timeout Exception에 대한 포스팅 :  https://choidoosic.tistory.com/142

 

제주도 여행 프로젝트 5일차(기상 api 사용시 주의할점)

지난 4일차에는 기상 api를 이용하여 날씨의 정보를 가져오는 작업을 하였는데 5일차에는 오류를 만나게되어 그에 대하여 공부하고 수정하는 시간을 가졌다. #주의할점 1(Socket Timeout Exception) 내가

choidoosic.tistory.com

그래서 이 문제를 해결하기 위해서 ajax를 이용하여 비동기 방식으로 데이터를 처리하기로 하였다.

 

#초기의 방법(Socket Timeout Exception발생을 가정한 과정) (@Controller + 기상청API 데이터 값) → Socket Timeout Exception → View를 만들지 못함.

 

#해결 방법(Socket Timeout Exception발생을 가정한 과정) @Controller → View → (@RestController + 기상청API 데이터값) → Socket Timeout Exception → View는 앞서 로딩이되어있고 날씨의 정보만 들어가지 못함.

 

다만 아직 문제가 되는점이 있다면 Socket Timeout Exception이 발생한 경우에 페이지는 띄웠으나 날씨의 정보가 들어가지 못한다는 문제가 있는데 이 부분에 대해서는 데이터베이스를 이용하여 문제를 해결하는 방법을 생각하고있다.

 

앞서 날씨 api를 사용하기전에 알아야할 부분이 있다. 바로 새벽 2시 이전에는 현재 요일의 정보를 가져올수

없기때문에 예를들어 2021년 10월 21일 새벽 1시에 21일자의 기상 데이터를 원한다면

데이터를 가져올수가 없어 오류가 난다는 부분이다. 그래서 이 문제를 해결하기위해서

데이터를 가져올때의 시간값을 정해주기위한 메서드를 만들었다.

 

새벽 2시 이전이라면 약 3시간전인 전날 23시의 데이터값을 가져오게 만드는 방법이다

LocalDate와 LocalTime을 이용하여 코드를 구성하였으며 시간값에 분은 필요없기에

DateTimeFormatter를 사용할때에 HH00으로 형식을 맞추었다(예 : 12시 21분일때에 -> 1200)

 

before은 현재의 시간값이고 after은 새벽 2시10분의 시간값이다. 문자열로 비교한다면 0200이겠지만

int로 형변환이되면서 0이 사라지고 200이 되기때문에 after은 210으로 값을 준것이다.

정각인 새벽2시인 0200이 아닌 210으로 설정해둔 이유는 API제공 시간이 02 : 10분으로 각 베이스타임에

+10분이기때문이다. 

 

- Base_time : 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 (18)

- API 제공 시간(~이후) : 02:10, 05:10, 08:10, 11:10, 14:10, 17:10, 20:10, 23:10

 

키값을 넣어주면 그에 맞는 벨류 즉, 시간값이 나올수있게 하였다.

이 방법이 좋은 방법인지는 모르겠으나 데이터의 양도 적고하니 아래의 이미지와같이 꺼내쓸때에

직관적이게 사용할수 있게 HashMap을 이용하여 구성해보았다.

 

[getWeather()] 메서드는 날씨의 정보를 JSP로 전달하여주는 역할을하는 메서드이다.

 

1. weather_dto 필요한 날씨 정보를 받아 리턴해줄 객체

2. sky, pty 하늘상태 temp온도 , pop 강수량

3. skyState에 이모티콘 값을 실어준다

4. GET방식으로 api서버에 원하는 정보를 설정하여 받는다.
좌표는 격자좌표를 사용하여 격자좌표는 기상청 api를 받을때의 엑셀문서에 포함되어있다.
요청자료 형식은 json과 xml만 가능하다.

 

isPost는 POST방식으로 데이터를 받았을때를 대비한것인데 GET방식으로만 받을것임으로 

사실상 없어도 된다.

 

5. getStringFromURL() 메서드는 url에 원하는 값들을 실어 기상청에 데이터를 요청하여

받아오는 역할을하는데 받아온 데이터들을 String 타입의 resultMap변수에 담아준다.

(getStringFromURL() 메서드로 잠시 넘어가서 살펴보자)

[getStringFromURL()] 메서드에 매개변수인 url로 데이터 요청을 보낼 url을 실어넣어주고

get방식을 이용하기때문에 주소에 모든 값들을 실어넣어주었다.

(여기도 마찬가지로 POST방식을 대비하기는 하였으나 GET방식을 이용하기 때문에 굳이 필요없다

코드 정리할때에 지워야겠다.)

StringBuffer 의 객체인 result는 요청하여 받아온 데이터들을 넣어줄 객체이다.

 

HttpURLConnection의 객체인 conn에 필요한 값들을 초기화하여준다

1.conn = (HttpURLConnection) apiURL.openConnection(); // 서버와 요청된 url로 연결

2.conn.setConnectTimeout(9000); // 서버연결에 지연발생
3.conn.setReadTimeout(9000); //서버에는 연결 되었으나 데이터를 받는데 지연발생

4.conn.setDoOutput(true); // boolean 타입의 dooutput 파라미터를 받아 doOutput 변수에 저장하는데
5.doOutput 변수가 true이면 OutputStream으로 데이터를 전송한다는 뜻이고, false이면 하지 않는다는 뜻인데, 
기본으로 false로 초기화되어있기 때문에 POST로 데이터를 전송하려면 꼭 옵션을 설정해줘야 한다.
6.conn.setUseCaches(false);// 캐시에 저장된 결과가 아닌 동적으로 그 순간에 생성된 결과를 읽도록,
//파라미터를 전송하는 경우 대부분 웹 페이지의 결과가 그 순간 순간 파라미터의 값에 따라 달라지기 때문.

 

여기서 중요한점은 setConnectTimeout() ,setReadTimeout() 은 꼭 설정해주어야 한다는것이다

물론 URL도... ㅎㅎ 위의 두 메서드를 꼭 설정해주어야 하는 이유는 서버에 데이터를 요청후

데이터를 받지못할경우 무한정 대기상태에 들어가 무슨 오류가 생겼는지 알지못하기 때문이다

그래서 두 메서드를 설정하여 일정시간이 지나면 서버와의 접속 연결을 종료하는것이다.

그리고 종료시에 뜨는 에러메세지가 Socket Timeout Exception 이다

setDoOutput() 은 포스트방식으로 받을것이 아니기때문에 꼭 설정해줄 필요가 없다.

setUseCaches()는 아직 공부가 부족하여 무슨말인지 감은오나 처리속도에 어떠한 큰 영향을 미치는지는 모르겠다.

 

이후 conn.conect() 메서드를 이용하여 서버와의 연결을 만들어준다.

 

이후 서버에서 받아온 데이터값을 BufferedReader의 객체에 담아주고

while문을 실행하여 개행 단위로 String result에 담아준다.4

안에는 여러 날씨 정보들이 담겨있다.

 

다시 getWeather() 메서드로 넘어가보자

getWeather() 메서드에서 만든 url을 getStringFromURL() 메서드를 통해 날씨의

정보를 가져오는데 성공하였으니 이 다음에는 가져온 날씨의 정보를 분리하여

내가 원하는데로 사용하는 일만 남았다.

 

api서버에 요청한 데이터는 json형식이였으므로 json형식으로 받아 안에서 필요한 데이터를

꺼내주어야한다 이때에 필요한 라이브러리는 json 라이브러리이다.

<dependency>
     <groupId>org.json</groupId>
     <artifactId>json</artifactId>
     <version>20180813</version>
</dependency>

 

JSONObject, JSONArray를 이용하여 값을 분리하여주는데 값이 담긴 모습을보면 respons안에 body안에

items가 있고 그 안에 내가 필요한 정보를 가진 item들이 배열 형식으로 담겨져있다.

JSONObject.get() 메서드를 이용해 안에있는 값들을 하나씩 꺼내어주고

마지막으로 JSONArray를 이용하여 배열형식으로 담겨있는 나머지 자료들을 꺼내어주면

내가 필요한 값들이 출력되는것이다. 

원래는 위의 이미지의 INFO : 안쪽에 있는 형태로 담겨오지만 그 아래는 전부 분리해내어 출력한 모습이다.

 

분리를 마친 후에는 if문을 이용하여 jsp에 보내줄 이모티콘값을 switch case를 통하여

분리하여주고 weather_dto의 객체안에 담아서 jsp단에 값을 전달하여주면

해당 날씨에 맞는 이모티콘과 온도 강수량이 출력된다!

 

글이 굉장히 길어 왔다갔다 복잡할수도 있으나

이 글을 본다면 기상 api를 이용하여 값을끌어와 출력할수 있을만큼 자세히 풀어두었다.