The New 나만의 Weather 만들기 프로젝트 - (3)

2024. 12. 10. 14:18Spring-Project

이전글

https://codepracticeroom.tistory.com/229

 

The New 나만의 Weather 만들기 프로젝트 - (2)

이전글https://codepracticeroom.tistory.com/228 The New 나만의 Weather 만들기 프로젝트 - (1)실행환경- Mac os- Java17- SpringBoot 3.4.0- Intellij  Weather 완성모습     오늘의 날씨 + 앞으로의 6일의 날씨 에측 데이

codepracticeroom.tistory.com

 

 

이전에 하였던 단기예보와 중기예보는 겹치는 코드가 많이 있다

이런 공통된

코드들을 모듈화를 하여 좀 더 편하게 사용할 것이다

 

 

        StringBuilder urlBuilder = new StringBuilder(vilageFcst);
        urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=" + serviceKey);
        urlBuilder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("1000", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode("JSON", "UTF-8"));

 

 

이 부분은 공통된 코드이다. 이 것을 가져와서 모듈화 시켜준다.

 

먼저 공통된 부분을 담을 클래스를 만들어 준다.

weather_test 아래에 comm 이라는 패키지를 만들어 주고 CommomGetWeather 을 만들어 준다.

 

 

 

위 클래스는 Json 으로 받은 String 를 반환해야 한다. 

그러므로 반환타입이 String 인 메서드를 만들고 단기예보, 중기예보의 @Value 값들을 넣어준다.

그 후 위 코드들을 붙여 넣어준다.

 

CommonGetWeather

public class CommonGetWeather {

    //Value로 properties에 있는 나의 servicekey를 가져온다
    @Value("${my.weather.servicekey}")
    private String serviceKey;

    @Value("${my.weather.sht.getUltraSrtNcst}")
    private String ultraSrtNcst;

    // 초단기예보
    //Value로 properties에 있는 나의 getUltraSrtFcst(초단기예보) 가져온다
    // 현재시간의 + 6시간 이내 데이터 가져옴 ( 5개 )
    @Value("${my.weather.sht.getUltraSrtFcst}")
    private String ultraSrtFcst;

    // 단기예보
    //Value로 properties에 있는 나의 getVilageFcst(단기예보) 가져온다
    // 1 ~ 3, 4일 이내 데이터를 가져옴
    @Value("${my.weather.sht.getVilageFcst}")
    private String vilageFcst;

    @Value("${my.weather.mid.getMidLandFcst}")
    private String midLandFcst;

    @Value("${my.weather.mid.getMidTa}")
    private String midTa;


       public String getWeatherApi() throws IOException {
        StringBuilder urlBuilder = new StringBuilder(vilageFcst);
        urlBuilder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=" + serviceKey);
        urlBuilder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("1000", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode("JSON", "UTF-8"));
    }


}

 

 

       // ---------- 단기예보 --------------------
 
        urlBuilder.append("&" + URLEncoder.encode("base_date", "UTF-8") + "=" + URLEncoder.encode(currentDate, "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("base_time", "UTF-8") + "=" + URLEncoder.encode("1400", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("nx", "UTF-8") + "=" + URLEncoder.encode("62", "UTF-8"));
        urlBuilder.append("&" + URLEncoder.encode("ny", "UTF-8") + "=" + URLEncoder.encode("122", "UTF-8"));

  
    
    
    //-------------- 중기예보 --------------------
  urlBuilder.append("&" + URLEncoder.encode("regId","UTF-8") + "=" + URLEncoder.encode("11B00000", "UTF-8"));
  urlBuilder.append("&" + URLEncoder.encode("tmFc","UTF-8") + "=" + URLEncoder.encode(currentDateTime, "UTF-8"));

 

 

위 부분이 단기예보와 중기예보가 다르므로 파라미터로 판단하여 맞는 String을 가져오도록 하겠다.

 

일단 첫번째 공통된 부분을 하나의 String로 만들어 줄 것이다

public String getWeatherApi(String weatherType, String weatherLink) {

            String getUrlApi = weatherType + "?serviceKey=" +serviceKey
                    + "&pageNo=1&numOfRows=1000&dataType=JSON" + weatherLink;


				...
}

이렇게 하나의 문자열로 만들어 주었다.

 

weatherType는 불러올 데이터가 초단기, 단기, 중기 예보인지 알려주는 것이고 뒤 weatherLink는 앞서 했던 단기, 중기예보의 뒷 부분이다.

 

 

그 다음 단기예보 전용 클래스 ShtWeatherService를 만들어 준다. 이 클래스에서는 단기예보에 관한것만 다룰 것이다.

 

만든 다음에 위 코드 부분을 주입 받아야 한다.

롬복을 사용하므로 ShtWeatherService 클래스 위에 @RequiredArgsConstructor 를 넣고 private final로 주입해 준다.

 

 

ShtWeatherService

@Service
@Slf4j
@RequiredArgsConstructor
public class ShtWeatherService {

    private final CommonGetWeather commonGetWeather;
    
...

 

 

그리고 CommonGetWeather 클래스에 있던 초단기예보 2개, 단기예보 @value로 불러왔단 변수들을 ShtWeatherService에 옮겨준다.

 

@Service
@Slf4j
@RequiredArgsConstructor
public class ShtWeatherService {

    private final CommonGetWeather commonGetWeather;

    // 초단기실황
    //Value로 properties에 있는 나의 getUltraSrtNcst(초단기실황) 가져온다
    // 현재 날씨 가져옴 (1시간 단위)
    @Value("${my.weather.sht.getUltraSrtNcst}")
    private String ultraSrtNcst;

    // 초단기예보
    //Value로 properties에 있는 나의 getUltraSrtFcst(초단기예보) 가져온다
    // 현재시간의 + 6 시간 이내 데이터 가져옴 ( 5개 )
    @Value("${my.weather.sht.getUltraSrtFcst}")
    private String ultraSrtFcst;

    // 단기예보
    //Value로 properties에 있는 나의 getVilageFcst(단기예보) 가져온다
    // 1 ~ 3, 4일 이내 데이터를 가져옴
    @Value("${my.weather.sht.getVilageFcst}")
    private String vilageFcst;

...

 

 

초단기, 단기예보의 요청 링크가 다르므로 알 맞게 값을 넣어줘야 한다

 

먼저 단기예보는 ( 발표시각: 02:00, 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00 ) 시간에만 업데이트가 되며 현재 시간이 00시 30분 이라면 02시의 데이터를 가져올 수 없으므로 전날 23시 데이터를 불러와야 한다.

 

그러므로 단기예보 (vilageFcst) 일 경우에는 시간 계산을 하여 요청 url에 넣어야 한다.

 

 

weatherShtForecastLink

 LocalDateTime date = LocalDateTime.now();
 String currentDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(date);
 String currentTime = DateTimeFormatter.ofPattern("HH").format(date) + "00";

...


int hour = date.getHour();
            // 발표시각: 02:00, 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00
            int[] forecastHours = {2, 5, 8, 11, 14, 17, 20, 23};

            // 현재 시각 이전의 가장 최근 발표 시각 찾기
            String baseTime = "";
            LocalDateTime baseDate = date;

            if (hour < 2) {
                // 당일 02시 이전인 경우 전날 23시 기준
                baseDate = date.minusDays(1);
                baseTime = "2300";
            } else {
                // 현재 시각 이전의 가장 최근 발표 시각 찾기
                for (int i = forecastHours.length - 1; i >= 0; i--) {
                    if (hour >= forecastHours[i]) {
                        baseTime = String.format("%02d00", forecastHours[i]);
                        break;
                    }
                }
            }

            result = "&base_date=" + baseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
                    "&base_time=" + baseTime;

 

현재 시간이 10시 라면 08시 시간을 넣어주는 코드이다. 만약 현재 시간이 00시50분 이라면 전날 23시 시간을 넣어준다

 

    result = "&base_date=" + baseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
                    "&base_time=" + baseTime;
                    
    // 현재 시간이 2024년 12월 10일 00시 50분 일 때..
    
    result = &base_date=20241209&base_time=2300

 

 

초단기예보, 실황 데이터는 url이 같다

그러므로 단기예보를 제외한 나머지는 초단기 실황, 예보이다

 

// ultraSrtNcst, ultraSrtFcst Call Weather API
result = "&base_date=" + currentDate + "&base_time=" + currentTime;

 

 

ShtWeatherService 전체코드

 

@Service
@Slf4j
@RequiredArgsConstructor
public class ShtWeatherService {

    private final CommonGetWeather commonGetWeather;

    // 초단기실황
    //Value로 properties에 있는 나의 getUltraSrtNcst(초단기실황) 가져온다
    // 현재 날씨 가져옴 (1시간 단위)
    @Value("${my.weather.sht.getUltraSrtNcst}")
    private String ultraSrtNcst;

    // 초단기예보
    //Value로 properties에 있는 나의 getUltraSrtFcst(초단기예보) 가져온다
    // 현재시간의 + 6 시간 이내 데이터 가져옴 ( 5개 )
    @Value("${my.weather.sht.getUltraSrtFcst}")
    private String ultraSrtFcst;

    // 단기예보
    //Value로 properties에 있는 나의 getVilageFcst(단기예보) 가져온다
    // 1 ~ 3, 4일 이내 데이터를 가져옴
    @Value("${my.weather.sht.getVilageFcst}")
    private String vilageFcst;

    @PostConstruct
    public void shtInit(){
        // 뒷 url
        String shtWeatherLink = weatherShtForecastLink(vilageFcst);

        // 데이터 url 요청
        String resultValue = commonGetWeather.getWeatherApi(vilageFcst, shtWeatherLink);

        log.info("resultValue={}", resultValue);

    }




    public String weatherShtForecastLink(String weatherType){

        LocalDateTime date = LocalDateTime.now();
        String currentDate = DateTimeFormatter.ofPattern("yyyyMMdd").format(date);
        String currentTime = DateTimeFormatter.ofPattern("HH").format(date) + "00";

        String result = "";

        if (weatherType.equals(vilageFcst)) {

            //vilageFcst Call Weather API

            int hour = date.getHour();
            // 발표시각: 02:00, 05:00, 08:00, 11:00, 14:00, 17:00, 20:00, 23:00
            int[] forecastHours = {2, 5, 8, 11, 14, 17, 20, 23};

            // 현재 시각 이전의 가장 최근 발표 시각 찾기
            String baseTime = "";
            LocalDateTime baseDate = date;

            if (hour < 2) {
                // 당일 02시 이전인 경우 전날 23시 기준
                baseDate = date.minusDays(1);
                baseTime = "2300";
            } else {
                // 현재 시각 이전의 가장 최근 발표 시각 찾기
                for (int i = forecastHours.length - 1; i >= 0; i--) {
                    if (hour >= forecastHours[i]) {
                        baseTime = String.format("%02d00", forecastHours[i]);
                        break;
                    }
                }
            }

            result = "&base_date=" + baseDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) +
                    "&base_time=" + baseTime;

        } else {
            // ultraSrtNcst, ultraSrtFcst Call Weather API
            result = "&base_date=" + currentDate + "&base_time=" + currentTime;
        }
        // 공통 위치 URL
        result+="&nx=62&ny=122";
        return result;
    }
}