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

[BLOOM-002] 식물 저장, 전체 조회, 상세 조회 API 개발 #5

Merged
merged 16 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 15 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dnd11th.blooming.api.controller

import dnd11th.blooming.api.dto.PlantDetailResponse
import dnd11th.blooming.api.dto.PlantResponse
import dnd11th.blooming.api.dto.PlantSaveRequest
import dnd11th.blooming.api.dto.PlantSaveResponse
import dnd11th.blooming.api.service.PlantService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

@RestController
class PlantController(
private val plantService: PlantService,
) {
@PostMapping("/plant")
fun createPlant(
@RequestBody request: PlantSaveRequest,
): PlantSaveResponse = plantService.savePlant(request)

@GetMapping("/plants")
fun getAllPlant(): List<PlantResponse> = plantService.findAllPlant()

@GetMapping("/plant/{id}")
fun getPlantDetail(
@PathVariable id: Long,
): PlantDetailResponse = plantService.findPlantDetail(id)
}
22 changes: 22 additions & 0 deletions src/main/kotlin/dnd11th/blooming/api/dto/PlantDetailResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dnd11th.blooming.api.dto

import dnd11th.blooming.domain.entity.Plant
import java.time.LocalDate

data class PlantDetailResponse(
val name: String,
val scientificName: String,
val startDate: LocalDate,
val lastWatedDate: LocalDate,
// TODO: 식물에 대한 상세 정보 추가 필요
) {
companion object {
fun from(plant: Plant): PlantDetailResponse =
PlantDetailResponse(
name = plant.name,
scientificName = plant.scientificName,
startDate = plant.startDate,
lastWatedDate = plant.lastWateredDate,
)
}
}
18 changes: 18 additions & 0 deletions src/main/kotlin/dnd11th/blooming/api/dto/PlantResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package dnd11th.blooming.api.dto

import dnd11th.blooming.domain.entity.Plant

data class PlantResponse(
val id: Long,
val name: String,
val scientificName: String,
) {
companion object {
fun from(plant: Plant): PlantResponse =
PlantResponse(
id = plant.id,
name = plant.name,
scientificName = plant.scientificName,
)
}
}
12 changes: 12 additions & 0 deletions src/main/kotlin/dnd11th/blooming/api/dto/PlantSaveRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dnd11th.blooming.api.dto

import java.time.LocalDate

data class PlantSaveRequest(
val scientificName: String,
val name: String,
val startDate: LocalDate,
val lastWateredDate: LocalDate,
val waterAlarm: Boolean,
val nutrientsAlarm: Boolean,
)
14 changes: 14 additions & 0 deletions src/main/kotlin/dnd11th/blooming/api/dto/PlantSaveResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dnd11th.blooming.api.dto

import dnd11th.blooming.domain.entity.Plant

class PlantSaveResponse(
val id: Long,
) {
companion object {
fun from(plant: Plant): PlantSaveResponse =
PlantSaveResponse(
id = plant.id,
)
}
}
53 changes: 53 additions & 0 deletions src/main/kotlin/dnd11th/blooming/api/service/PlantService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dnd11th.blooming.api.service

import dnd11th.blooming.api.dto.PlantDetailResponse
import dnd11th.blooming.api.dto.PlantResponse
import dnd11th.blooming.api.dto.PlantSaveRequest
import dnd11th.blooming.api.dto.PlantSaveResponse
import dnd11th.blooming.common.exception.InvalidDateException
import dnd11th.blooming.common.exception.PlantNotFoundException
import dnd11th.blooming.domain.entity.Plant
import dnd11th.blooming.domain.repository.PlantRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate

@Service
@Transactional
Dompoo marked this conversation as resolved.
Show resolved Hide resolved
class PlantService(
private val plantRepository: PlantRepository,
) {
fun savePlant(request: PlantSaveRequest): PlantSaveResponse {
if (request.lastWateredDate.isAfter(LocalDate.now()) || request.startDate.isAfter(LocalDate.now())) {
throw InvalidDateException()
}

val plant =
Plant(
scientificName = request.scientificName,
name = request.name,
startDate = request.startDate,
lastWateredDate = request.lastWateredDate,
waterAlarm = request.waterAlarm,
nutrientsAlarm = request.nutrientsAlarm,
)
return PlantSaveResponse.from(plantRepository.save(plant))
}

fun findAllPlant(): List<PlantResponse> {
val plantList = plantRepository.findAll()

return plantList.stream().map { plant ->
PlantResponse.from(plant)
}.toList()
}

fun findPlantDetail(id: Long): PlantDetailResponse {
val plant =
plantRepository.findByIdOrNull(id)
?: throw PlantNotFoundException()

return PlantDetailResponse.from(plant)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dnd11th.blooming.common.exception

import com.fasterxml.jackson.annotation.JsonInclude

@JsonInclude(JsonInclude.Include.NON_NULL)
data class ErrorResponse(
val code: ExceptionCode,
val message: String,
val field: List<String>? = null,
) {
companion object {
fun from(exception: MyException): ErrorResponse =
ErrorResponse(
code = exception.code,
message = exception.message ?: "",
field = exception.field?.takeIf { it.isNotEmpty() },
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dnd11th.blooming.common.exception

enum class ExceptionCode {
INVALID_REQUEST,
INVALID_DATE,
NOT_FOUND_PLANT_ID,
}
Dompoo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dnd11th.blooming.common.exception

import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice

@RestControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(MyException::class)
fun handleMyException(exception: MyException): ResponseEntity<ErrorResponse> {
return ResponseEntity
.status(exception.status)
.body(ErrorResponse.from(exception))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dnd11th.blooming.common.exception

import org.springframework.http.HttpStatus

class InvalidDateException(
message: String = "올바르지 않은 날짜입니다.",
) : MyException(statusCode, code, message) {
companion object {
val statusCode = HttpStatus.BAD_REQUEST
val code = ExceptionCode.INVALID_DATE
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dnd11th.blooming.common.exception

import org.springframework.http.HttpStatus

abstract class MyException(
val status: HttpStatus,
val code: ExceptionCode,
message: String,
val field: List<String>? = null,
) : RuntimeException(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dnd11th.blooming.common.exception

import org.springframework.http.HttpStatus

class PlantNotFoundException(
message: String = "존재하지 않는 식물입니다.",
) : MyException(statusCode, code, message) {
companion object {
val statusCode = HttpStatus.NOT_FOUND
val code = ExceptionCode.NOT_FOUND_PLANT_ID
}
}
28 changes: 28 additions & 0 deletions src/main/kotlin/dnd11th/blooming/domain/entity/Plant.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dnd11th.blooming.domain.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import java.time.LocalDate

@Entity
class Plant(
@Column(nullable = false)
var scientificName: String,
@Column
var name: String,
@Column
var startDate: LocalDate = LocalDate.now(),
@Column
var lastWateredDate: LocalDate = LocalDate.now(),
@Column
var waterAlarm: Boolean = true,
@Column
var nutrientsAlarm: Boolean = true,
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dnd11th.blooming.domain.repository

import dnd11th.blooming.domain.entity.Plant
import org.springframework.data.jpa.repository.JpaRepository

interface PlantRepository : JpaRepository<Plant, Long>
Loading
Loading