diff --git a/be/src/main/java/yeonba/be/config/WebConfig.java b/be/src/main/java/yeonba/be/config/WebConfig.java index 2d996c0a..6cea811a 100644 --- a/be/src/main/java/yeonba/be/config/WebConfig.java +++ b/be/src/main/java/yeonba/be/config/WebConfig.java @@ -22,8 +22,6 @@ public void addInterceptors(InterceptorRegistry registry) { "/error") .excludePathPatterns( "/users/join/**", - "/users/email-inquiry/**", - "/users/pw-inquiry", "/users/login", "/users/refresh"); } diff --git a/be/src/main/java/yeonba/be/exception/ExceptionAdvice.java b/be/src/main/java/yeonba/be/exception/ExceptionAdvice.java index 3e354ab3..ce3f840a 100644 --- a/be/src/main/java/yeonba/be/exception/ExceptionAdvice.java +++ b/be/src/main/java/yeonba/be/exception/ExceptionAdvice.java @@ -1,8 +1,6 @@ package yeonba.be.exception; import jakarta.servlet.http.HttpServletRequest; -import jakarta.validation.ConstraintViolation; -import jakarta.validation.ConstraintViolationException; import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; @@ -21,118 +19,82 @@ @RestControllerAdvice(annotations = {RestController.class}) public class ExceptionAdvice extends ResponseEntityExceptionHandler { - @ExceptionHandler(value = GeneralException.class) - public ResponseEntity handleGeneralException( - GeneralException exception, - HttpServletRequest request) { - - return handleExceptionInternal( - exception, - request); - } - - @ExceptionHandler(value = ConstraintViolationException.class) - public ResponseEntity handleConstraintViolationException( - ConstraintViolationException exception, - WebRequest request) { - - String exceptionMessage = getConstraintViolationMessage(exception); - - return handleExceptionInternalConstraint( - exception, - exceptionMessage, - request); - } - - @Override - protected ResponseEntity handleMethodArgumentNotValid( - MethodArgumentNotValidException exception, - HttpHeaders headers, - HttpStatusCode status, - WebRequest request) { - - Map exceptionArgs = getMethodArgumentExceptionArgs(exception); - - return handleExceptionInternalArgs( - exception, - exceptionArgs, - request); - } - - private ResponseEntity handleExceptionInternal( - GeneralException exception, - HttpServletRequest request) { - - CustomResponse body = new CustomResponse<>(exception.getExceptionReason()); - WebRequest webRequest = new ServletWebRequest(request); - - return super.handleExceptionInternal( - exception, - body, - HttpHeaders.EMPTY, - exception.getHttpStatus(), - webRequest); - } - - private Map getMethodArgumentExceptionArgs( - MethodArgumentNotValidException exception) { - - Map exceptionArgs = new LinkedHashMap<>(); - exception.getBindingResult().getFieldErrors() - .forEach(fieldError -> { - String fieldName = fieldError.getField(); - String errorMessage = Optional - .ofNullable(fieldError.getDefaultMessage()) - .orElse(""); - exceptionArgs.merge( - fieldName, - errorMessage, - (existingErrorMessage, newErrorMessage) -> - existingErrorMessage - .concat(", ") - .concat(newErrorMessage)); - }); - - return exceptionArgs; - } - - private ResponseEntity handleExceptionInternalArgs( - MethodArgumentNotValidException exception, - Map exceptionArgs, - WebRequest request) { - - CustomResponse> body = CustomResponse.onFailure( - CommonException.BAD_REQUEST.getReason(), - exceptionArgs); - - return super.handleExceptionInternal( - exception, - body, - HttpHeaders.EMPTY, - CommonException.BAD_REQUEST.getHttpStatus(), - request); - } - - private String getConstraintViolationMessage(ConstraintViolationException exception) { - - return exception.getConstraintViolations().stream() - .map(ConstraintViolation::getMessage) - .findFirst() - .orElseThrow(() -> new RuntimeException("ConstraintViolationException 추출 도중 오류 발생")); - } - - private ResponseEntity handleExceptionInternalConstraint( - ConstraintViolationException exception, - String exceptionMessage, - WebRequest request) { - - CustomResponse body = new CustomResponse<>(exceptionMessage); - - return super.handleExceptionInternal( - exception, - body, - HttpHeaders.EMPTY, - CommonException.BAD_REQUEST.getHttpStatus(), - request); - } + @ExceptionHandler(value = GeneralException.class) + public ResponseEntity handleGeneralException( + GeneralException exception, + HttpServletRequest request) { + + return handleExceptionInternal( + exception, + request); + } + + private ResponseEntity handleExceptionInternal( + GeneralException exception, + HttpServletRequest request) { + + CustomResponse body = new CustomResponse<>(exception.getExceptionReason()); + WebRequest webRequest = new ServletWebRequest(request); + + return super.handleExceptionInternal( + exception, + body, + HttpHeaders.EMPTY, + exception.getHttpStatus(), + webRequest); + } + + @Override + protected ResponseEntity handleMethodArgumentNotValid( + MethodArgumentNotValidException exception, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + + Map exceptionArgs = getMethodArgumentExceptionArgs(exception); + + return handleExceptionInternalArgs( + exception, + exceptionArgs, + request); + } + + private Map getMethodArgumentExceptionArgs( + MethodArgumentNotValidException exception) { + + Map exceptionArgs = new LinkedHashMap<>(); + exception.getBindingResult().getFieldErrors() + .forEach(fieldError -> { + String fieldName = fieldError.getField(); + String errorMessage = Optional + .ofNullable(fieldError.getDefaultMessage()) + .orElse(""); + exceptionArgs.merge( + fieldName, + errorMessage, + (existingErrorMessage, newErrorMessage) -> + existingErrorMessage + .concat(", ") + .concat(newErrorMessage)); + }); + + return exceptionArgs; + } + + private ResponseEntity handleExceptionInternalArgs( + MethodArgumentNotValidException exception, + Map exceptionArgs, + WebRequest request) { + + CustomResponse> body = CustomResponse.onFailure( + CommonException.BAD_REQUEST.getReason(), + exceptionArgs); + + return super.handleExceptionInternal( + exception, + body, + HttpHeaders.EMPTY, + CommonException.BAD_REQUEST.getHttpStatus(), + request); + } } diff --git a/be/src/main/java/yeonba/be/exception/JoinException.java b/be/src/main/java/yeonba/be/exception/JoinException.java index 9eddcca2..0faad4be 100644 --- a/be/src/main/java/yeonba/be/exception/JoinException.java +++ b/be/src/main/java/yeonba/be/exception/JoinException.java @@ -8,22 +8,6 @@ public enum JoinException implements BaseException { HttpStatus.BAD_REQUEST, "비밀번호 확인 값이 비밀번호와 일치하지 않습니다."), - VOCAL_RANGE_NOT_FOUND( - HttpStatus.BAD_REQUEST, - "존재하지 않는 음역대입니다."), - - ANIMAL_NOT_FOUND( - HttpStatus.BAD_REQUEST, - "존재하지 않는 동물상입니다."), - - AREA_NOT_FOUND( - HttpStatus.BAD_REQUEST, - "존재하지 않는 지역입니다."), - - ALREADY_USED_EMAIL( - HttpStatus.BAD_REQUEST, - "이미 사용 중인 이메일입니다."), - ALREADY_USED_NICKNAME( HttpStatus.BAD_REQUEST, "이미 사용 중인 닉네임입니다."), diff --git a/be/src/main/java/yeonba/be/exception/UserException.java b/be/src/main/java/yeonba/be/exception/UserException.java index c2dc378c..4799a498 100644 --- a/be/src/main/java/yeonba/be/exception/UserException.java +++ b/be/src/main/java/yeonba/be/exception/UserException.java @@ -1,36 +1,49 @@ package yeonba.be.exception; +import lombok.AllArgsConstructor; +import lombok.Getter; import org.springframework.http.HttpStatus; +@Getter +@AllArgsConstructor public enum UserException implements BaseException { INVALID_REFRESH_TOKEN( HttpStatus.UNAUTHORIZED, "유효하지 않은 리프레시 토큰입니다."), + NOT_MATCH_LOGIN_TYPE( + HttpStatus.BAD_REQUEST, + "다른 로그인 방식을 이용해주세요."), + + VOCAL_RANGE_NOT_FOUND( + HttpStatus.BAD_REQUEST, + "존재하지 않는 음역대입니다."), + + ANIMAL_NOT_FOUND( + HttpStatus.BAD_REQUEST, + "존재하지 않는 동물상입니다."), + + AREA_NOT_FOUND( + HttpStatus.BAD_REQUEST, + "존재하지 않는 지역입니다."), + USER_NOT_FOUND( HttpStatus.BAD_REQUEST, "해당 사용자가 존재하지 않습니다."), - NOT_MATCH_LOGIN_TYPE( + USER_PREFERENCE_NOT_FOUND( HttpStatus.BAD_REQUEST, - "다른 로그인 방식을 이용해주세요."); - - private final HttpStatus httpStatus; - private final String reason; + "해당 사용자의 선호내역이 존재하지 않습니다."), - UserException(HttpStatus httpStatus, String reason) { - this.httpStatus = httpStatus; - this.reason = reason; - } + AGE_OUT_OF_RANGE( + HttpStatus.BAD_REQUEST, + "서비스 이용이 가능한 사용자 나이는 20~40세입니다."), - @Override - public HttpStatus getHttpStatus() { - return httpStatus; - } + LOWER_BOUND_LESS_THAN_OR_EQUAL_UPPER_BOUND( + HttpStatus.BAD_REQUEST, + "하한 값은 상한 값보다 작거나 같아야 합니다."); - @Override - public String getReason() { - return reason; - } + private final HttpStatus httpStatus; + private final String reason; } diff --git a/be/src/main/java/yeonba/be/login/controller/LoginController.java b/be/src/main/java/yeonba/be/login/controller/LoginController.java index e64a9bc8..0cdb327c 100644 --- a/be/src/main/java/yeonba/be/login/controller/LoginController.java +++ b/be/src/main/java/yeonba/be/login/controller/LoginController.java @@ -10,14 +10,9 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import yeonba.be.login.dto.request.UserEmailInquiryRequest; import yeonba.be.login.dto.request.UserJoinRequest; import yeonba.be.login.dto.request.UserLoginRequest; -import yeonba.be.login.dto.request.UserPasswordInquiryRequest; import yeonba.be.login.dto.request.UserRefreshJwtRequest; -import yeonba.be.login.dto.request.UserVerificationCodeRequest; -import yeonba.be.login.dto.request.UserVerifyPhoneNumberRequest; -import yeonba.be.login.dto.response.UserEmailInquiryResponse; import yeonba.be.login.dto.response.UserJoinResponse; import yeonba.be.login.dto.response.UserLoginResponse; import yeonba.be.login.dto.response.UserRefrehJwtResponse; diff --git a/be/src/main/java/yeonba/be/login/dto/request/UserEmailInquiryRequest.java b/be/src/main/java/yeonba/be/login/dto/request/UserEmailInquiryRequest.java deleted file mode 100644 index 3d06c9b7..00000000 --- a/be/src/main/java/yeonba/be/login/dto/request/UserEmailInquiryRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -package yeonba.be.login.dto.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class UserEmailInquiryRequest { - - @Schema( - type = "string", - description = "인증 번호를 받은 번호", - example = "01011112222") - @Pattern( - regexp = "^010\\d{8}$", - message = "전화번호는 11자리 010으로 시작하며 하이픈(-) 없이 0~9의 숫자로 이뤄져야 합니다.") - @NotBlank(message = "전화번호는 반드시 입력되어야 합니다.") - private String phoneNumber; - - @Schema( - type = "string", - description = "아이디 찾기 인증 코드", - example = "A1b2C3") - @Pattern( - regexp = "^[A-Za-z0-9]{6}$", - message = "인증 코드는 6자리로 영어대소문자, 숫자로만 이뤄져야 합니다.") - @NotBlank(message = "인증 코드는 반드시 입력되어야 합니다.") - private String verificationCode; -} diff --git a/be/src/main/java/yeonba/be/login/dto/request/UserJoinRequest.java b/be/src/main/java/yeonba/be/login/dto/request/UserJoinRequest.java index fcc2f45f..cdc48993 100644 --- a/be/src/main/java/yeonba/be/login/dto/request/UserJoinRequest.java +++ b/be/src/main/java/yeonba/be/login/dto/request/UserJoinRequest.java @@ -5,12 +5,12 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.Size; import java.time.LocalDate; import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; +import org.hibernate.validator.constraints.Range; import org.springframework.web.multipart.MultipartFile; @Getter @@ -50,7 +50,7 @@ public class UserJoinRequest { message = "전화번호는 11자리 010으로 시작하며 하이픈(-) 없이 0~9의 숫자로 이뤄져야 합니다.") @NotBlank(message = "전화번호는 반드시 입력되어야 합니다.") private String phoneNumber; - + @Schema( type = "string", description = "생년월일", @@ -72,7 +72,7 @@ public class UserJoinRequest { type = "number", description = "키", example = "180") - @Positive(message = "키는 양의 정수여야 합니다.") + @Range(min = 130, max = 220, message = "키는 130 ~ 220cm 내 값만 가능합니다.") @NotNull(message = "키는 반드시 입력되어야 합니다.") private int height; @@ -162,30 +162,30 @@ public class UserJoinRequest { @Schema( type = "number", description = "선호하는 나이 하한", - example = "22") - @Positive(message = "선호하는 나이 하한은 양수여야 합니다.") - private int preferredAgeLowerBound; + example = "21") + @Range(min = 20, max = 40, message = "선호하는 나이는 20~40 내 값만 가능합니다.") + private Integer preferredAgeLowerBound; @Schema( type = "number", description = "선호하는 나이 상한", example = "30") - @Positive(message = "선호하는 나이 상한은 양수여야 합니다.") - private int preferredAgeUpperBound; + @Range(min = 20, max = 40, message = "선호하는 나이는 20~40 내 값만 가능합니다.") + private Integer preferredAgeUpperBound; @Schema( type = "number", description = "선호하는 키 하한", example = "177") - @Positive(message = "선호하는 키 하한은 양수여야 합니다.") - private int preferredHeightLowerBound; + @Range(min = 130, max = 220, message = "선호하는 키는 130~220cm 내 값만 가능합니다.") + private Integer preferredHeightLowerBound; @Schema( type = "number", description = "선호하는 키 상한", example = "185") - @Positive(message = "선호하는 키 상한은 양수여야 합니다.") - private int preferredHeightUpperBound; + @Range(min = 130, max = 220, message = "선호하는 키는 130~220cm 내 값만 가능합니다.") + private Integer preferredHeightUpperBound; @Schema( type = "string", diff --git a/be/src/main/java/yeonba/be/login/dto/request/UserPasswordInquiryRequest.java b/be/src/main/java/yeonba/be/login/dto/request/UserPasswordInquiryRequest.java deleted file mode 100644 index a140a261..00000000 --- a/be/src/main/java/yeonba/be/login/dto/request/UserPasswordInquiryRequest.java +++ /dev/null @@ -1,19 +0,0 @@ -package yeonba.be.login.dto.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Pattern; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class UserPasswordInquiryRequest { - - @Schema(type = "string", - description = "임시 비밀번호를 받을 이메일", - example = "mj3242@naver.com") - @Pattern( - regexp = "[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$", - message = "유효하지 않은 이메일 형식입니다.") - private String email; -} diff --git a/be/src/main/java/yeonba/be/login/dto/response/UserEmailInquiryResponse.java b/be/src/main/java/yeonba/be/login/dto/response/UserEmailInquiryResponse.java deleted file mode 100644 index ee858136..00000000 --- a/be/src/main/java/yeonba/be/login/dto/response/UserEmailInquiryResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package yeonba.be.login.dto.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class UserEmailInquiryResponse { - - @Schema( - type = "string", - description = "이메일", - example = "mj3242@naver.com") - private String email; -} diff --git a/be/src/main/java/yeonba/be/mypage/controller/MyPageController.java b/be/src/main/java/yeonba/be/mypage/controller/MyPageController.java index 503d3e71..a6270e9e 100644 --- a/be/src/main/java/yeonba/be/mypage/controller/MyPageController.java +++ b/be/src/main/java/yeonba/be/mypage/controller/MyPageController.java @@ -21,7 +21,6 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import yeonba.be.mypage.dto.request.UserAllowNotificationsRequest; -import yeonba.be.mypage.dto.request.UserChangePasswordRequest; import yeonba.be.mypage.dto.request.UserDormantRequest; import yeonba.be.mypage.dto.request.UserUpdateProfileRequest; import yeonba.be.mypage.dto.request.UserUpdateUnwantedAcquaintancesRequest; @@ -67,7 +66,7 @@ public ResponseEntity> getProfileDetai } @Operation(summary = "자신의 프로필 사진 수정", description = "자신의 프로필 사진을 수정할 수 있습니다.") - @ApiResponse(responseCode = "202", description = "자신의 프로필 사진 수정 정상 처리") + @ApiResponse(responseCode = "200", description = "자신의 프로필 사진 수정 정상 처리") @PutMapping(path = "/users/profile-photos", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity> updateProfilePhotos( @RequestAttribute("userId") long userId, @@ -79,12 +78,12 @@ public ResponseEntity> updateProfilePhotos( myPageService.updateProfilePhotos(profilePhotos, realTimePhoto, userId); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } @Operation(summary = "자신의 프로필 수정", description = "자신의 프로필 정보를 수정할 수 있습니다.") - @ApiResponse(responseCode = "204", description = "자신의 프로필 수정 요청 정상 처리") + @ApiResponse(responseCode = "200", description = "자신의 프로필 수정 요청 정상 처리") @PatchMapping("/users/profiles") public ResponseEntity> updateProfile( @Valid @RequestBody UserUpdateProfileRequest request, @@ -93,29 +92,23 @@ public ResponseEntity> updateProfile( myPageService.updateProfile(request, userId); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } - @Operation( - summary = "알림 on/off 설정", - description = "알림별로 on/off를 설정할 수 있습니다." - ) - @ApiResponse( - responseCode = "204", - description = "알림 on/off 설정 정상 처리" - ) + @Operation(summary = "알림 on/off 설정", description = "알림별로 on/off를 설정할 수 있습니다.") + @ApiResponse(responseCode = "200", description = "알림 on/off 설정 정상 처리") @PatchMapping("/user/notifications") public ResponseEntity> allowNotifications( @RequestBody UserAllowNotificationsRequest request) { return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } @Operation(summary = "만나고 싶지 않은 지인 목록 수정", description = "만나고 싶지 않은 지인을 추가합니다.") - @ApiResponse(responseCode = "202", description = "지인 목록 추가 정상 처리") + @ApiResponse(responseCode = "200", description = "지인 목록 추가 정상 처리") @PutMapping("/users/unwanted-acquaintances") public ResponseEntity> updateUnwantedAcquaintances( @RequestAttribute("userId") long userId, @@ -124,7 +117,7 @@ public ResponseEntity> updateUnwantedAcquaintances( acquaintanceService.updateUnwantedAcquaintances(userId, request); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } @@ -142,7 +135,7 @@ public ResponseEntity> getBlockedUsers( } @Operation(summary = "차단 해제", description = "차단한 사용자를 해제할 수 있습니다.") - @ApiResponse(responseCode = "202", description = "차단 해제 정상 처리") + @ApiResponse(responseCode = "200", description = "차단 해제 정상 처리") @DeleteMapping("/users/{userId}/block") public ResponseEntity> unblockUser( @RequestAttribute("userId") long userId, @@ -151,12 +144,12 @@ public ResponseEntity> unblockUser( myPageService.unblockUser(userId, blockedUserId); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } @Operation(summary = "휴면 계정 전환", description = "계정의 휴면 상태를 전환할 수 있습니다.") - @ApiResponse(responseCode = "202", description = "휴면 상태 전환 요청 정상 처리") + @ApiResponse(responseCode = "200", description = "휴면 상태 전환 요청 정상 처리") @PatchMapping("/users/dormant") public ResponseEntity> dormantUser( @RequestAttribute("userId") long userId, @@ -165,12 +158,12 @@ public ResponseEntity> dormantUser( myPageService.changeDormantStatus(userId, request); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } @Operation(summary = "회원 탈퇴", description = "회원 탈퇴를 할 수 있습니다. 즉시 탈퇴 처리됩니다.") - @ApiResponse(responseCode = "202", description = "계정 탈퇴 요청 정상 처리") + @ApiResponse(responseCode = "200", description = "계정 탈퇴 요청 정상 처리") @DeleteMapping("/users") public ResponseEntity> deleteUser( @RequestAttribute("userId") long userId) { @@ -178,7 +171,7 @@ public ResponseEntity> deleteUser( myPageService.deleteUser(userId); return ResponseEntity - .accepted() + .ok() .body(new CustomResponse<>()); } } diff --git a/be/src/main/java/yeonba/be/mypage/dto/request/UserUpdateProfileRequest.java b/be/src/main/java/yeonba/be/mypage/dto/request/UserUpdateProfileRequest.java index bb5bcf14..cf549b5d 100644 --- a/be/src/main/java/yeonba/be/mypage/dto/request/UserUpdateProfileRequest.java +++ b/be/src/main/java/yeonba/be/mypage/dto/request/UserUpdateProfileRequest.java @@ -1,12 +1,15 @@ package yeonba.be.mypage.dto.request; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; +import jakarta.validation.constraints.Pattern; +import java.time.LocalDate; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Range; @Getter @NoArgsConstructor @@ -16,119 +19,137 @@ public class UserUpdateProfileRequest { @Schema( type = "string", description = "별명", - example = "재벌3세" - ) - @NotBlank(message = "별명은 필수입니다.") + example = "재벌3세") + @Pattern( + regexp = "^[a-zA-Z0-9가-힣]{1,8}$", + message = "닉네임은 공백 없이 영어 대소문자,한글,숫자로 구성되어야 하며 최대 8자까지 가능합니다.") + @NotBlank(message = "닉네임은 반드시 입력되어야 합니다.") private String nickname; @Schema( type = "number", description = "키", - example = "177" - ) - @NotNull(message = "키는 필수입니다.") + example = "177") + @Range(min = 130, max = 220, message = "키는 130 ~ 220cm 내 값만 가능합니다.") + @NotNull(message = "키는 반드시 입력되어야 합니다.") private int height; @Schema( type = "string", - description = "체형", - example = "조금 통통" - ) - @NotBlank(message = "체형은 필수입니다.") - private String bodyType; + description = "음역대", + example = "고음") + @NotBlank(message = "음역대는 반드시 입력되어야 합니다.") + private String vocalRange; @Schema( type = "string", - description = "직업", - example = "직장인" - ) - @NotBlank(message = "직업은 필수입니다.") - private String job; + description = "생년월일", + example = "1998-04-08") + @PastOrPresent(message = "생년월일은 현재 날짜와 같거나 과거여야 합니다.") + @NotNull(message = "생년월일은 반드시 입력되어야 합니다.") + private LocalDate birth; @Schema( type = "string", - description = "활동 지역", - example = "서울시 강남구" - ) - @NotBlank(message = "활동 지역은 필수입니다.") - private String activityArea; + description = "체형", + example = "조금 통통") + @NotBlank(message = "체형은 반드시 입력되어야 합니다.") + private String bodyType; @Schema( type = "string", - description = "음주 성향", - example = "가끔" - ) - @NotBlank(message = "음주 성향은 필수입니다.") - private String drinkingTendency; + description = "직업", + example = "직장인") + @NotBlank(message = "직업은 반드시 입력되어야 합니다.") + private String job; @Schema( type = "string", - description = "흡연 성향", - example = "자주" - ) - @NotBlank(message = "흡연 성향은 필수입니다.") - private String smokingTendency; + description = "활동 지역", + example = "서울") + @NotBlank(message = "활동 지역은 반드시 입력되어야 합니다.") + private String activityArea; @Schema( type = "string", - description = "음역대", - example = "고음" - ) - @NotBlank(message = "음역대는 필수입니다.") - private String vocalRange; + description = "닮은 동물상", + example = "강아지상") + @NotBlank(message = "닮은 동물상은 반드시 입력되어야 합니다.") + private String lookAlikeAnimal; @Schema( type = "string", description = "MBTI", - example = "INFP" - ) + example = "INFP") + @Pattern( + regexp = "^[EI][SN][TF][JP]$", + message = "유효하지 않은 MBTI 형식입니다.") + @NotBlank(message = "MBTI는 반드시 입력되어야 합니다.") private String mbti; @Schema( type = "string", description = "선호하는 닮은 동물상", - example = "고양이상" - ) - @NotBlank(message = "선호하는 닮은 동물상은 필수입니다.") - private String preferredAnimalAppearance; + example = "고양이상") + @NotBlank(message = "선호하는 닮은 동물상은 반드시 입력되어야 합니다.") + private String preferredAnimal; @Schema( type = "string", description = "선호하는 지역", - example = "서울시 마포구" - ) - @NotBlank(message = "선호하는 지역은 필수입니다.") + example = "서울") + @NotBlank(message = "선호하는 지역은 반드시 입력되어야 합니다.") private String preferredArea; @Schema( type = "string", description = "선호하는 음역대", - example = "저음" - ) - @NotBlank(message = "선호하는 음역대는 필수입니다.") + example = "저음") + @NotBlank(message = "선호하는 음역대는 반드시 입력되어야 합니다.") private String preferredVocalRange; @Schema( type = "number", description = "선호하는 나이 하한", - example = "21" - ) - @Min(value = 0, message = "선호하는 나이 하한은 0 이상이어야 합니다.") - private int preferredAgeLowerBound; + example = "21") + @Range(min = 20, max = 40, message = "선호하는 나이는 20~40 내 값만 가능합니다.") + private Integer preferredAgeLowerBound; @Schema( type = "number", description = "선호하는 나이 상한", - example = "30" - ) - @Min(value = 0, message = "선호하는 나이 상한은 0 이상이어야 합니다.") - private int preferredAgeUpperBound; + example = "30") + @Range(min = 20, max = 40, message = "선호하는 나이는 20~40 내 값만 가능합니다.") + private Integer preferredAgeUpperBound; + + @Schema( + type = "number", + description = "선호하는 키 하한", + example = "177") + @Range(min = 130, max = 220, message = "선호하는 키는 130~220cm 내 값만 가능합니다.") + private Integer preferredHeightLowerBound; + + @Schema( + type = "number", + description = "선호하는 키 상한", + example = "185") + @Range(min = 130, max = 220, message = "선호하는 키는 130~220cm 내 값만 가능합니다.") + private Integer preferredHeightUpperBound; @Schema( type = "string", description = "선호하는 체형", - example = "마른 체형" - ) - @NotBlank(message = "선호하는 체형은 필수입니다.") + example = "마른체형") + @NotBlank(message = "선호하는 체형은 반드시 입력되어야 합니다.") private String preferredBodyType; + + @Schema( + type = "string", + description = "선호하는 MBTI", + example = "ISTJ") + @Pattern( + regexp = "^[EI][SN][TF][JP]$", + message = "유효하지 않은 MBTI 형식입니다.") + @NotBlank(message = "선호하는 MBTI는 반드시 입력되어야 합니다.") + private String preferredMbti; } diff --git a/be/src/main/java/yeonba/be/mypage/dto/response/UserProfileDetailResponse.java b/be/src/main/java/yeonba/be/mypage/dto/response/UserProfileDetailResponse.java index 815f9754..9b283d90 100644 --- a/be/src/main/java/yeonba/be/mypage/dto/response/UserProfileDetailResponse.java +++ b/be/src/main/java/yeonba/be/mypage/dto/response/UserProfileDetailResponse.java @@ -36,12 +36,6 @@ public class UserProfileDetailResponse { example = "181") private int height; - @Schema( - type = "string", - description = "이메일", - example = "mj3242@naver.com") - private String email; - @Schema( type = "string", description = "전화번호", diff --git a/be/src/main/java/yeonba/be/mypage/service/MyPageService.java b/be/src/main/java/yeonba/be/mypage/service/MyPageService.java index fc537717..c1172459 100644 --- a/be/src/main/java/yeonba/be/mypage/service/MyPageService.java +++ b/be/src/main/java/yeonba/be/mypage/service/MyPageService.java @@ -1,8 +1,10 @@ package yeonba.be.mypage.service; +import java.time.LocalDate; +import java.time.Period; import java.util.List; +import java.util.Objects; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -10,28 +12,44 @@ import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import yeonba.be.mypage.dto.request.UserChangePasswordRequest; +import yeonba.be.exception.GeneralException; +import yeonba.be.exception.UserException; import yeonba.be.mypage.dto.request.UserDormantRequest; import yeonba.be.mypage.dto.request.UserUpdateProfileRequest; import yeonba.be.mypage.dto.response.BlockedUserResponse; import yeonba.be.mypage.dto.response.BlockedUsersResponse; import yeonba.be.mypage.dto.response.UserProfileDetailResponse; import yeonba.be.mypage.dto.response.UserSimpleProfileResponse; +import yeonba.be.user.entity.Animal; +import yeonba.be.user.entity.Area; import yeonba.be.user.entity.Block; import yeonba.be.user.entity.User; +import yeonba.be.user.entity.UserPreference; +import yeonba.be.user.entity.VocalRange; import yeonba.be.user.repository.BlockCommand; import yeonba.be.user.repository.BlockQuery; +import yeonba.be.user.repository.animal.AnimalQuery; +import yeonba.be.user.repository.area.AreaQuery; import yeonba.be.user.repository.user.UserQuery; +import yeonba.be.user.repository.userpreference.UserPreferenceQuery; +import yeonba.be.user.repository.vocalrange.VocalRangeQuery; +import yeonba.be.util.AgeValidator; @Service @RequiredArgsConstructor public class MyPageService { - private final S3Client s3Client; - private final UserQuery userQuery; + private final AnimalQuery animalQuery; + private final AreaQuery areaQuery; private final BlockQuery blockQuery; + private final UserPreferenceQuery userPreferenceQuery; + private final UserQuery userQuery; + private final VocalRangeQuery vocalRangeQuery; + private final BlockCommand blockCommand; + private final S3Client s3Client; + @Value("${S3_BUCKET_NAME}") private String bucketName; @@ -58,11 +76,102 @@ public UserProfileDetailResponse getProfileDetail(long userId) { @Transactional public void updateProfile(UserUpdateProfileRequest request, long userId) { - User validatedUser = userQuery.findById(userId); + // 사용자 및 사용자 선호 조건 조회 + User user = userQuery.findById(userId); + UserPreference userPreference = userPreferenceQuery.findByUser(user); + + // 생년월일 업데이트시 20~40세인 지 검증, 새로운 나이 계산 + LocalDate birth = request.getBirth(); + LocalDate currentDate = LocalDate.now(); + AgeValidator.validateAgeByBirth(birth, currentDate); + int age = Period.between(birth, currentDate).getYears(); + + // 음역대, 선호하는 음역대 조회 + List vocalRanges = vocalRangeQuery.findAll(); + VocalRange vocalRange = + findVocalRangeByClassification(vocalRanges, request.getVocalRange()); + VocalRange preferredVocalRange = + findVocalRangeByClassification(vocalRanges, request.getPreferredVocalRange()); + + // 동물상, 선호하는 동물상 조회 + List animals = animalQuery.findAll(); + Animal animal = findAnimalByName(animals, request.getLookAlikeAnimal()); + Animal preferredAnimal = findAnimalByName(animals, request.getPreferredAnimal()); + + // 활동 지역, 선호하는 지역 조회 + List areas = areaQuery.findAll(); + Area area = findAreaByName(areas, request.getActivityArea()); + Area preferredArea = findAreaByName(areas, request.getPreferredArea()); + + // 하한, 상한 값이 모두 존재할 경우만 하한 <= 상한 검증 + Integer preferredAgeLowerBound = request.getPreferredAgeLowerBound(); + Integer preferredAgeUpperBound = request.getPreferredAgeUpperBound(); + validateBounds(preferredAgeLowerBound, preferredAgeUpperBound); + + Integer preferredHeightLowerBound = request.getPreferredHeightLowerBound(); + Integer preferredHeightUpperBound = request.getPreferredHeightUpperBound(); + validateBounds(preferredHeightLowerBound, preferredHeightUpperBound); + + // 사용자 프로필 및 선호 조건 업데이트 + user.updateProfile( + request.getNickname(), + request.getHeight(), + birth, + age, + request.getBodyType(), + request.getJob(), + request.getMbti(), + vocalRange, + animal, + area); + + userPreference.updatePreference( + preferredAgeLowerBound, + preferredAgeUpperBound, + preferredHeightLowerBound, + preferredHeightUpperBound, + request.getPreferredMbti(), + request.getPreferredBodyType(), + preferredVocalRange, + preferredAnimal, + preferredArea); + } + + private VocalRange findVocalRangeByClassification( + List vocalRanges, String classification) { + + return vocalRanges.stream() + .filter(vocalRange -> vocalRange.hasSameClassificationAs(classification)) + .findFirst() + .orElseThrow(() -> new GeneralException(UserException.VOCAL_RANGE_NOT_FOUND)); + } - // TODO: 선호 조건 테이블 생성 후 로직 추가 + private Animal findAnimalByName(List animals, String name) { - // validatedUser.updateProfile(request); + return animals.stream() + .filter(animal -> animal.hasSameNameAs(name)) + .findFirst() + .orElseThrow(() -> new GeneralException(UserException.ANIMAL_NOT_FOUND)); + } + + private Area findAreaByName(List areas, String name) { + + return areas.stream() + .filter(area -> area.hasSameNameAs(name)) + .findFirst() + .orElseThrow(() -> new GeneralException(UserException.AREA_NOT_FOUND)); + } + + private void validateBounds(Integer lowerBound, Integer upperBound) { + + if (Objects.isNull(lowerBound) || Objects.isNull(upperBound)) { + + return; + } + + if (lowerBound > upperBound) { + throw new GeneralException(UserException.LOWER_BOUND_LESS_THAN_OR_EQUAL_UPPER_BOUND); + } } public void updateProfilePhotos(List profilePhotos, MultipartFile realTimePhoto, diff --git a/be/src/main/java/yeonba/be/user/entity/Animal.java b/be/src/main/java/yeonba/be/user/entity/Animal.java index a1c01b87..dcc4e363 100644 --- a/be/src/main/java/yeonba/be/user/entity/Animal.java +++ b/be/src/main/java/yeonba/be/user/entity/Animal.java @@ -9,6 +9,7 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; @Table(name = "animals") @Getter @@ -26,4 +27,9 @@ public class Animal { public Animal(String name) { this.name = name; } + + public boolean hasSameNameAs(String name) { + + return StringUtils.equals(this.name, name); + } } diff --git a/be/src/main/java/yeonba/be/user/entity/Area.java b/be/src/main/java/yeonba/be/user/entity/Area.java index c93a683e..d751475c 100644 --- a/be/src/main/java/yeonba/be/user/entity/Area.java +++ b/be/src/main/java/yeonba/be/user/entity/Area.java @@ -1,24 +1,34 @@ package yeonba.be.user.entity; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; @Table(name = "areas") @Getter @Entity @NoArgsConstructor -@AllArgsConstructor public class Area { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(nullable = false) private String name; + + public Area(String name) { + this.name = name; + } + + public boolean hasSameNameAs(String name) { + + return StringUtils.equals(this.name, name); + } } diff --git a/be/src/main/java/yeonba/be/user/entity/User.java b/be/src/main/java/yeonba/be/user/entity/User.java index 50ca5883..99eb4fc9 100644 --- a/be/src/main/java/yeonba/be/user/entity/User.java +++ b/be/src/main/java/yeonba/be/user/entity/User.java @@ -223,4 +223,28 @@ public void updateRefreshToken(String refreshToken) { this.refreshToken = refreshToken; } + + public void updateProfile( + String nickname, + int height, + LocalDate birth, + int age, + String bodyType, + String job, + String mbti, + VocalRange vocalRange, + Animal animal, + Area area) { + + this.nickname = nickname; + this.height = height; + this.birth = birth; + this.age = age; + this.bodyType = bodyType; + this.job = job; + this.mbti = mbti; + this.vocalRange = vocalRange; + this.animal = animal; + this.area = area; + } } diff --git a/be/src/main/java/yeonba/be/user/entity/UserPreference.java b/be/src/main/java/yeonba/be/user/entity/UserPreference.java index eb3f3e18..3589515b 100644 --- a/be/src/main/java/yeonba/be/user/entity/UserPreference.java +++ b/be/src/main/java/yeonba/be/user/entity/UserPreference.java @@ -23,17 +23,13 @@ public class UserPreference { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) - private int ageLowerBound; + private Integer ageLowerBound; - @Column(nullable = false) - private int ageUpperBound; + private Integer ageUpperBound; - @Column(nullable = false) - private int heightLowerBound; + private Integer heightLowerBound; - @Column(nullable = false) - private int heightUpperBound; + private Integer heightUpperBound; @Column(nullable = false) private String mbti; @@ -80,4 +76,26 @@ public UserPreference( this.area = area; this.animal = animal; } + + public void updatePreference( + Integer ageLowerBound, + Integer ageUpperBound, + Integer heightLowerBound, + Integer heightUpperBound, + String mbti, + String bodyType, + VocalRange vocalRange, + Animal animal, + Area area) { + + this.ageLowerBound = ageLowerBound; + this.ageUpperBound = ageUpperBound; + this.heightLowerBound = heightLowerBound; + this.heightUpperBound = heightUpperBound; + this.mbti = mbti; + this.bodyType = bodyType; + this.vocalRange = vocalRange; + this.animal = animal; + this.area = area; + } } diff --git a/be/src/main/java/yeonba/be/user/entity/VocalRange.java b/be/src/main/java/yeonba/be/user/entity/VocalRange.java index 9b24f3ab..78b70f1e 100644 --- a/be/src/main/java/yeonba/be/user/entity/VocalRange.java +++ b/be/src/main/java/yeonba/be/user/entity/VocalRange.java @@ -1,23 +1,34 @@ package yeonba.be.user.entity; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; @Table(name = "vocals_ranges") @Getter @Entity @NoArgsConstructor -@AllArgsConstructor public class VocalRange { @Id @GeneratedValue private Long id; + + @Column(nullable = false) private String classification; + + public VocalRange(String classification) { + this.classification = classification; + } + + public boolean hasSameClassificationAs(String classification) { + + return StringUtils.equals(this.classification, classification); + } } diff --git a/be/src/main/java/yeonba/be/user/repository/animal/AnimalQuery.java b/be/src/main/java/yeonba/be/user/repository/animal/AnimalQuery.java index 1cfbd8c3..f55f6e9f 100644 --- a/be/src/main/java/yeonba/be/user/repository/animal/AnimalQuery.java +++ b/be/src/main/java/yeonba/be/user/repository/animal/AnimalQuery.java @@ -1,9 +1,10 @@ package yeonba.be.user.repository.animal; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import yeonba.be.exception.GeneralException; -import yeonba.be.exception.JoinException; +import yeonba.be.exception.UserException; import yeonba.be.user.entity.Animal; @Component @@ -15,6 +16,11 @@ public class AnimalQuery { public Animal findByName(String name) { return animalRepository.findByName(name) - .orElseThrow(() -> new GeneralException(JoinException.ANIMAL_NOT_FOUND)); + .orElseThrow(() -> new GeneralException(UserException.ANIMAL_NOT_FOUND)); + } + + public List findAll() { + + return animalRepository.findAll(); } } diff --git a/be/src/main/java/yeonba/be/user/repository/area/AreaQuery.java b/be/src/main/java/yeonba/be/user/repository/area/AreaQuery.java index d803a69c..f92ade3e 100644 --- a/be/src/main/java/yeonba/be/user/repository/area/AreaQuery.java +++ b/be/src/main/java/yeonba/be/user/repository/area/AreaQuery.java @@ -1,9 +1,10 @@ package yeonba.be.user.repository.area; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import yeonba.be.exception.GeneralException; -import yeonba.be.exception.JoinException; +import yeonba.be.exception.UserException; import yeonba.be.user.entity.Area; @Component @@ -15,6 +16,11 @@ public class AreaQuery { public Area findByName(String name) { return areaRepository.findByName(name) - .orElseThrow(() -> new GeneralException(JoinException.AREA_NOT_FOUND)); + .orElseThrow(() -> new GeneralException(UserException.AREA_NOT_FOUND)); + } + + public List findAll() { + + return areaRepository.findAll(); } } diff --git a/be/src/main/java/yeonba/be/user/repository/user/UserQuery.java b/be/src/main/java/yeonba/be/user/repository/user/UserQuery.java index c0e6056f..c0bfa009 100644 --- a/be/src/main/java/yeonba/be/user/repository/user/UserQuery.java +++ b/be/src/main/java/yeonba/be/user/repository/user/UserQuery.java @@ -5,7 +5,6 @@ import yeonba.be.exception.GeneralException; import yeonba.be.exception.UserException; import yeonba.be.user.entity.User; -import yeonba.be.user.enums.LoginType; @Component @RequiredArgsConstructor diff --git a/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceQuery.java b/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceQuery.java new file mode 100644 index 00000000..938d3ec1 --- /dev/null +++ b/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceQuery.java @@ -0,0 +1,22 @@ +package yeonba.be.user.repository.userpreference; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import yeonba.be.exception.GeneralException; +import yeonba.be.exception.UserException; +import yeonba.be.user.entity.User; +import yeonba.be.user.entity.UserPreference; + +@Component +@RequiredArgsConstructor +public class UserPreferenceQuery { + + private final UserPreferenceRepository userPreferenceRepository; + + public UserPreference findByUser(User user) { + + return userPreferenceRepository.findFirstByUser(user) + .orElseThrow(() -> new GeneralException(UserException.USER_PREFERENCE_NOT_FOUND)); + } + +} diff --git a/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceRepository.java b/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceRepository.java index 21fc69b4..43f1ad8d 100644 --- a/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceRepository.java +++ b/be/src/main/java/yeonba/be/user/repository/userpreference/UserPreferenceRepository.java @@ -1,10 +1,14 @@ package yeonba.be.user.repository.userpreference; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import yeonba.be.user.entity.User; import yeonba.be.user.entity.UserPreference; @Repository public interface UserPreferenceRepository extends JpaRepository { + Optional findFirstByUser(User user); + } diff --git a/be/src/main/java/yeonba/be/user/repository/vocalrange/VocalRangeQuery.java b/be/src/main/java/yeonba/be/user/repository/vocalrange/VocalRangeQuery.java index 24a11a90..9e81d807 100644 --- a/be/src/main/java/yeonba/be/user/repository/vocalrange/VocalRangeQuery.java +++ b/be/src/main/java/yeonba/be/user/repository/vocalrange/VocalRangeQuery.java @@ -1,9 +1,10 @@ package yeonba.be.user.repository.vocalrange; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import yeonba.be.exception.GeneralException; -import yeonba.be.exception.JoinException; +import yeonba.be.exception.UserException; import yeonba.be.user.entity.VocalRange; @Component @@ -12,9 +13,14 @@ public class VocalRangeQuery { private final VocalRangeRepository vocalRangeRepository; - public VocalRange findBy(String classification) { + public VocalRange findByClassification(String classification) { return vocalRangeRepository.findByClassification(classification) - .orElseThrow(() -> new GeneralException(JoinException.VOCAL_RANGE_NOT_FOUND)); + .orElseThrow(() -> new GeneralException(UserException.VOCAL_RANGE_NOT_FOUND)); + } + + public List findAll() { + + return vocalRangeRepository.findAll(); } } diff --git a/be/src/main/java/yeonba/be/user/service/UserService.java b/be/src/main/java/yeonba/be/user/service/UserService.java index fe17ac80..23e48ac4 100644 --- a/be/src/main/java/yeonba/be/user/service/UserService.java +++ b/be/src/main/java/yeonba/be/user/service/UserService.java @@ -20,13 +20,14 @@ import yeonba.be.user.entity.VocalRange; import yeonba.be.user.enums.Gender; import yeonba.be.user.enums.LoginType; -import yeonba.be.user.repository.user.UserCommand; -import yeonba.be.user.repository.user.UserQuery; import yeonba.be.user.repository.animal.AnimalQuery; import yeonba.be.user.repository.area.AreaQuery; import yeonba.be.user.repository.profilephoto.ProfilePhotoCommand; +import yeonba.be.user.repository.user.UserCommand; +import yeonba.be.user.repository.user.UserQuery; import yeonba.be.user.repository.userpreference.UserPreferenceCommand; import yeonba.be.user.repository.vocalrange.VocalRangeQuery; +import yeonba.be.util.AgeValidator; import yeonba.be.util.S3Service; @Service @@ -88,12 +89,14 @@ public User saveUser(UserJoinRequest request) { // 성별 판별 Gender gender = Gender.from(request.getGender()); - // 나이 계산 + // 나이 20~40세인 지 검증 & 나이 계산 LocalDate birth = request.getBirth(); - int age = Period.between(birth, LocalDate.now()).getYears(); + LocalDate currentDate = LocalDate.now(); + AgeValidator.validateAgeByBirth(birth, currentDate); + int age = Period.between(birth, currentDate).getYears(); // 음역대, 동물상, 지역 조회 - VocalRange vocalRange = vocalRangeQuery.findBy(request.getVocalRange()); + VocalRange vocalRange = vocalRangeQuery.findByClassification(request.getVocalRange()); Animal animal = animalQuery.findByName(request.getLookAlikeAnimal()); Area area = areaQuery.findByName(request.getActivityArea()); @@ -136,7 +139,8 @@ public void saveUserPreference(User user, UserJoinRequest request) { // 선호 음역대, 동물상, 지역 조회 Animal preferredAnimal = animalQuery.findByName(request.getPreferredAnimal()); - VocalRange preferredVocalRange = vocalRangeQuery.findBy(request.getPreferredVocalRange()); + VocalRange preferredVocalRange = + vocalRangeQuery.findByClassification(request.getPreferredVocalRange()); Area preferredArea = areaQuery.findByName(request.getPreferredArea()); UserPreference userPreference = new UserPreference( diff --git a/be/src/main/java/yeonba/be/util/AgeValidator.java b/be/src/main/java/yeonba/be/util/AgeValidator.java new file mode 100644 index 00000000..908791c4 --- /dev/null +++ b/be/src/main/java/yeonba/be/util/AgeValidator.java @@ -0,0 +1,26 @@ +package yeonba.be.util; + +import java.time.LocalDate; +import java.time.Period; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import yeonba.be.exception.GeneralException; +import yeonba.be.exception.UserException; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AgeValidator { + + public static void validateAgeByBirth(LocalDate birth, LocalDate currentDate) { + + int ageLowerBound = 20; + int ageUpperBound = 40; + int age = Period.between(birth, currentDate).getYears(); + + boolean isLessThanLowerBound = age < ageLowerBound; + boolean isGreaterThanUpperBound = age > ageUpperBound; + + if (isLessThanLowerBound || isGreaterThanUpperBound) { + throw new GeneralException(UserException.AGE_OUT_OF_RANGE); + } + } +} diff --git a/be/src/main/java/yeonba/be/util/GlobalValidationRegex.java b/be/src/main/java/yeonba/be/util/GlobalValidationRegex.java index b496a24e..ca09526b 100644 --- a/be/src/main/java/yeonba/be/util/GlobalValidationRegex.java +++ b/be/src/main/java/yeonba/be/util/GlobalValidationRegex.java @@ -1,18 +1,15 @@ package yeonba.be.util; -public enum GlobalValidationRegex { - - EMAIL("[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"), - PASSWORD("^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[~#@!]).{8,20}$"); +import lombok.AllArgsConstructor; +import lombok.Getter; - private final String pattern; - - GlobalValidationRegex(String pattern) { - this.pattern = pattern; - } +@Getter +@AllArgsConstructor +public enum GlobalValidationRegex { - public String getPattern() { + PASSWORD("^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[~#@!]).{8,20}$"), + VERIFICATION_CODE("^[A-Za-z0-9]{6}$"), + PHONE_NUMBER("^010\\d{8}$"); - return pattern; - } + private final String pattern; } diff --git a/be/src/main/java/yeonba/be/util/ServiceRegex.java b/be/src/main/java/yeonba/be/util/ServiceRegex.java deleted file mode 100644 index 315ff805..00000000 --- a/be/src/main/java/yeonba/be/util/ServiceRegex.java +++ /dev/null @@ -1,21 +0,0 @@ -package yeonba.be.util; - -public enum ServiceRegex { - - EMAIL("[a-zA-Z0-9_!#$%&’*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"), - PASSWORD("^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[~#@!]).{8,20}$"), - VERIFICATION_CODE("^[A-Za-z0-9]{6}$"), - PHONE_NUMBER("^010\\d{8}$"); - - private final String pattern; - - ServiceRegex(String pattern) { - - this.pattern = pattern; - } - - public String getPattern() { - - return pattern; - } -}