Project/AWS-Final

최종 프로젝트(8) - AWS 풀스택 과정 97일차

awspspgh 2024. 12. 16. 09:33
목차
1. 날씨 아이콘

 

1. 날씨 아이콘

OpenWeather API

OpenWeather API에서 날씨 아이콘을 출력하려면 weather에서 날씨에 따른 아이콘 코드를 가져와야 함

... 
  "weather": [
	{
	  "id": 500,
	  "main":"Rain",
	  "description": "light rain",
	  "icon": "10n"
	}
  ],
...

 icon의 코드는 weather 배열에 있는 첫 번째 객체에 있음

 

아래의 OpenWeather API URL을 통해서 이미지를 화면에 출력할 수 있음

https://openweathermap.org/img/wn/10d@2x.png

 URL을 해석하자면

- https://openweathermap.org/img/wn/: OpenWeatherMap의 아이콘 이미지가 위치하는 기본 URL임

- 10d: 날씨 아이콘의 코드임 (숫자 + 영어 형태)

  - 숫자날씨 상태를 나타내며, 10은 비가 오는 날씨를 의미함

  - 영어시간대를 나타내며, d는 낮을 의미함

- @2x: 이미지를 2배 크기로 요청하는 것을 의미함

- .png: 이미지 파일 형식으로 PNG 형식의 아이콘을 요청하는 것을 의미함

=> 따라서, 이 URL은 비가 오고 낮 시간대인 날씨에 해당하는 아이콘을 2배 크기로 요청하는 링크입니다.

 

 아이콘 목록

 

url을 활용하여 아이콘을 출력을 다음과 같이 할 수 있음

▶ 코드

 index.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultrap.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout}">

<div layout:fragment="content">
  <div class="container-md">
    <!--    카카오맵 API 로딩 (HTTPS 사용)-->
    <script type="text/javascript"
            th:src="@{'https://dapi.kakao.com/v2/maps/sdk.js?appkey=내 API 키 입력&libraries=services'}"></script>

      <p id="status">위치를 찾지 못했습니다</p>
      <div id="map" style="width:500px;height:400px;"></div>
      <ul id="places"></ul>

      <hr>

    <form id="addressForm" th:action="@{/}" method="get" style="display: none;">
      <input id="addressInput" name="address" type="text" />
    </form>

    <script th:src="@{/js/currentLocationMap.js}"></script>

    <div th:unless="${weather == null}">
      <li th:text="'아이콘 : ' + ${weather['weather_icon']}"></li>
      <img th:src="'https://openweathermap.org/img/wn/' + ${weather['weather_icon']} + '@2x.png'" alt="Weather Icon" />
      <li th:text="'날씨 : ' + ${weather['weather_main']}"></li>
      <li th:text="'날씨 설명 : ' + ${weather['weather_description']}"></li>
      <li th:text="'온도 : ' + ${weather['temperature']} + '℃'"></li>
      <li th:text="'습도 : ' + ${weather['humidity']} + '%'"></li>
    </div>
    <div th:if="${weather == null}">
      <p>날씨 정보를 불러올 수 없습니다.</p>
    </div>
  </div>
</div>

 

 WeatherService.java

package com.project.joonggo.service;

import org.springframework.beans.factory.annotation.Value;
import org.json.JSONObject;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;


@Service
@PropertySource("classpath:config.properties")
public class WeatherService {
    @Value("${Geocoder_API_KEY}")
    private String Geocoder_API_KEY;

    @Value("${OpenWeatherMap_API_KEY}")
    private String OpenWeatherMap_API_KEY;

    // 위도와 경도를 Map<String, String> 형태로 반환하는 메서드
    public Map<String, String> returnLanLon(String address){
        Map<String, String> coordinates = new HashMap<>();
        String apiKey = Geocoder_API_KEY; // Geocoder API 2.0에서 발급받은 API Key 작성할 것

        try{
            // 주소 인코딩 (인코딩 X 시 400 에러 발생함)
            String encodedAddress = URLEncoder.encode(address, StandardCharsets.UTF_8.toString());
            String apiUrl = "https://api.vworld.kr/req/address?service=address&request=getCoord&key=" + apiKey + "&type=ROAD&address=" + encodedAddress;

            // URL 객체 생성
            URL url = new URL(apiUrl);

            // 연결 설정
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");

            // 응답 코드 확인
            if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                StringBuilder response = new StringBuilder();
                String inputLine;

                // 응답 내용 읽기
                while ((inputLine = in.readLine()) != null){
                    response.append(inputLine);
                }
                in.close();

                // JSON 응답 파싱
                JSONObject jsonResponse = new JSONObject(response.toString());
                if(jsonResponse.getJSONObject("response").getString("status").equals("OK")) {
                    String x = jsonResponse.getJSONObject("response").getJSONObject("result").getJSONObject("point").getString("x");
                    String y = jsonResponse.getJSONObject("response").getJSONObject("result").getJSONObject("point").getString("y");
                    coordinates.put("lat", y);
                    coordinates.put("lon", x);
                }
            }else{
                System.out.println("Error: " + conn.getResponseCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return coordinates;
    }

    // 날씨 정보를 Map<String, String> 형태로 반환하는 메서드
    public Map<String, String> returnWeather(Map<String, String> lanLon){
        String apiKey = OpenWeatherMap_API_KEY; // Open Weather Map 날씨 API에서 발급받은 API Key 작성할 것

        // 넘어온 위도, 경도를 포함한 url
        String apiUrl = "https://api.openweathermap.org/data/2.5/weather?lat=" + lanLon.get("lat") + "&lon=" + lanLon.get("lon") + "&appid=" + apiKey;

        Map<String, String> weather = new HashMap<>();

        try {
            // URL 객체 생성
            URL url = new URL(apiUrl);
            // 연결 설정
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");

            // 응답 코드 확인
            if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                StringBuilder response = new StringBuilder();
                String inputLine;

                // 응답 내용 읽기
                while((inputLine = in.readLine()) != null){
                    response.append(inputLine);
                }
                in.close();

                // JSON 응답 파싱
                JSONObject jsonResponse = new JSONObject(response.toString());

                weather.put("weather_icon", jsonResponse.getJSONArray("weather").getJSONObject(0).getString("icon"));
                weather.put("weather_main", jsonResponse.getJSONArray("weather").getJSONObject(0).getString("main"));
                weather.put("weather_description", jsonResponse.getJSONArray("weather").getJSONObject(0).getString("description"));

                BigDecimal temp = jsonResponse.getJSONObject("main").getBigDecimal("temp");
                BigDecimal tempCelsius = BigDecimal.valueOf(temp.doubleValue() - 273.15).setScale(2, RoundingMode.HALF_UP); // 소수점 둘째 자리에서 반올림

                weather.put("temperature", String.valueOf(tempCelsius));

                int humidity = jsonResponse.getJSONObject("main").getInt("humidity");
                weather.put("humidity", Integer.toString(humidity));
            } else {
                System.out.println("Error: " + conn.getResponseCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return weather;
    }

}

 

=> index.html - WeatherService.java에서 가져온 weather_iconURL 사이에 삽입하기

<img th:src="'https://openweathermap.org/img/wn/' + ${weather['weather_icon']} + '@2x.png'" alt="Weather Icon" />

 

=> WeatherService.java - weather 배열객체에서 icon 속성의 value 값 찾아오기

 // JSON 응답 파싱
JSONObject jsonResponse = new JSONObject(response.toString());

weather.put("weather_icon", jsonResponse.getJSONArray("weather").getJSONObject(0).getString("icon"));

 

▷ 출력

 

▣ 참고 자료 출처

https://openweathermap.org/weather-conditions

 

Weather Conditions - OpenWeatherMap

Ulla OpenWeather AI assistant Chat with Ulla Ask her anything about OpenWeather products

openweathermap.org