refactor: ReservationTimeController 코틀린 전환 및 Swagger 코드 분리

This commit is contained in:
이상진 2025-07-18 05:09:04 +09:00
parent 9f86edfc20
commit 6d4d2c0ade
2 changed files with 112 additions and 96 deletions

View File

@ -0,0 +1,58 @@
package roomescape.reservation.docs
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.HttpServletResponse
import jakarta.validation.Valid
import jakarta.validation.constraints.NotNull
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import roomescape.auth.web.support.Admin
import roomescape.auth.web.support.LoginRequired
import roomescape.common.dto.response.CommonApiResponse
import roomescape.common.dto.response.RoomescapeApiResponse
import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success
import roomescape.common.dto.response.RoomescapeErrorResponse
import roomescape.reservation.web.ReservationTimeInfosResponse
import roomescape.reservation.web.ReservationTimeRequest
import roomescape.reservation.web.ReservationTimeResponse
import roomescape.reservation.web.ReservationTimesResponse
import java.time.LocalDate
@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.")
interface ReservationTimeAPI {
@Admin
@Operation(summary = "모든 시간 조회", tags = ["관리자 로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun getAllTimes(): ResponseEntity<CommonApiResponse<ReservationTimesResponse>>
@Admin
@Operation(summary = "시간 추가", tags = ["관리자 로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true))
fun saveTime(
@Valid @RequestBody reservationTimeRequest: ReservationTimeRequest,
): ResponseEntity<CommonApiResponse<ReservationTimeResponse>>
@Admin
@Operation(summary = "시간 삭제", tags = ["관리자 로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true))
fun removeTime(
@PathVariable id: Long
): ResponseEntity<CommonApiResponse<Unit>>
@LoginRequired
@Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = ["로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findAllAvailableReservationTimes(
@RequestParam date: LocalDate,
@RequestParam themeId: Long
): ResponseEntity<CommonApiResponse<ReservationTimeInfosResponse>>
}

View File

@ -1,108 +1,66 @@
package roomescape.reservation.web; package roomescape.reservation.web
import java.time.LocalDate; import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import org.springframework.http.HttpHeaders; import io.swagger.v3.oas.annotations.media.Content
import org.springframework.http.HttpStatus; import io.swagger.v3.oas.annotations.media.Schema
import org.springframework.web.bind.annotation.DeleteMapping; import io.swagger.v3.oas.annotations.responses.ApiResponse
import org.springframework.web.bind.annotation.GetMapping; import io.swagger.v3.oas.annotations.responses.ApiResponses
import org.springframework.web.bind.annotation.PathVariable; import jakarta.servlet.http.HttpServletResponse
import org.springframework.web.bind.annotation.PostMapping; import jakarta.validation.Valid
import org.springframework.web.bind.annotation.RequestBody; import jakarta.validation.constraints.NotNull
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.http.HttpHeaders
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.RestController; import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import io.swagger.v3.oas.annotations.Operation; import roomescape.auth.web.support.Admin
import io.swagger.v3.oas.annotations.Parameter; import roomescape.auth.web.support.LoginRequired
import io.swagger.v3.oas.annotations.media.Content; import roomescape.common.dto.response.CommonApiResponse
import io.swagger.v3.oas.annotations.media.Schema; import roomescape.common.dto.response.RoomescapeApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponse; import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success
import io.swagger.v3.oas.annotations.responses.ApiResponses; import roomescape.common.dto.response.RoomescapeErrorResponse
import io.swagger.v3.oas.annotations.tags.Tag; import roomescape.reservation.business.ReservationTimeService
import jakarta.servlet.http.HttpServletResponse; import roomescape.reservation.docs.ReservationTimeAPI
import jakarta.validation.Valid; import java.net.URI
import jakarta.validation.constraints.NotNull; import java.time.LocalDate
import roomescape.auth.web.support.Admin;
import roomescape.auth.web.support.LoginRequired;
import roomescape.common.dto.response.RoomescapeApiResponse;
import roomescape.common.dto.response.RoomescapeErrorResponse;
import roomescape.reservation.business.ReservationTimeService;
@RestController @RestController
@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") class ReservationTimeController(
public class ReservationTimeController { private val reservationTimeService: ReservationTimeService
) : ReservationTimeAPI {
private final ReservationTimeService reservationTimeService; @GetMapping("/times")
override fun getAllTimes(): ResponseEntity<CommonApiResponse<ReservationTimesResponse>> {
val response: ReservationTimesResponse = reservationTimeService.findAllTimes()
public ReservationTimeController(ReservationTimeService reservationTimeService) { return ResponseEntity.ok(CommonApiResponse(response))
this.reservationTimeService = reservationTimeService; }
}
@Admin @PostMapping("/times")
@GetMapping("/times") override fun saveTime(
@ResponseStatus(HttpStatus.OK) @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest,
@Operation(summary = "모든 시간 조회", tags = "관리자 로그인이 필요한 API") ): ResponseEntity<CommonApiResponse<ReservationTimeResponse>> {
@ApiResponses({ val response: ReservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest)
@ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)
})
public RoomescapeApiResponse<ReservationTimesResponse> getAllTimes() {
return RoomescapeApiResponse.success(reservationTimeService.findAllTimes());
}
@Admin return ResponseEntity
@PostMapping("/times") .created(URI.create("/times/${response.id}"))
@ResponseStatus(HttpStatus.CREATED) .body(CommonApiResponse(response))
@Operation(summary = "시간 추가", tags = "관리자 로그인이 필요한 API") }
@ApiResponses({
@ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true),
@ApiResponse(responseCode = "409", description = "같은 시간을 추가할 수 없습니다.",
content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class)))
})
public RoomescapeApiResponse<ReservationTimeResponse> saveTime(
@Valid @RequestBody ReservationTimeRequest reservationTimeRequest,
HttpServletResponse response
) {
ReservationTimeResponse reservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest);
response.setHeader(HttpHeaders.LOCATION, "/times/" + reservationTimeResponse.id);
return RoomescapeApiResponse.success(reservationTimeResponse); @DeleteMapping("/times/{id}")
} override fun removeTime(@PathVariable id: Long): ResponseEntity<CommonApiResponse<Unit>> {
reservationTimeService.removeTimeById(id)
@Admin return ResponseEntity.noContent().build()
@DeleteMapping("/times/{id}") }
@ResponseStatus(HttpStatus.NO_CONTENT)
@Operation(summary = "시간 삭제", tags = "관리자 로그인이 필요한 API")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true),
@ApiResponse(responseCode = "409", description = "예약된 시간은 삭제할 수 없습니다.",
content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class)))
})
public RoomescapeApiResponse<Void> removeTime(
@NotNull(message = "timeId는 null 또는 공백일 수 없습니다.") @PathVariable @Parameter(description = "삭제하고자 하는 시간의 ID값") Long id
) {
reservationTimeService.removeTimeById(id);
return RoomescapeApiResponse.success(); @GetMapping("/times/filter")
} override fun findAllAvailableReservationTimes(
@RequestParam date: LocalDate,
@RequestParam themeId: Long
): ResponseEntity<CommonApiResponse<ReservationTimeInfosResponse>> {
val response: ReservationTimeInfosResponse = reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId)
@LoginRequired return ResponseEntity.ok(CommonApiResponse(response))
@GetMapping("/times/filter") }
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = "로그인이 필요한 API")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)
})
public RoomescapeApiResponse<ReservationTimeInfosResponse> findAllAvailableReservationTimes(
@NotNull(message = "날짜는 null일 수 없습니다.")
@RequestParam
@Parameter(description = "yyyy-MM-dd 형식으로 입력해주세요.", example = "2024-06-10")
LocalDate date,
@NotNull(message = "themeId는 null일 수 없습니다.")
@RequestParam
@Parameter(description = "조회할 테마의 ID를 입력해주세요.", example = "1")
Long themeId
) {
return RoomescapeApiResponse.success(reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId));
}
} }