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 org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
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 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;
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 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.business.ReservationTimeService
import roomescape.reservation.docs.ReservationTimeAPI
import java.net.URI
import java.time.LocalDate
@RestController
@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.")
public class ReservationTimeController {
class ReservationTimeController(
private val reservationTimeService: ReservationTimeService
) : ReservationTimeAPI {
private final ReservationTimeService reservationTimeService;
public ReservationTimeController(ReservationTimeService reservationTimeService) {
this.reservationTimeService = reservationTimeService;
}
@Admin
@GetMapping("/times")
@ResponseStatus(HttpStatus.OK)
@Operation(summary = "모든 시간 조회", tags = "관리자 로그인이 필요한 API")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)
})
public RoomescapeApiResponse<ReservationTimesResponse> getAllTimes() {
return RoomescapeApiResponse.success(reservationTimeService.findAllTimes());
override fun getAllTimes(): ResponseEntity<CommonApiResponse<ReservationTimesResponse>> {
val response: ReservationTimesResponse = reservationTimeService.findAllTimes()
return ResponseEntity.ok(CommonApiResponse(response))
}
@Admin
@PostMapping("/times")
@ResponseStatus(HttpStatus.CREATED)
@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);
override fun saveTime(
@Valid @RequestBody reservationTimeRequest: ReservationTimeRequest,
): ResponseEntity<CommonApiResponse<ReservationTimeResponse>> {
val response: ReservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest)
return RoomescapeApiResponse.success(reservationTimeResponse);
return ResponseEntity
.created(URI.create("/times/${response.id}"))
.body(CommonApiResponse(response))
}
@Admin
@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);
override fun removeTime(@PathVariable id: Long): ResponseEntity<CommonApiResponse<Unit>> {
reservationTimeService.removeTimeById(id)
return RoomescapeApiResponse.success();
return ResponseEntity.noContent().build()
}
@LoginRequired
@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));
override fun findAllAvailableReservationTimes(
@RequestParam date: LocalDate,
@RequestParam themeId: Long
): ResponseEntity<CommonApiResponse<ReservationTimeInfosResponse>> {
val response: ReservationTimeInfosResponse = reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId)
return ResponseEntity.ok(CommonApiResponse(response))
}
}