목차 | |
1. | 지도 & 날씨 연동 |
2. | properties |
1. 지도 & 날씨 연동
▶ 코드
◈ 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}">
<body>
<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 Key 입력&libraries=services'}"></script>
<!-- <button onclick="getLocation()">주변 인기 장소 찾기</button>-->
<p id="status">위치를 찾지 못했습니다</p>
<!-- <h1>Geolocation API로 현재 위치 가져오기</h1>-->
<div id="map" style="width:500px;height:400px;"></div>
<ul id="places"></ul>
<script th:src="@{/js/currentLocationMap.js}"></script>
<hr>
<!-- <form th:action="@{/}" method="post">-->
<!-- <input name="address" placeholder="도로명 주소를 입력해주세요."/>-->
<!-- <button type="submit">입력</button>-->
<!-- </form>-->
<form id="addressForm" th:action="@{/}" method="post" style="display: none;">
<input id="addressInput" name="address" type="text" />
</form>
<div th:unless="${weather == null}">
<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>
<hr>
<script>
</script>
</div>
</div>
</body>
</html>
◈ currentLocationMap.js
let map;
let geocoder;
function initializeMap() {
// Geocoder 객체 생성
geocoder = new kakao.maps.services.Geocoder();
// 페이지 로드 시 위치 정보 가져오기
getLocation();
}
function getLocation() {
const status = document.getElementById("status");
// Geolocation API 지원 여부 확인
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude } = position.coords;
status.textContent = `위도: ${latitude}, 경도: ${longitude}`;
// Kakao Maps Geocoder로 도로명 주소 가져오기
const coords = new kakao.maps.LatLng(latitude, longitude);
// 지도를 해당 위치로 이동
const mapContainer = document.getElementById('map');
const mapOption = {
center: coords, // 지도의 중심 좌표 설정
level: 7 // 지도 확대 수준(레벨) 설정
};
map = new kakao.maps.Map(mapContainer, mapOption);
// 마커 표시
const marker = new kakao.maps.Marker({
position: coords,
map: map
});
// marker.setMap(map);
// 주소 변환
geocoder.coord2Address(coords.getLng(), coords.getLat(), (result, status) => {
console.log("API 호출 결과: ", result);
console.log("API 상태: ", status);
if (status === kakao.maps.services.Status.OK) {
// console.log("result.length: ", result.length);
// console.log("result[0].road_address: ", result[0].road_address);
if (result.length > 0) {
// 도로명 주소가 있으면 도로명 주소 사용, 없으면 일반 주소 사용
const region_1depth_name = result[0]?.address?.region_1depth_name;
const region_2depth_name = result[0]?.address?.region_2depth_name;
const region_3depth_name = result[0]?.address?.region_3depth_name;
const depthAddress = region_1depth_name + region_2depth_name + region_3depth_name;
// console.log("roadAddress: ", roadAddress);
// console.log("result[0]?.address_name: ", result[0]?.address_name);
// console.log("주소: ", address);
if (depthAddress) {
console.log("도로명 주소: ", depthAddress);
// 페이지 로드 후 한 번만 자동 제출하도록 설정
const addressInput = document.getElementById("addressInput");
addressInput.value = depthAddress;
// 'addressForm' 제출 방지 여부 확인
if (!sessionStorage.getItem('addressSubmitted')) {
const addressForm = document.getElementById("addressForm");
addressForm.submit();
// 제출한 후 sessionStorage에 표시
sessionStorage.setItem('addressSubmitted', 'true');
}
} else {
console.error("도로명 주소를 찾을 수 없습니다.");
}
} else {
console.error("주소 변환에 실패했습니다.");
}
} else {
console.log("coord2Address API 호출 실패: ", status);
}
});
},
(error) => {
status.textContent = `위치 정보를 가져올 수 없습니다: ${error.message}`;
},
{
enableHighAccuracy: true, // 정확도 우선 모드
timeout: 10000, // 10초 이내에 응답 없으면 에러 발생
maximumAge: 0 // 항상 최신 위치 정보 수집
}
);
} else {
status.textContent = "브라우저가 위치 서비스를 지원하지 않습니다.";
}
}
// Kakao 지도 API가 로드된 후 initializeMap 호출
window.onload = initializeMap;
// kakao map API로 지도 띄우기
/* var container = document.getElementById('map');
var options = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3
};
var map = new kakao.maps.Map(container, options);*/
▷ 출력
2. properties
◈ 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_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;
}
}
◈ WeatherController.java
package com.project.joonggo.controller;
import com.project.joonggo.service.WeatherService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
@Controller
@RequiredArgsConstructor
public class WeatherController {
private final WeatherService weatherService;
// @Value("${KakaoMap_API_KEY}")
// private String KakaoMap_API_KEY;
@GetMapping
public String home(){
return "index";
}
// @GetMapping
// public String home(Model model) {
// model.addAttribute("KakaoMap_API_KEY", KakaoMap_API_KEY);
// return "index";
// }
@PostMapping("/")
public String showWeather(@RequestParam("address") String address, Model model){
Map<String, String> lanLon = weatherService.returnLanLon(address);
model.addAttribute("weather", weatherService.returnWeather(lanLon));
return "index";
}
}
1. config.properties 파일 생성
src/main/resources 하위에 config.properties 파일 생성 후, 다음과 같이 API KEY 값 작성
src/main/resources 하위에 config.properties 파일 생성 후, 다음과 같이 API KEY 값 작성
2. @ProvertySoursece("classpath:config.properties")
API KEY를 사용하고자 하는 파일에 @PropertySource 어노테이션 작성
@PropertySource("classpath:config.properties")
public class SampleController {
...
}
3. API KEY 불러오기
@Value 어노테이션을 통해 config.properties 파일에서 설정해둔 변수명으로 값 주입
@Value("${SAMPLE_API_KEY}")
private String API_KEY;
4. .gitignore에 추가
보안을 위해 .gitignore 파일에 config.properties 추가
config.properties
▣ 참고 자료 출처
- 좌표를 도로명 주소로 변환
https://apis.map.kakao.com/web/sample/coord2addr/
- properties
'Project > AWS-Final' 카테고리의 다른 글
최종 프로젝트(7) - AWS 풀스택 과정 96일차 (0) | 2024.12.13 |
---|---|
최종 프로젝트(6) - AWS 풀스택 과정 95일차 (0) | 2024.12.12 |
최종 프로젝트(4) - AWS 풀스택 과정 93일차 (0) | 2024.12.10 |
최종 프로젝트(3) - AWS 풀스택 과정 92일차 (0) | 2024.12.09 |
최종 프로젝트(2) - AWS 풀스택 과정 91일차 (0) | 2024.12.06 |