Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open Weather API를 연동 #37

Merged
merged 17 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
[submodule "application/wypl-image/src/main/resources/security"]
path = application/wypl-image/src/main/resources/security
url = https://github.com/What-s-Your-Plan/wypl-image-properties.git
branch = main
branch = main
[submodule "application/wypl-core/src/main/resources/security"]
path = application/wypl-core/src/main/resources/security
url = https://github.com/What-s-Your-Plan/wypl-server-properties
branch = main
1 change: 1 addition & 0 deletions application/wypl-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ java {

dependencies {
implementation project(':application:application-common')
implementation project(':client:openweather-client')
implementation project(':domain:jpa-common')
implementation project(':domain:mongo-common')
implementation project(':domain:jpamongo-review-domain')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.wypl.wyplcore.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
33 changes: 11 additions & 22 deletions application/wypl-core/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
spring:
application:
name: wypl-core
jpa:
properties:
hibernate:
show_sql: true
format_sql: true
hibernate:
ddl-auto: create-drop
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:db
username: sa
password:
h2:
console:
enabled: true
path: /h2

de:
flapdoodle:
mongodb:
embedded:
version: 4.0.2
config:
import:
- security/application-mongo.yml
- security/application-oracle.yml
- security/application-weather.yml
activate:
on-profile:
- default
- local
- dev
- prod
1 change: 1 addition & 0 deletions application/wypl-core/src/main/resources/security
Submodule security added at 95d67e
4 changes: 4 additions & 0 deletions client/openweather-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ java {
}

dependencies {
implementation project(':common')

implementation('org.springframework.boot:spring-boot-starter')
implementation('org.springframework.boot:spring-boot-starter-web')
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.wypl.openweatherclient;

import com.wypl.openweatherclient.data.OpenWeatherCond;
import com.wypl.openweatherclient.data.OpenWeatherResponse;

public interface OpenWeatherClient {
OpenWeatherResponse fetchWeather(OpenWeatherCond cond);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.wypl.openweatherclient;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.wypl.openweatherclient.data.OpenWeatherCond;
import com.wypl.openweatherclient.data.OpenWeatherResponse;
import com.wypl.openweatherclient.exception.OpenWeatherErrorCode;
import com.wypl.openweatherclient.exception.OpenWeatherException;
import com.wypl.openweatherclient.type.WeatherRegion;

import lombok.RequiredArgsConstructor;

@EnableConfigurationProperties(OpenWeatherProperties.class)
@RequiredArgsConstructor
@Component
public class OpenWeatherClientImpl implements OpenWeatherClient {

private final RestTemplate restTemplate;
private final OpenWeatherProperties properties;

public OpenWeatherResponse fetchWeather(OpenWeatherCond cond) {
String url = getUrl(cond);
ResponseEntity<OpenWeatherResponse> response = restTemplate.getForEntity(
url,
OpenWeatherResponse.class
);
if (response.getStatusCode().is2xxSuccessful()) {
return response.getBody();
}
if (response.getStatusCode().is5xxServerError()) {
throw new OpenWeatherException(OpenWeatherErrorCode.INTERNAL_SERVER_ERROR);
}
throw new OpenWeatherException(OpenWeatherErrorCode.INVALID_OPEN_WEATHER_REQUEST);
}

private String getUrl(OpenWeatherCond cond) {
StringBuilder url = new StringBuilder(properties.getBaseUrl())
.append("?appid=")
.append(properties.getKey());

addParamByCity(url, cond.city());
addParamByLang(url, cond.isLangKr());
addParamByUnits(url, cond.isMetric());

return url.toString();
}

private void addParamByCity(StringBuilder url, WeatherRegion region) {
url.append("&q=").append(region.getCityEn());
}

private void addParamByLang(StringBuilder url, boolean isLangKr) {
if (isLangKr) {
url.append("&lang=kr");
}
}

private void addParamByUnits(StringBuilder url, boolean isMetric) {
if (isMetric) {
url.append("&units=metric");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.wypl.openweatherclient;

import org.springframework.boot.context.properties.ConfigurationProperties;

import lombok.Data;

@Data
@ConfigurationProperties(prefix = "open-weather")
public class OpenWeatherProperties {
private String key;
private String baseUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.wypl.openweatherclient.data;

import com.wypl.openweatherclient.type.WeatherRegion;

public record OpenWeatherCond(
WeatherRegion city,
boolean isMetric,
boolean isLangKr
) {
public static OpenWeatherCond from(
final WeatherRegion city
) {
return new OpenWeatherCond(city, true, true);
}

public static OpenWeatherCond of(
final WeatherRegion city,
final boolean isMetric,
final boolean isLangKr
) {
return new OpenWeatherCond(city, isMetric, isLangKr);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.wypl.openweatherclient.data;

import java.util.List;

import com.fasterxml.jackson.annotation.JsonProperty;

public record OpenWeatherResponse(
@JsonProperty("weather")
List<WeatherResponse> weather,
@JsonProperty("main")
MainResponse main,
@JsonProperty("sys")
SysResponse sys,
@JsonProperty("dt")
long dateTime
) {

public static WeatherResponse ofByWeatherResponse(final int id, final String main, final String desc) {
return new WeatherResponse(id, main, desc);
}

public static MainResponse fromByMainResponse(
final float temp,
final float maxTemp,
final float minTemp
) {
return new MainResponse(temp, maxTemp, minTemp);
}

public static SysResponse fromBySysResponse(
final long sunrise,
final long sunset
) {
return new SysResponse(sunrise, sunset);
}

public int getWeatherId() {
return weather.get(0).id();
}

public String getWeatherName() {
return weather.get(0).main();
}

public String getWeatherDescription() {
return weather.get(0).description();
}

public float getTemperature() {
return main.temp();
}

public float getMaxTemperature() {
return main.maxTemp();
}

public float getMinTemperature() {
return main.minTemp();
}

public long getSunrise() {
return sys.sunrise();
}

public long getSunset() {
return sys.sunset();
}

public record WeatherResponse(
@JsonProperty("id")
int id,
@JsonProperty("main")
String main,
@JsonProperty("description")
String description
) {
}

public record MainResponse(
@JsonProperty("temp")
float temp,
@JsonProperty("temp_max")
float maxTemp,
@JsonProperty("temp_min")
float minTemp
) {
}

public record SysResponse(
@JsonProperty("sunrise")
long sunrise,
@JsonProperty("sunset")
long sunset
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.wypl.openweatherclient.exception;

import com.wypl.common.exception.ServerErrorCode;

import lombok.Getter;

@Getter
public enum OpenWeatherErrorCode implements ServerErrorCode {
INVALID_OPEN_WEATHER_REQUEST(500, "OPEN_WEATHER_001", "외부 서비스의 오류입니다."),
INTERNAL_SERVER_ERROR(400, "OPEN_WEATHER_002", "올바르지 않은 요청입니다.");

private final int statusCode;
private final String errorCode;
private final String message;

OpenWeatherErrorCode(int statusCode, String errorCode, String message) {
this.statusCode = statusCode;
this.errorCode = errorCode;
this.message = message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.wypl.openweatherclient.exception;

import com.wypl.common.exception.WyplException;

public class OpenWeatherException extends WyplException {
public OpenWeatherException(OpenWeatherErrorCode serverErrorCode) {
super(serverErrorCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.wypl.openweatherclient.type;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum WeatherRegion {
KOREA("Asia/Seoul", "Seoul", "서울"),
WEST_USA("America/Los_Angeles", "Los Angeles", "로스엔젤레스"),
EAST_USA("America/New_York", "New York", "뉴욕"),
ENGLAND("Europe/London", "London", "런던");

private final String timeZone;
private final String cityEn;
private final String cityKr;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.wypl.openweatherclient.type;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import lombok.AllArgsConstructor;
import lombok.Generated;
import lombok.Getter;

/**
* <a href="https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2">OPEN WEATHER ID</a>
*/
@Generated
@AllArgsConstructor
@Getter
public enum WeatherType {
CLEAR(1, new HashSet<>(List.of(800)), "맑음"),
CLOUDS(2, new HashSet<>(List.of(801, 802, 803, 804)), "구름"),
RAIN(3, new HashSet<>(List.of(500, 501, 502, 503, 504, 511, 520, 521, 522, 531)), "비"),
DRIZZLE(4, new HashSet<>(List.of(300, 301, 302, 310, 311, 312, 313, 314, 321)), "이슬비"),
SNOW(5, new HashSet<>(List.of(600, 601, 602, 611, 612, 613, 615, 616, 620, 621, 622)), "눈"),
MIST(6, new HashSet<>(List.of(701, 711, 721, 731, 741, 751, 761, 762)), "안개"),
SQUALL(7, new HashSet<>(List.of(771)), "스콜"),
TORNADO(8, new HashSet<>(List.of(781)), "태풍"),
THUNDERSTORM(9, new HashSet<>(List.of(200, 201, 202, 210, 211, 212, 221, 230, 231, 232)), "천둥");

private final int weatherId;
private final Set<Integer> ids;
private final String description;

public boolean containsIds(final int weatherId) {
return ids.contains(weatherId);
}
}

This file was deleted.

Loading