ABOUT ME

-

  • [ Java ] 기상청 Api 완벽 활용하기 - 2 ( 시간별 날씨, 주간 날씨 )
    BackEnd/Spring 2025. 4. 5. 18:17
    반응형

    https://yumedev.tistory.com/57

     

    [ Java ] 기상청 Api 완벽 활용하기 - 1 ( 실시간 날씨, 미세먼지 조회 )

    기상청 api를 사용하여 날씨 정보를 가져올때 각 api별로 보내야하는 파라미터가 달라서 사용하기가 까다롭다. 간단하게 설명을 위해 자세한 코드 실행 결과보다는 과정으로 설명 진행 ( 예외처

    yumedev.tistory.com

     

    실시간 날씨, 미세먼지 api활용에 이어서 이제 날씨에서 시간별 날씨와 주간 날씨 데이터를 가져오고자 한다.

    어떤 api를 사용하는지 확인을 하고자 하면 위 링크를 통해 간단하게 보고 오면 좋을 것 같다. 

     

    간단하게 설명을 위해 자세한 코드 실행 결과보다는 과정으로 설명 진행 ( 예외처리 작업 및 DB 처리 과정은 생략했다. )

    Front 에서 지오코딩을 활용하여 현재 위도 경도 값을 찾고 해당 위도 경도값을 Back으로 보내는 방식으로 진행

     

    날씨 api는 그리드 좌표계로 위도 경도 값을 바꿔주어야하는데 이때 바꿔주는 방법은 위 링크에 그리드 좌표계 변환 하는 메서드를 올려두었다.


    시간별 날씨 - 단기예보 Api

    기상청이나 날씨 정보를 보면 1시간 간격으로 그래프를 보여주는데,

    ( 날씨 그래프를 보여줄때 front에서 그래프를 아래의 기상청처럼 꾸미는 방법은 다양하게 있겠지만 

    그래프를 position: absolute를 주어 해당 위치에 그래프를 넣어주는 방식으로 하여

    기상청의 시간별 날씨 그래프를 만들었다. -> 이 방법이 제일 편할 것 같아서.. )

     

    시간별 날씨 데이터를 가져오기 위해서 우선 단기예보조회 api를 활용한다.

    해당 api를 요청하면 각 시간별로 3일간의 데이터를 가져올 수 있다.

     

    이를 활용하여 요청시간을 기준으로 앞으로 3일간의 시간별 날씨 데이터를 가져올 수 있다.

    하지만 여기서 좀 더 정확하게 하기 위해서

     

    이전에 사용했던 초단기예보조회 api를 활용하여 현재 시간을 기준으로 6시간의 데이터를 업데이트를 시켜준다.

     

    api호출은 따로 재사용을 위해 private 메서드로 빼서 사용했다.

    getShortWeather은 단기 api를 호출하고 db에 저장하는 메서드이며,

    ultarShortWeather은 초단기 api를 호출하고 db에 저장 및 업데이트하는 메서드이다.

    /* 초단기 & 단기 */
        public List<WeatherDaysResponseDto> getShortTermWeather(GeoLocationDto param) {
            String todayDate = getCurrentDate("0");
            String currentTime = String.format("%02d",getCurrentHour()) + String.format("%02d",getCurrentMinute());
    
            // 단기 저장 후 초단기 현재 시각 6시간 저장
            boolean shortFcst = getShortWeather(param);
    
            // 단기 저장 성공시 초단기 세팅
            boolean ultraShortFcst = getUltraShortWeather(param);
    
            // 현재 조회한 기준으로 부터 fcstDt 와 fcstTm이 기준 이후인 값들 전부 조회
            WeatherRequestDto weatherDaysRequestDto = new WeatherRequestDto();
            weatherDaysRequestDto.setFcstDt(todayDate);
            weatherDaysRequestDto.setFcstTm(String.format("%02d00",getCurrentHour()));
    
            weatherDaysRequestDto.setX(param.getX());
            weatherDaysRequestDto.setY(param.getY());
    
            return weatherApiMapper.selectWeatherDay(weatherDaysRequestDto);
        }

     

    이렇게 단기 저장 후 초단기를 저장하면 현재 기준으로 6시간은 변경되는 빈도가 잦으며, 좀 더 정확한 데이터를 제공할 수 있다.


    주간 날씨 - 중기예보 Api

    주간날씨의 경우 기상청 중기예보 api를 활용한다.



    중기예보에서 육상예보조회와 중기기온조회 두개의 api를 사용하는데

    육상예보조회는 날씨의 정보를 조회하고 중기기온은 온도의 정보를 조회한다.

     

    이때 중기예보는 regId를 사용하는데

    해당 regId값은 지역마다 다르다. ( 추가로 같은 지역이어도 기온조회와 육상예보조회의 regId 코드값이 다르니 주의 )

    이 regId 지역코드 값은 중기예보 api의 문서에 포함되어있다.

     

    그럼 위도 경도를 통해서 어떻게 regId값을 가져와야하는지 판단해야하므로,

    역지오코딩을 활용했다. 

    역지오코딩은 현재 위도와 경도 값을 보내면 해당위치를 주소로 변환해준다.

    public static String nomianatim(WeatherApiRequestDto location) {
            String urlString = "https://nominatim.openstreetmap.org/reverse?lat=" + location.getLatitude() + "&lon=" + location.getLongitude() + "&format=json";
    
            try {
                URL url = new URL(urlString);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    
                connection.setRequestMethod("GET");
                connection.setRequestProperty("User-Agent", "Mozilla/5.0");
    
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
    
                StringBuffer response = new StringBuffer();
    
                while((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
    
                in.close();
    
                JSONObject jsonObject = new JSONObject(response.toString());
                String formattedAddress = jsonObject.getString("display_name");
    
                return formattedAddress;
    
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
    
            return null;
        }

     

    이 주소를 활용하여 regId 코드값을 찾는다.

    만약 역지오코딩에서 나온 주소값에 '서울' 이 값이 포함되어있다면 서울 인것으로 파악하여 서울 지역코드를 사용하여 중기예보 api를 호출하는 방식으로 진행했다.

     

    중기예보 api의 경우 3일 후 부터 10일 후 까지의 정보를 조회할 수 있다.

    그럼 오늘부터 3일 후 이 사이의 데이터는 시간별 날씨 데이터를 활용한다.

     

    그러기 위해서 중기예보의 데이터를 요청시에 시간별 날씨 처럼 단기 api를 호출하고 초단기 api를 호출하여

    오늘부터 3일 까지의 데이터를 만들어준다.

     

    이후 중기 api를 활용하여 3일 부터 10일까지의 날씨 데이터를 만들어준다.

        public List<WeatherWeekResponseDto> getWeatherWeeks(GeoLocationDto param) {
            Result initShort = weahterInitShort(param);
    
            // 오늘 부터 10일간의 데이터를 가져오기 위해 단기 + 초단기 + 중기 활용하여 호출
            // 단기 저장 후 초단기 현재 시각 6시간 저장
            boolean shortFcst = getShortWeather(param);
    
            // 단기 저장 성공시 초단기 세팅
            boolean ultraShortFcst = getUltraShortWeather(param);
    
            boolean midWeather = getMidWeather(param);
    
            WeatherRequestDto weatherWeekRequestDto = new WeatherRequestDto();
            weatherWeekRequestDto.setFcstDt(getCurrentDate("0"));
            weatherWeekRequestDto.setX(param.getX());
            weatherWeekRequestDto.setY(param.getY());
    
            return weatherApiMapper.selectWeatherWeek(weatherWeekRequestDto;
        }

     

    데이터를 조회하면 단기 예보의 경우에는 시간별이므로 이를 잘 활용해 주어야한다.

     

    이후 주간 날씨 정보를 보면 최고온도, 최저온도, 강수 확률, 오전 오후 날씨를 보여준다.

    중기예보 api의 경우에는 해당 날짜의 최고,최저온도, 강수확률, 오전 오후 날씨 데이터를 조회하여 간단한데,

     

    단기 조회와 중기조회는 각각 다른 테이블에 저장하여 관리하고 있으므로 

     

    단기예보의 경우는 시간별 데이터를 가져오므로 최고, 최저 온도, 강수 확률, 오전 오후 데이터를 계산을 직접해야한다.

    back에서 처리해도 되지만, 쿼리에서 처리했다. -> 이 부분은 기준을 어떻게 하느냐에 따라서 결과가 달라진다.

     

    최대한 정확하게 하기 위해서 중기예보 요청시에 한가지 조건을 추가하여 단기 api를 추가 요청을 했다.

    만약 중기 요청시에 오늘날짜의 00시 부터 데이터가 존재하지 않을경우 00시부터 없는 시간대까지 db에 저장하여 

    오늘 날짜의 데이터를 00시부터 전부 저장할 수 있도록 처리하여 db에 저장했다.

     

    이제 쿼리에서 해당 단기예보 db에서 해당날짜의 00 - 23시 까지의 사이에서의 최고 기온과 최저 기온을 계산하여 최고 기온과 최저 기온을 가져오고,

     

    09 ~ 12시 미만데이터와 12 ~ 15시 까지의 데이터 중에서 데이터를 하나 골라서 오전 오후 강수확률과 구름상태를 가져와서 처리했다.

    ( 기준은 최고온도로 했다. )

     

    중기예보 api의 경우에는 처음 요청시에는 많은 api를 요청하다보니 시간이 오래 걸린다.

    좀 덜 정확하더라도 속도를 개선하는 편이 더 좋지 않을까 생각한다.

     

     

    728x90
    반응형