-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from dnd-side-project/feat/weather
[BLOOM-030] 날씨에 맞는 식물 관리법 조회 API
- Loading branch information
Showing
13 changed files
with
254 additions
and
3 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
src/main/kotlin/dnd11th/blooming/api/controller/weather/WeatherMessageController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package dnd11th.blooming.api.controller.weather | ||
|
||
import dnd11th.blooming.api.dto.weather.WeatherMessageResponse | ||
import dnd11th.blooming.api.service.weather.WeatherMessage | ||
import dnd11th.blooming.api.service.weather.WeatherService | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.RequestMapping | ||
import org.springframework.web.bind.annotation.RestController | ||
import java.time.LocalDateTime | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/weather-message") | ||
class WeatherMessageController( | ||
private val weatherService: WeatherService, | ||
) { | ||
@GetMapping | ||
fun getWeatherMessage(): List<WeatherMessageResponse> { | ||
val weatherMessages: List<WeatherMessage> = | ||
weatherService.createWeatherMessage(LocalDateTime.now()) | ||
return weatherMessages.map { weatherMessage -> WeatherMessageResponse.from(weatherMessage) } | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/main/kotlin/dnd11th/blooming/api/dto/weather/WeatherMessageResponse.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package dnd11th.blooming.api.dto.weather | ||
|
||
import dnd11th.blooming.api.service.weather.WeatherMessage | ||
|
||
data class WeatherMessageResponse( | ||
val status: String, | ||
val title: String, | ||
val message: List<String>, | ||
) { | ||
companion object { | ||
fun from(weatherMessages: WeatherMessage): WeatherMessageResponse { | ||
return WeatherMessageResponse( | ||
status = weatherMessages.name, | ||
title = weatherMessages.title, | ||
message = weatherMessages.message, | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
src/main/kotlin/dnd11th/blooming/api/service/weather/WeatherMessage.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package dnd11th.blooming.api.service.weather | ||
|
||
enum class WeatherMessage(val title: String, val message: List<String>) { | ||
HUMIDITY("과습주의보", listOf("과습이에요", "과습입니다.")), | ||
DRY("건조주의보", listOf("건조에요", "건조입니다")), | ||
COLD("한파주의보", listOf("한파입니다", "한파에요")), | ||
HOT("더위주의보", listOf("덥습니다", "더워요")), | ||
} |
104 changes: 104 additions & 0 deletions
104
src/main/kotlin/dnd11th/blooming/api/service/weather/WeatherService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package dnd11th.blooming.api.service.weather | ||
|
||
import dnd11th.blooming.client.dto.WeatherItem | ||
import dnd11th.blooming.client.weather.WeatherInfoClient | ||
import dnd11th.blooming.common.exception.ErrorType | ||
import dnd11th.blooming.common.exception.NotFoundException | ||
import dnd11th.blooming.domain.entity.user.User | ||
import dnd11th.blooming.domain.repository.user.UserRepository | ||
import org.springframework.beans.factory.annotation.Value | ||
import org.springframework.stereotype.Service | ||
import org.springframework.transaction.annotation.Transactional | ||
import java.time.LocalDate | ||
import java.time.LocalDateTime | ||
import java.time.LocalTime | ||
import java.time.format.DateTimeFormatter | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
class WeatherService( | ||
@Value("\${weather.serviceKey}") | ||
private val serviceKey: String, | ||
private val weatherInfoClient: WeatherInfoClient, | ||
private val userRepository: UserRepository, | ||
) { | ||
companion object { | ||
private const val HUMIDITY_KEY = "REH" | ||
private const val TEMPERATURE_KEY = "TMP" | ||
private const val MAX_HUMIDITY = 100 | ||
private const val MIN_HUMIDITY = 0 | ||
private const val MAX_TEMPERATURE = 40 | ||
private const val MIN_TEMPERATURE = -20 | ||
private const val HIGH_HUMIDITY_THRESHOLD = 80 | ||
private const val LOW_HUMIDITY_THRESHOLD = 20 | ||
private const val LOW_TEMPERATURE_THRESHOLD = 5 | ||
private const val HIGH_TEMPERATURE_THRESHOLD = 30 | ||
} | ||
|
||
fun createWeatherMessage(now: LocalDateTime): List<WeatherMessage> { | ||
val user: User = userRepository.findById(1L).orElseThrow { throw NotFoundException(ErrorType.USER_NOT_FOUND) } | ||
|
||
val weatherItems: List<WeatherItem> = | ||
weatherInfoClient.getWeatherInfo( | ||
serviceKey = serviceKey, | ||
base_date = getBaseDate(now), | ||
nx = user.nx, | ||
ny = user.ny, | ||
).toWeatherItems() | ||
|
||
return determineWeatherMessages(weatherItems) | ||
} | ||
|
||
/** | ||
* 과습 -> 그날 습도가 80 이상 넘어가는 날 있으면 HUMIDITY | ||
* 건조 -> 그날 습도가 20 이하 내려가는 시간 있으면 DRY | ||
* 한파 -> 최저 온도가 5도 이하로 내려가면 COLD | ||
* 더위 -> 최고 온도가 30도 이상 올라가는 날 있으면 HOT | ||
*/ | ||
private fun determineWeatherMessages(items: List<WeatherItem>): List<WeatherMessage> { | ||
var maxHumidity = MIN_HUMIDITY | ||
var minHumidity = MAX_HUMIDITY | ||
var maxTemperature = MIN_TEMPERATURE | ||
var minTemperature = MAX_TEMPERATURE | ||
|
||
items.forEach { item -> | ||
when (item.category) { | ||
HUMIDITY_KEY -> { | ||
val humidity = item.fcstValue.toInt() | ||
maxHumidity = maxOf(maxHumidity, humidity) | ||
minHumidity = minOf(minHumidity, humidity) | ||
} | ||
TEMPERATURE_KEY -> { | ||
val temperature = item.fcstValue.toInt() | ||
maxTemperature = maxOf(maxTemperature, temperature) | ||
minTemperature = minOf(minTemperature, temperature) | ||
} | ||
} | ||
} | ||
|
||
return mutableListOf<WeatherMessage>().apply { | ||
if (maxHumidity >= HIGH_HUMIDITY_THRESHOLD) add(WeatherMessage.HUMIDITY) | ||
if (minHumidity <= LOW_HUMIDITY_THRESHOLD) add(WeatherMessage.DRY) | ||
if (minTemperature <= LOW_TEMPERATURE_THRESHOLD) add(WeatherMessage.COLD) | ||
if (maxTemperature >= HIGH_TEMPERATURE_THRESHOLD) add(WeatherMessage.HOT) | ||
} | ||
} | ||
|
||
/** | ||
* 현재 시간이 2시 10분을 지났다면, 현재 날짜를 반환합니다. | ||
* 그렇지 않다면, 어제 날짜를 반환합니다. | ||
*/ | ||
private fun getBaseDate(now: LocalDateTime): String { | ||
val baseTime = LocalTime.of(2, 20) | ||
return if (now.toLocalTime().isAfter(baseTime)) { | ||
formatDate(now.toLocalDate()) | ||
} else { | ||
formatDate(now.toLocalDate().minusDays(1)) | ||
} | ||
} | ||
|
||
private fun formatDate(date: LocalDate): String { | ||
val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") | ||
return date.format(formatter) | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
src/main/kotlin/dnd11th/blooming/client/dto/WeatherResponse.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package dnd11th.blooming.client.dto | ||
|
||
import dnd11th.blooming.common.exception.ClientCallException | ||
import dnd11th.blooming.common.exception.ErrorType | ||
|
||
data class WeatherResponse( | ||
val response: ResponseData, | ||
) { | ||
fun toWeatherItems(): List<WeatherItem> { | ||
validate() | ||
return response.body?.items?.item ?: emptyList() | ||
} | ||
|
||
private fun validate() { | ||
if (response.header.resultCode != "00") { | ||
throw ClientCallException(ErrorType.OPEN_API_CALL_EXCEPTION) | ||
} | ||
} | ||
} | ||
|
||
data class ResponseData( | ||
val header: HeaderData, | ||
val body: BodyData?, | ||
) | ||
|
||
data class HeaderData( | ||
val resultCode: String, | ||
val resultMsg: String, | ||
) | ||
|
||
data class BodyData( | ||
val items: Items, | ||
) | ||
|
||
data class Items( | ||
val item: List<WeatherItem>, | ||
) | ||
|
||
data class WeatherItem( | ||
val baseDate: String, | ||
val baseTime: String, | ||
val category: String, | ||
val fcstDate: String, | ||
val fcstTime: String, | ||
val fcstValue: String, | ||
val nx: Int, | ||
val ny: Int, | ||
) |
2 changes: 1 addition & 1 deletion
2
...d11th/blooming/client/KakaoOauthClient.kt → ...blooming/client/kakao/KakaoOauthClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
src/main/kotlin/dnd11th/blooming/client/weather/WeatherInfoClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package dnd11th.blooming.client.weather | ||
|
||
import dnd11th.blooming.client.dto.WeatherResponse | ||
import org.springframework.cloud.openfeign.FeignClient | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.RequestParam | ||
|
||
@FeignClient( | ||
name = "WeatherInfoClient", | ||
url = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst", | ||
) | ||
interface WeatherInfoClient { | ||
companion object { | ||
const val FIXED_PAGE_NUMBER = 1 | ||
const val FIXED_NUMBER_OF_ROWS = 288 | ||
const val FIXED_DATA_TYPE = "JSON" | ||
const val FIXED_BASE_TIME = "0200" | ||
} | ||
|
||
@GetMapping | ||
fun getWeatherInfo( | ||
@RequestParam serviceKey: String, | ||
@RequestParam pageNo: Int = FIXED_PAGE_NUMBER, | ||
@RequestParam numOfRows: Int = FIXED_NUMBER_OF_ROWS, | ||
@RequestParam dataType: String = FIXED_DATA_TYPE, | ||
@RequestParam base_date: String, | ||
@RequestParam base_time: String = FIXED_BASE_TIME, | ||
@RequestParam nx: Int, | ||
@RequestParam ny: Int, | ||
): WeatherResponse | ||
} |
3 changes: 3 additions & 0 deletions
3
src/main/kotlin/dnd11th/blooming/common/exception/ClientCallException.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package dnd11th.blooming.common.exception | ||
|
||
class ClientCallException(errorType: ErrorType) : MyException(errorType) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters