diff --git a/build.gradle b/build.gradle index b30e701..af0a6b9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.4.2' - id 'io.spring.dependency-management' version '1.1.7' + id 'org.springframework.boot' version '3.3.1' + id 'io.spring.dependency-management' version '1.1.5' } group = 'hyu.erica' @@ -33,6 +33,8 @@ dependencies { testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // h2 implementation 'com.h2database:h2' + // Swagger + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.4' } tasks.named('test') { diff --git a/src/main/java/hyu/erica/capstone/api/ApiResponse.java b/src/main/java/hyu/erica/capstone/api/ApiResponse.java new file mode 100644 index 0000000..cbe2267 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/ApiResponse.java @@ -0,0 +1,63 @@ +package hyu.erica.capstone.api; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import hyu.erica.capstone.api.code.BaseCode; +import hyu.erica.capstone.api.code.status.ErrorStatus; +import hyu.erica.capstone.api.code.status.SuccessStatus; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +public class ApiResponse { + + @JsonProperty("isSuccess") + private final boolean isSuccess; // 성공 여부 + private final String code; // 응답 코드 + private final String message; // 응답 메시지 + + @JsonInclude(JsonInclude.Include.NON_NULL) + private T result; // 응답 데이터 + + + @JsonProperty("isSuccess") + public boolean isSuccess() { + return isSuccess; + } + + // 성공한 경우 응답 생성 + public static ApiResponse onSuccess(SuccessStatus code, T result) { + return new ApiResponse<>(true, code.getCode(), code.getMessage(), result); + + } + + public static ApiResponse of(BaseCode code, T result) { + return new ApiResponse<>(true, code.getReasonHttpStatus().getCode(), code.getReasonHttpStatus().getMessage(), result); + } + + // 성공한 경우 응답 생성 (Void 타입 지원) + public static ApiResponse onSuccess(SuccessStatus code) { + return new ApiResponse<>(true, code.getCode(), code.getMessage(), null); + } + + // 실패한 경우 응답 생성 + public static ApiResponse onFailure(String code, String message, T data) { + return new ApiResponse<>(false, code, message, data); + } + + public ApiResponse(ErrorStatus status) { + this.isSuccess = false; + this.message = status.getMessage(); + this.code = status.getCode(); + } + + public ApiResponse(ErrorStatus status, T result) { + this.isSuccess = false; + this.message = status.getMessage(); + this.code = status.getCode(); + this.result = result; + } +} diff --git a/src/main/java/hyu/erica/capstone/api/code/BaseCode.java b/src/main/java/hyu/erica/capstone/api/code/BaseCode.java new file mode 100644 index 0000000..58b731f --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/BaseCode.java @@ -0,0 +1,9 @@ +package hyu.erica.capstone.api.code; + + +public interface BaseCode { + + public ReasonDTO getReason(); + + public ReasonDTO getReasonHttpStatus(); +} diff --git a/src/main/java/hyu/erica/capstone/api/code/BaseErrorCode.java b/src/main/java/hyu/erica/capstone/api/code/BaseErrorCode.java new file mode 100644 index 0000000..6ceecfa --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/BaseErrorCode.java @@ -0,0 +1,8 @@ +package hyu.erica.capstone.api.code; + +public interface BaseErrorCode { + + public ErrorReasonDTO getReason(); + + public ErrorReasonDTO getReasonHttpStatus(); +} diff --git a/src/main/java/hyu/erica/capstone/api/code/ErrorReasonDTO.java b/src/main/java/hyu/erica/capstone/api/code/ErrorReasonDTO.java new file mode 100644 index 0000000..c79342e --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/ErrorReasonDTO.java @@ -0,0 +1,20 @@ +package hyu.erica.capstone.api.code; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@Builder +public class ErrorReasonDTO { + + private HttpStatus httpStatus; + + private final boolean isSuccess; + private final String code; + private final String message; + + public boolean getIsSuccess() { + return isSuccess; + } +} diff --git a/src/main/java/hyu/erica/capstone/api/code/ReasonDTO.java b/src/main/java/hyu/erica/capstone/api/code/ReasonDTO.java new file mode 100644 index 0000000..57f1149 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/ReasonDTO.java @@ -0,0 +1,20 @@ +package hyu.erica.capstone.api.code; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@Builder +public class ReasonDTO { + + private HttpStatus httpStatus; + + private final boolean isSuccess; + private final String code; + private final String message; + + public boolean getIsSuccess() { + return isSuccess; + } +} diff --git a/src/main/java/hyu/erica/capstone/api/code/status/ErrorStatus.java b/src/main/java/hyu/erica/capstone/api/code/status/ErrorStatus.java new file mode 100644 index 0000000..1d1da6b --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/status/ErrorStatus.java @@ -0,0 +1,60 @@ +package hyu.erica.capstone.api.code.status; + +import hyu.erica.capstone.api.code.BaseErrorCode; +import hyu.erica.capstone.api.code.ErrorReasonDTO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorStatus implements BaseErrorCode { + + //공통 에러 + _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 내부 오류 발생"), + _BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON4000", "잘못된 요청입니다."), + _UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "COMMON4001", "인증되지 않은 요청입니다."), + _FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON4002", "접근이 거부되었습니다."), + _BAD_VALUE_REQUEST(HttpStatus.BAD_REQUEST, "COMMON4003", "올바르지 않은 값을 입력 하셨습니다."), + _INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "COMMON4004", "입력값이 유효하지 않습니다."), + _EMPTY_JWT(HttpStatus.BAD_REQUEST, "COMMON4005", "JWT 토큰이 비어있습니다."), + _INVALID_JWT(HttpStatus.BAD_REQUEST, "COMMON4006", "유효하지 않은 JWT token입니다."), + _EXPIRED_JWT(HttpStatus.BAD_REQUEST, "COMMON4007", "만료된 JWT token입니다."), + _UNSUPPORTED_JWT(HttpStatus.BAD_REQUEST, "COMMON4008", "지원되지 않는 JWT token입니다."), + _INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "COMMON4009", "유효하지 않은 리프레시 토큰입니다."), + _EXPIRED_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "COMMON4010", "만료된 리프레시 토큰입니다."), + _NULL_VALUE(HttpStatus.BAD_REQUEST, "COMMON4011", "값이 입력되지 않았습니다."), + _VALUE_RANGE_EXCEEDED(HttpStatus.BAD_REQUEST, "COMMON4012", "값이 지정된 범위를 초과합니다."), + _TERMS_NOT_AGREED(HttpStatus.FORBIDDEN, "COMMON4013", "이용 약관이 동의되지 않았습니다."), + _MEMBER_EMAIL_EXIST(HttpStatus.BAD_REQUEST, "COMMON4014", "이미 가입 된 이메일입니다. 다른 로그인 방식을 이용해주세요."), + _RSA_ERROR(HttpStatus.BAD_REQUEST, "COMMON4015", "RSA 에러가 발생했습니다."), + + + ; + + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDTO getReason() { + return ErrorReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(false) + .build() + ; + } + + @Override + public ErrorReasonDTO getReasonHttpStatus() { + return ErrorReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(false) + .httpStatus(httpStatus) + .build() + ; + } +} diff --git a/src/main/java/hyu/erica/capstone/api/code/status/SuccessStatus.java b/src/main/java/hyu/erica/capstone/api/code/status/SuccessStatus.java new file mode 100644 index 0000000..b6f1efd --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/code/status/SuccessStatus.java @@ -0,0 +1,42 @@ +package hyu.erica.capstone.api.code.status; + +import hyu.erica.capstone.api.code.BaseCode; +import hyu.erica.capstone.api.code.ReasonDTO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum SuccessStatus implements BaseCode { + //공통 응답 + _OK(HttpStatus.OK, "COMMON200", "OK"), + _CREATED(HttpStatus.CREATED, "COMMON201", "생성 완료"), + _ACCEPTED(HttpStatus.ACCEPTED, "COMMON202", "요청 수락됨"), + _NO_CONTENT(HttpStatus.NO_CONTENT, "COMMON204", "콘텐츠 없음"), + ; + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ReasonDTO getReason() { + return ReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(true) + .build(); + } + + @Override + public ReasonDTO getReasonHttpStatus() { + return ReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(true) + .httpStatus(httpStatus) + .build() + ; + } +} diff --git a/src/main/java/hyu/erica/capstone/api/exception/ExceptionAdvice.java b/src/main/java/hyu/erica/capstone/api/exception/ExceptionAdvice.java new file mode 100644 index 0000000..9c80367 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/exception/ExceptionAdvice.java @@ -0,0 +1,45 @@ +package hyu.erica.capstone.api.exception; + + +import hyu.erica.capstone.api.ApiResponse; +import hyu.erica.capstone.api.code.status.ErrorStatus; +import jakarta.validation.ConstraintViolationException; +import java.util.List; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + + +@Slf4j +@RestControllerAdvice +public class ExceptionAdvice { + + /** + * GeneralException 처리 + * @param exception GeneralException + * @return ApiResponse - GeneralException + */ + @ExceptionHandler(GeneralException.class) + public ApiResponse baseExceptionHandle(GeneralException exception) { + log.warn("BaseException. error message: {}", exception.getMessage()); + return new ApiResponse<>(exception.getStatus()); + } + + /** + * Exception 처리 + * @param exception Exception + * @return ApiResponse - INTERNAL_SERVER_ERROR + */ + @ExceptionHandler(Exception.class) + public ApiResponse exceptionHandle(Exception exception) { + log.error("Exception has occurred. {}", exception); + return new ApiResponse<>(ErrorStatus._INTERNAL_SERVER_ERROR); + } + + +} \ No newline at end of file diff --git a/src/main/java/hyu/erica/capstone/api/exception/GeneralException.java b/src/main/java/hyu/erica/capstone/api/exception/GeneralException.java new file mode 100644 index 0000000..7b8ef83 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/api/exception/GeneralException.java @@ -0,0 +1,15 @@ +package hyu.erica.capstone.api.exception; + +import hyu.erica.capstone.api.code.status.ErrorStatus; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class GeneralException extends RuntimeException { + private ErrorStatus status; + public GeneralException(ErrorStatus status) { + super(status.getCode()); + this.status = status; + } +} diff --git a/src/main/java/hyu/erica/capstone/config/SwaggerConfig.java b/src/main/java/hyu/erica/capstone/config/SwaggerConfig.java new file mode 100644 index 0000000..7ce739f --- /dev/null +++ b/src/main/java/hyu/erica/capstone/config/SwaggerConfig.java @@ -0,0 +1,39 @@ +package hyu.erica.capstone.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI SpotAPI() { + Info info = new Info() + .title("Capstone Project API") + .description("Capstone Project API 명세서"); + + String jwtSchemeName = "accessToken"; + + SecurityRequirement securityRequirement = new SecurityRequirement() + .addList(jwtSchemeName); + + Components components = new Components() + .addSecuritySchemes(jwtSchemeName, new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("Bearer") + .bearerFormat("JWT")); + + return new OpenAPI() + .openapi("3.0.1") // 🔥 OpenAPI 버전 명시 추가! + .addServersItem(new Server().url("/")) + .info(info) + .addSecurityItem(securityRequirement) + .components(components); + } +} \ No newline at end of file diff --git a/src/main/java/hyu/erica/capstone/domain/enums/PhoneService.java b/src/main/java/hyu/erica/capstone/domain/enums/PhoneService.java new file mode 100644 index 0000000..bd47aeb --- /dev/null +++ b/src/main/java/hyu/erica/capstone/domain/enums/PhoneService.java @@ -0,0 +1,9 @@ +package hyu.erica.capstone.domain.enums; + +public enum PhoneService { + SKT, + KT, + LGT; + + +} diff --git a/src/main/java/hyu/erica/capstone/controller/DefaultController.java b/src/main/java/hyu/erica/capstone/web/controller/DefaultController.java similarity index 62% rename from src/main/java/hyu/erica/capstone/controller/DefaultController.java rename to src/main/java/hyu/erica/capstone/web/controller/DefaultController.java index 31412f6..6ff4aa3 100644 --- a/src/main/java/hyu/erica/capstone/controller/DefaultController.java +++ b/src/main/java/hyu/erica/capstone/web/controller/DefaultController.java @@ -1,11 +1,13 @@ -package hyu.erica.capstone.controller; +package hyu.erica.capstone.web.controller; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DefaultController { + @Operation(summary = "Health Check", description = "서버 상태 확인") @GetMapping("/health-check") public String healthCheck() { return "Hello, World!"; diff --git a/src/main/java/hyu/erica/capstone/web/controller/PlanController.java b/src/main/java/hyu/erica/capstone/web/controller/PlanController.java new file mode 100644 index 0000000..85634b3 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/controller/PlanController.java @@ -0,0 +1,69 @@ +package hyu.erica.capstone.web.controller; + + +import hyu.erica.capstone.api.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Plan", description = "여행 계획 관련 API") +@CrossOrigin +@RestController +@RequestMapping("/api/plans") +public class PlanController { + + // 일정 제공 + @GetMapping("/{planId}") + public ApiResponse getPlan() { + // 일정 제공 + return null; + } + + // Result 화면 위한 API + @GetMapping("/result") + public ApiResponse getResult() { + // Result 화면 위한 API + return null; + } + + // 채팅 입력 -> AI API 호출 + @PostMapping("/chat") + public ApiResponse chat() { + // 채팅 입력 -> AI API 호출 + return null; + } + + // 일정 편집 (순서 변경) + @PutMapping("") + public ApiResponse editPlan() { + // 일정 편집 (순서 변경) + return null; + } + + + // 일정 편집 (삭제) + @DeleteMapping() + public ApiResponse deletePlan() { + // 일정 편집 (삭제) + return null; + } + + // 일정 편집 (추가) + @PostMapping() + public ApiResponse addPlan() { + // 일정 편집 (추가) + return null; + } + + // 최종 저장 + @PostMapping("/final") + public ApiResponse finalSave() { + // 최종 저장 + return null; + } +} diff --git a/src/main/java/hyu/erica/capstone/web/controller/TripPlanController.java b/src/main/java/hyu/erica/capstone/web/controller/TripPlanController.java new file mode 100644 index 0000000..adae712 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/controller/TripPlanController.java @@ -0,0 +1,287 @@ +package hyu.erica.capstone.web.controller; + +import hyu.erica.capstone.api.ApiResponse; +import hyu.erica.capstone.web.dto.trip.request.AdditionalInfoRequestDTO; +import hyu.erica.capstone.web.dto.trip.request.PreferActivitiesRequestDTO; +import hyu.erica.capstone.web.dto.trip.request.SaveAttractionRequestDTO; +import hyu.erica.capstone.web.dto.trip.request.SaveRestaurantRequestDTO; +import hyu.erica.capstone.web.dto.trip.request.TripPeriodRequestDTO; +import hyu.erica.capstone.web.dto.trip.response.AdditionalInfoResponseDTO; +import hyu.erica.capstone.web.dto.trip.response.PreferActivitiesResponseDTO; +import hyu.erica.capstone.web.dto.trip.response.TripPeriodResponseDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.CrossOrigin; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +@CrossOrigin +@RestController +@RequestMapping("/api/trip-plans/{tripPlansId}") +public class TripPlanController { + + // 여행 기간 입력 + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "여행 기간 입력", description = """ + ### 여행 기간을 입력합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + + ### Request Body + - startDate: 여행 시작 날짜 + - startHour: 여행 시작 시간 + - endDate: 여행 종료 날짜 + - endHour: 여행 종료 시간 + """) + @PostMapping("/period") + public ApiResponse inputPeriod( + @PathVariable Long tripPlansId, + @RequestBody TripPeriodRequestDTO request) { + // 여행 기간 입력 + return null; + } + + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "여행 기간 조회", description = """ + ### 여행 기간을 조회합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + @GetMapping("/period") + public ApiResponse getPeriod( + @PathVariable Long tripPlansId) { + // 여행 기간 입력 + return null; + } + + // 선호 활동 입력 + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "선호 활동 입력", description = """ + ### 선호 활동을 입력합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + + ### Request Body + - activities: 선호 활동 (String) + """) + @PostMapping("/activities") + public ApiResponse inputActivities( + @PathVariable Long tripPlansId, + @RequestBody PreferActivitiesRequestDTO request) { + // 선호 활동 입력 + return null; + } + + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "선호 활동 조회", description = """ + ### 선호 활동을 조회합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + @GetMapping("/activities") + public ApiResponse getActivities( + @PathVariable Long tripPlansId) { + // 선호 활동 입력 + return null; + } + + // 추가적인 요구 사항 입력 + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "추가적인 요구 사항 입력", description = """ + ### 추가적인 요구 사항을 입력합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + + ### Request Body + - additionalInfo: 추가적인 요구 사항 (String) + """) + @PostMapping("/additional") + public ApiResponse inputAdditional( + @PathVariable Long tripPlansId, + @RequestBody AdditionalInfoRequestDTO request) { + // 추가적인 요구 사항 입력 + return null; + } + + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "추가적인 요구 사항 조회", description = """ + ### 추가적인 요구 사항을 조회합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + @GetMapping("/additional") + public ApiResponse getAdditional( + @PathVariable Long tripPlansId) { + // 추가적인 요구 사항 입력 + return null; + } + + @Tag(name = "Trip", description = "여행 관련 API") + @Operation(summary = "일정 제공", description = """ + ### 최종적으로 입력한 정보를 바탕으로 일정을 제공합니다. + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + // 최종 입력 ( AI API 호출) + @GetMapping("/final") + public ApiResponse finalInput( + @PathVariable Long tripPlansId) { + // 최종 입력 ( AI API 호출) + return null; + } + + /* ------------------------------------------------------------------------------------------------------ */ + + // 선택지 확인 (여행지) + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "선택지 (여행지) 확인", description = """ + ### 선택지 확인 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + @GetMapping("/attractions") + public ApiResponse checkPlaces( + @PathVariable Long tripPlansId) { + // 선택지 확인 (여행지) + return null; + } + + // 선택지 상세 보기 (여행지) + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "선택지 (여행지) 상세 보기", description = """ + ### 선택지 상세 보기 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + - attractionId: 여행지 ID + """) + @GetMapping("/attractions/{attractionId}") + public ApiResponse viewPlaceDetail( + @PathVariable Long tripPlansId, + @PathVariable Long attractionId) { + // 선택지 상세 보기 (여행지) + return null; + } + + // 여행지 키워드 검색 + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "여행지 키워드 검색", description = """ + ### 여행지 키워드 검색 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + + ### Request Param + - keyword: 검색 키워드 + """) + @GetMapping("/attractions/search") + public ApiResponse searchPlace( + @PathVariable Long tripPlansId, + @RequestParam String keyword) { + // 여행지 키워드 검색 + return null; + } + + // 여행지 최종 선택 + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "여행지 최종 선택", description = """ + ### 여행지 최종 선택 API + + ### Path Variables + - tripPlansIds: 여행 계획 ID (List) + + """) + @PostMapping("/attractions/final") + public ApiResponse finalPlace( + @PathVariable Long tripPlansId, + @RequestBody SaveAttractionRequestDTO request) { + // 여행지 최종 선택 + return null; + } + + // 선택지 확인 (음식점) + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "선택지 (음식점) 확인", description = """ + ### 선택지 확인 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + """) + @GetMapping("/restaurants") + public ApiResponse checkRestaurants( + @PathVariable Long tripPlansId) { + // 선택지 확인 (음식점) + return null; + } + + + // 선택지 상세 보기 (음식점) + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "선택지 (음식점) 상세 보기", description = """ + ### 선택지 상세 보기 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + - restaurantId: 음식점 ID + """) + @GetMapping("/restaurants/{restaurantId}") + public ApiResponse viewRestaurantDetail( + @PathVariable Long tripPlansId, + @PathVariable Long restaurantId) { + // 선택지 상세 보기 (음식점) + return null; + } + + + // 음식점 키워드 검색 + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "음식점 키워드 검색", description = """ + ### 음식점 키워드 검색 API + + ### Path Variables + - tripPlansId: 여행 계획 ID + + ### Request Param + - keyword: 검색 키워드 + """) + @GetMapping("/restaurants/search") + public ApiResponse searchRestaurant( + @PathVariable Long tripPlansId, + @RequestParam String keyword) { + // 음식점 키워드 검색 + return null; + } + + + // 음식점 최종 선택 + @Tag(name = "선택지 확인", description = "선택지 확인 API") + @Operation(summary = "음식점 최종 선택", description = """ + ### 음식점 최종 선택 API + + ### Path Variables + - tripPlansIds: 여행 계획 ID (List) + """) + @PostMapping("/restaurants/final") + public ApiResponse finalRestaurant( + @PathVariable Long tripPlansId, + @RequestBody SaveRestaurantRequestDTO request) { + // 음식점 최종 선택 + return null; + } + + +} diff --git a/src/main/java/hyu/erica/capstone/web/controller/UserController.java b/src/main/java/hyu/erica/capstone/web/controller/UserController.java new file mode 100644 index 0000000..fea1756 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/controller/UserController.java @@ -0,0 +1,100 @@ +package hyu.erica.capstone.web.controller; + +import hyu.erica.capstone.api.ApiResponse; +import hyu.erica.capstone.web.dto.user.request.SignInRequestDTO; +import hyu.erica.capstone.web.dto.user.request.SignUpRequestDTO; +import hyu.erica.capstone.web.dto.user.request.UpdateInfoRequestDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "User", description = "사용자 관련 API") +@CrossOrigin +@RestController +@RequestMapping("/api/users") +public class UserController { + + // 회원 가입 + @Operation(summary = "회원 가입", description = """ + ### 회원 가입을 진행합니다. + + ### Request Body + - email: 이메일 + - password: 비밀번호 + - nickname: 닉네임 + - phoneNumber: 전화번호 + - birthDate: 생년월일 + - phoneService: 통신사 + """) + @PostMapping("/sign-up") + public ApiResponse signUp( + @RequestBody SignUpRequestDTO request + ) { + return null; + } + + // 로그인 + @Operation(summary = "로그인", description = """ + ### 로그인을 진행합니다. + + ### Request Body + - email: 이메일 + - password: 비밀번호 + """) + @PostMapping("/login") + public ApiResponse login(@RequestBody SignInRequestDTO request) { + return null; + } + + // 토큰 재발급 + @Operation(summary = "토큰 재발급", description = """ + ### 토큰을 재발급합니다. refresh-token을 이용하여 access-token을 재발급합니다. + + ### Request Header + - Authorization: Bearer {refresh-token} + """) + @PostMapping("/reissue-token") + public ApiResponse reissueToken() { + return null; + } + + // 로그아웃 + @Operation(summary = "로그아웃", description = """ + ### 로그아웃을 진행합니다. + """) + @PostMapping("/logout") + public ApiResponse logout() { + return null; + } + + // 마이페이지 + @Operation(summary = "마이페이지", description = """ + ### 마이페이지를 조회합니다. + """) + @GetMapping("/my-page") + public ApiResponse myPage() { + return null; + } + + + // 프로필 수정 + @Operation(summary = "프로필 수정", description = """ + ### 프로필을 수정합니다. + + ### Request Body + - nickname: 닉네임 + - profileImage: 프로필 이미지 + - phoneNumber: 전화번호 + """) + @PostMapping("/edit-profile") + public ApiResponse editProfile( + @RequestBody UpdateInfoRequestDTO request + ) { + return null; + } +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/request/AdditionalInfoRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/request/AdditionalInfoRequestDTO.java new file mode 100644 index 0000000..6a5ff54 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/request/AdditionalInfoRequestDTO.java @@ -0,0 +1,4 @@ +package hyu.erica.capstone.web.dto.trip.request; + +public record AdditionalInfoRequestDTO(String additionalInfo) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/request/PreferActivitiesRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/request/PreferActivitiesRequestDTO.java new file mode 100644 index 0000000..96498f5 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/request/PreferActivitiesRequestDTO.java @@ -0,0 +1,4 @@ +package hyu.erica.capstone.web.dto.trip.request; + +public record PreferActivitiesRequestDTO(String preferActivities) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveAttractionRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveAttractionRequestDTO.java new file mode 100644 index 0000000..254b3b2 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveAttractionRequestDTO.java @@ -0,0 +1,6 @@ +package hyu.erica.capstone.web.dto.trip.request; + +import java.util.List; + +public record SaveAttractionRequestDTO(List attractionIds) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveRestaurantRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveRestaurantRequestDTO.java new file mode 100644 index 0000000..e3e1a1f --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/request/SaveRestaurantRequestDTO.java @@ -0,0 +1,6 @@ +package hyu.erica.capstone.web.dto.trip.request; + +import java.util.List; + +public record SaveRestaurantRequestDTO (List restaurantIds) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/request/TripPeriodRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/request/TripPeriodRequestDTO.java new file mode 100644 index 0000000..5235187 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/request/TripPeriodRequestDTO.java @@ -0,0 +1,6 @@ +package hyu.erica.capstone.web.dto.trip.request; + +import java.time.LocalDate; + +public record TripPeriodRequestDTO(LocalDate startDate, Integer startHour, LocalDate endDate, Integer endHour) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/response/AdditionalInfoResponseDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AdditionalInfoResponseDTO.java new file mode 100644 index 0000000..f9d6f39 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AdditionalInfoResponseDTO.java @@ -0,0 +1,7 @@ +package hyu.erica.capstone.web.dto.trip.response; + +public record AdditionalInfoResponseDTO (String additionalInfo){ + public static AdditionalInfoResponseDTO of(String additionalInfo) { + return new AdditionalInfoResponseDTO(additionalInfo); + } +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionListResponseDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionListResponseDTO.java new file mode 100644 index 0000000..39c2c90 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionListResponseDTO.java @@ -0,0 +1,15 @@ +package hyu.erica.capstone.web.dto.trip.response; + +import hyu.erica.capstone.domain.Attraction; +import java.util.List; + +public record AttractionListResponseDTO(List attractions, Integer totalAttractions) { + public static AttractionListResponseDTO of(List attractions) { + return new AttractionListResponseDTO( + attractions.stream().map(AttractionResponseDTO::of).toList(), + attractions.size() + ); + } + + +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionResponseDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionResponseDTO.java new file mode 100644 index 0000000..14ef3e6 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/response/AttractionResponseDTO.java @@ -0,0 +1,9 @@ +package hyu.erica.capstone.web.dto.trip.response; + +import hyu.erica.capstone.domain.Attraction; + +public record AttractionResponseDTO(String image, String name) { + public static AttractionResponseDTO of(Attraction attraction) { + return new AttractionResponseDTO(new String(), new String()); + } +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/response/PreferActivitiesResponseDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/response/PreferActivitiesResponseDTO.java new file mode 100644 index 0000000..7817b82 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/response/PreferActivitiesResponseDTO.java @@ -0,0 +1,7 @@ +package hyu.erica.capstone.web.dto.trip.response; + +public record PreferActivitiesResponseDTO (String preferActivities) { + public static PreferActivitiesResponseDTO of(String preferActivities) { + return new PreferActivitiesResponseDTO(preferActivities); + } +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/trip/response/TripPeriodResponseDTO.java b/src/main/java/hyu/erica/capstone/web/dto/trip/response/TripPeriodResponseDTO.java new file mode 100644 index 0000000..4dd09be --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/trip/response/TripPeriodResponseDTO.java @@ -0,0 +1,9 @@ +package hyu.erica.capstone.web.dto.trip.response; + +import java.time.LocalDate; + +public record TripPeriodResponseDTO(LocalDate startDate, Integer startHour, LocalDate endDate, Integer endHour) { + public static TripPeriodResponseDTO of(LocalDate startDate, Integer startHour, LocalDate endDate, Integer endHour) { + return new TripPeriodResponseDTO(startDate, startHour, endDate, endHour); + } +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/user/request/SignInRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/user/request/SignInRequestDTO.java new file mode 100644 index 0000000..9f27c8c --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/user/request/SignInRequestDTO.java @@ -0,0 +1,4 @@ +package hyu.erica.capstone.web.dto.user.request; + +public record SignInRequestDTO (String email, String password) { +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/user/request/SignUpRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/user/request/SignUpRequestDTO.java new file mode 100644 index 0000000..5952ff4 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/user/request/SignUpRequestDTO.java @@ -0,0 +1,9 @@ +package hyu.erica.capstone.web.dto.user.request; + +import hyu.erica.capstone.domain.enums.PhoneService; +import java.time.LocalDate; + +public record SignUpRequestDTO (String email, String password, String name, String phoneNumber, LocalDate birthDate, + PhoneService phoneService) { + +} diff --git a/src/main/java/hyu/erica/capstone/web/dto/user/request/UpdateInfoRequestDTO.java b/src/main/java/hyu/erica/capstone/web/dto/user/request/UpdateInfoRequestDTO.java new file mode 100644 index 0000000..c2e5f65 --- /dev/null +++ b/src/main/java/hyu/erica/capstone/web/dto/user/request/UpdateInfoRequestDTO.java @@ -0,0 +1,4 @@ +package hyu.erica.capstone.web.dto.user.request; + +public record UpdateInfoRequestDTO (String nickname, String phoneNumber, String profileImage) { +}