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

[Java] 날씨 정보 가져오기(위도/경도 포함)

by 코딩중독 2023. 12. 20.

목차

    build.gradle 파일에 gson 라이브러리 추가

    날씨 정보 api에서 전달받은 json 파일을 파싱 하기 위한 gson 라이브러리 추가하기

    1. https://mvnrepository.com/ 접속
    2. gson 검색
    3. 사용할 버전 선택
    4. 사용할 방식 선택하여 추가하기 (Maven, Gradle, jar파일 다운로드 등...)

    dependencies {
    
        // https://mvnrepository.com/artifact/com.google.code.gson/gson
        implementation 'com.google.code.gson:gson:2.10.1'
    
    }

     

     

    프로젝트 구조 만들기

    1. 위도/경도 DTO(Locale), 날씨정보 DTO(Weather)
    2. 위도/경도 Service(LocaleService), 날씨정보 Service(WeatherService)
    3. 전체(날씨정보) 컨트롤러
    4. 사용자 화면(ConsoleView)

     

    api 키 발급

    1. https://openweathermap.org/ 가입하기
    2. 사용자 메뉴에서 키 발급받기

    api key 발급
    api 키 발급

     

     

    위도/경도 받아오기

    API call 예시

    http://api.openweathermap.org/geo/1.0/direct?q={city name},{state code},{country code}&limit={limit}&appid={API key}

     

    Parameters

    • q (필수값) : 도시이름, 주 코드(미국만 해당) 및 국가 코드를 쉼표로 구분하여 작성
    • appid (필수값) : 발급받은 API 키
    • limit (옵션값) : API 응답의 수 (최대 5개)
    // 항상 최대값으로 5개를 가져오도록 전달, country는 메서드를 호출하는 쪽에서 주입(사용자가 입력)
    String address = "http://api.openweathermap.org/geo/1.0/direct?q=" + country + "&limit=5&appid=" + Api.key();

     

    Http 통신

    URL url = new URL(address);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setRequestProperty("Accept", "application/json");
    responseCode = connection.getResponseCode();
    if (responseCode == 200) {
        BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line;
        StringBuffer sb = new StringBuffer();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
    
        // TODO json parsing
    
    } else {
        throw new RuntimeException("Http Error");
    }

     

    응답값 파싱 후 DTO 담기

    JsonArray localeArray = JsonParser.parseString(sb.toString()).getAsJsonArray();
    for (JsonElement element : localeArray) {
        JsonObject object = element.getAsJsonObject();
        if (object.getAsJsonObject().has("country")) {
            String ct = object.getAsJsonObject().get("country").getAsString();
            if (ct.equals("KR")) {
                locale.setLat(object.getAsJsonObject().get("lat").getAsDouble());
                locale.setLon(object.getAsJsonObject().get("lon").getAsDouble());
                locale.setSucceed(true);
                locale.setName(country);
                break;
            }
        }
    }
    
    
    // 필요한 값만 변수로 선언한 LocaleDTO
    public class Locale {
    
        private boolean isSucceed = false;	// http 응답 결과
    
        private String name;	// 도시이름
    
        private Double lat;	// 위도
    
        private Double lon;	// 경도
    
        public Locale() {
        }
    
        public Locale(boolean isSucceed, String name, Double lat, Double lon) {
            this.isSucceed = isSucceed;
            this.name = name;
            this.lat = lat;
            this.lon = lon;
        }
    
        public boolean isSucceed() {
            return isSucceed;
        }
    
        public void setSucceed(boolean succeed) {
            isSucceed = succeed;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getLat() {
            return lat;
        }
    
        public void setLat(Double lat) {
            this.lat = lat;
        }
    
        public Double getLon() {
            return lon;
        }
    
        public void setLon(Double lon) {
            this.lon = lon;
        }
    
        @Override
        public String toString() {
            return "Locale{" +
                    "isSucceed=" + isSucceed +
                    ", name='" + name + '\'' +
                    ", lat=" + lat +
                    ", lon=" + lon +
                    '}';
        }
    }

     

    위도/경도를 이용하여 날씨 정보 받아오기

    API call 예시

    https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}

     

    Parameters

    • lat (필수값) : 위도
    • lon (필수값) : 경도
    • appid (필수값) : 발급받은 API 키
    • lang (선택값) : 국가별 언어 지원
    String address = "https://api.openweathermap.org/data/2.5/weather?lat="
            + locale.getLat() + "&lon=" + locale.getLon()
            + "&appid=" + Api.key() + "&lang=kr";

     

    Http 통신

    try {
        URL url = new URL(address);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setRequestProperty("Accept", "application/json");
        responseCode = connection.getResponseCode();
        if (responseCode == 200) {
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuffer sb = new StringBuffer();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
    
            // json parsing
    
        } else {
            throw new RuntimeException("Http Error");
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }

     

    응답값 파싱 후 DTO 담기

    JsonObject weatherData = JsonParser.parseString(sb.toString()).getAsJsonObject();
    JsonArray weatherArray = weatherData.getAsJsonArray("weather");
    
    String description = weatherArray.get(0).getAsJsonObject().get("description").getAsString();
    double temp = convertKelvinToCelsius(weatherData.getAsJsonObject("main").get("temp").getAsDouble());
    double tempMin = convertKelvinToCelsius(weatherData.getAsJsonObject("main").get("temp_min").getAsDouble());
    double tempMax = convertKelvinToCelsius(weatherData.getAsJsonObject("main").get("temp_max").getAsDouble());
    int humidity = weatherData.getAsJsonObject("main").get("humidity").getAsInt();
    String sunrise = convertEpochToTimestamp(weatherData.getAsJsonObject("sys").get("sunrise").getAsLong());
    String sunset = convertEpochToTimestamp(weatherData.getAsJsonObject("sys").get("sunset").getAsLong());
    
    weather.setDescription(description);
    weather.setTemp(temp);
    weather.setTempMin(tempMin);
    weather.setTempMax(tempMax);
    weather.setHumidity(humidity);
    weather.setSunrise(sunrise);
    weather.setSunset(sunset);
    
    // 필요한 값만 변수로 선언한 WeatherDTO
    public class Weather {
    
        private int resultCode;
    
        private String description;
    
        private Double temp;
    
        private Double tempMin;
    
        private Double tempMax;
    
        private Integer humidity;
    
        private String sunrise;
    
        private String sunset;
    
        public Weather() {
        }
    
        public Weather(int resultCode, String description, Double temp, Double tempMin, Double tempMax, Integer humidity, String sunrise, String sunset) {
            this.resultCode = resultCode;
            this.description = description;
            this.temp = temp;
            this.tempMin = tempMin;
            this.tempMax = tempMax;
            this.humidity = humidity;
            this.sunrise = sunrise;
            this.sunset = sunset;
        }
    
        public int getResultCode() {
            return resultCode;
        }
    
        public void setResultCode(int resultCode) {
            this.resultCode = resultCode;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Double getTemp() {
            return temp;
        }
    
        public void setTemp(Double temp) {
            this.temp = temp;
        }
    
        public Double getTempMin() {
            return tempMin;
        }
    
        public void setTempMin(Double tempMin) {
            this.tempMin = tempMin;
        }
    
        public Double getTempMax() {
            return tempMax;
        }
    
        public void setTempMax(Double tempMax) {
            this.tempMax = tempMax;
        }
    
        public Integer getHumidity() {
            return humidity;
        }
    
        public void setHumidity(Integer humidity) {
            this.humidity = humidity;
        }
    
        public String getSunrise() {
            return sunrise;
        }
    
        public void setSunrise(String sunrise) {
            this.sunrise = sunrise;
        }
    
        public String getSunset() {
            return sunset;
        }
    
        public void setSunset(String sunset) {
            this.sunset = sunset;
        }
    
        @Override
        public String toString() {
            return "Weather{" +
                    "resultCode=" + resultCode +
                    ", description='" + description + '\'' +
                    ", temp=" + temp +
                    ", tempMin=" + tempMin +
                    ", tempMax=" + tempMax +
                    ", humidity=" + humidity +
                    ", sunrise='" + sunrise + '\'' +
                    ", sunset='" + sunset + '\'' +
                    '}';
        }
    }

     

    json 구조에 따라 jsonObject에서 키 값으로 바로 파싱해오거나, 배열에 먼저 접근하여 하위 jsonObject에서 파싱

     

    애플리케이션 시작하여 확인하기

    public class WeatherController {
    
        private final ConsoleView consoleView;
        private final LocaleService localeService;
        private final WeatherService weatherService;
    
        public WeatherController() {
            consoleView = new ConsoleView();
            localeService = new LocaleService();
            weatherService = new WeatherService();
        }
    
        public void applicationStart() {
            while (true) {
                String country = consoleView.getCountry();
                if (country.equalsIgnoreCase("q")) {
                    break;
                } else {
                    Locale locale = localeService.locale(country);
                    Weather weather = weatherService.weather(locale);
                    consoleView.printWeather(weather);
                }
            }
        }
    }

     

    WeatherController에서 위도/경도를 가져오는 Service, 날씨정보를 가져오는 Service 사용

    사용자가 q를 입력하면 애플리케이션 중지, 도시 또는 지역을 입력하면 정보 출력

     

    출력 결과

    > Task :WeatherApplication.main()
    지역을 입력해주세요(시 또는 구 또는 동) : 서초동
    ==============================
    날씨 : 온흐림
    평균기온 : -5
    최저기온 : -5
    최고기온 : -5
    습도 : 44
    일출시각 : 2023/12/20 07:41:56
    일몰시각 : 2023/12/20 17:16:21
    ==============================
    지역을 입력해주세요(시 또는 구 또는 동) : 용산
    ==============================
    날씨 : 구름조금
    평균기온 : -5
    최저기온 : -6
    최고기온 : -5
    습도 : 63
    일출시각 : 2023/12/20 07:42:10
    일몰시각 : 2023/12/20 17:16:20
    ==============================
    지역을 입력해주세요(시 또는 구 또는 동) : 제주도
    ==============================
    날씨 : 가벼운 눈
    평균기온 : -5
    최저기온 : -5
    최고기온 : -5
    습도 : 56
    일출시각 : 2023/12/20 07:32:50
    일몰시각 : 2023/12/20 17:29:12
    ==============================

     

     

    마치며

    기본적인 api 활용법, json 파싱에 대해 알아볼 수 있었다.