diff --git a/build.gradle.kts b/build.gradle.kts index 81ca14d..25435de 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,6 +50,9 @@ dependencies { //log implementation ("io.github.microutils:kotlin-logging:3.0.5") + + // valid + implementation("org.springframework.boot:spring-boot-starter-validation") } allOpen { diff --git a/src/main/kotlin/com/psr/psr/global/Constant.kt b/src/main/kotlin/com/psr/psr/global/Constant.kt index 5c6b585..a7bb788 100644 --- a/src/main/kotlin/com/psr/psr/global/Constant.kt +++ b/src/main/kotlin/com/psr/psr/global/Constant.kt @@ -1,20 +1,11 @@ package com.psr.psr.global class Constant { - class JWT{ - companion object JWT{ + class JWT { + companion object JWT { const val AUTHORIZATION_HEADER = "Authorization" const val BEARER_PREFIX: String = "Bearer " } } - class User{ - companion object User{ - // 비밀번호 (숫자, 문자, 특수문자 포함 8~15자리 이내) - const val PASSWORD_VALIDATION = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$" - const val EMAIL_VALIDATION = "^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}\$" - const val PHONE_VALIDATION = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})\$" - } - } - } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt index e13b99a..6f74a53 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/BaseResponseCode.kt @@ -13,9 +13,6 @@ enum class BaseResponseCode(status: HttpStatus, message: String) { EXPIRED_TOKEN(HttpStatus.FORBIDDEN, "만료된 토큰 값입니다."), // user - INVALID_EMAIL(HttpStatus.BAD_REQUEST, "올바르지 않은 이메일 형식입니다."), - INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "올바르지 않은 비밀번호 형식입니다."), - INVALID_PHONE(HttpStatus.BAD_REQUEST, "올바르지 않은 휴대폰 형식입니다."), EXISTS_PHONE(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 휴대폰 번호입니다."), EXISTS_EMAIL(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 이메일입니다."), EXISTS_NICKNAME(HttpStatus.BAD_REQUEST, "이미 가입되어 있는 닉네임입니다."), diff --git a/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt b/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt index 3be41fa..cc1a796 100644 --- a/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt +++ b/src/main/kotlin/com/psr/psr/global/exception/ExceptionHandler.kt @@ -1,9 +1,14 @@ package com.psr.psr.global.exception -import com.psr.psr.global.dto.BaseResponse +import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity +import org.springframework.validation.FieldError +import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.bind.annotation.RestControllerAdvice +import java.util.* + @RestControllerAdvice class ExceptionHandler { @@ -12,4 +17,12 @@ class ExceptionHandler { return ResponseEntity.status(e.baseResponseCode.status) .body(BaseRes(e.baseResponseCode.status.value(), e.baseResponseCode.message)) } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MethodArgumentNotValidException::class) + protected fun handleMethodArgumentNotValidException(e:MethodArgumentNotValidException): ResponseEntity{ + val fieldError = Objects.requireNonNull(e.fieldError) + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(BaseRes(HttpStatus.BAD_REQUEST.value(), String.format("%s", fieldError?.defaultMessage))) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt index 220a1be..9f15244 100644 --- a/src/main/kotlin/com/psr/psr/user/controller/UserController.kt +++ b/src/main/kotlin/com/psr/psr/user/controller/UserController.kt @@ -1,10 +1,10 @@ package com.psr.psr.user.controller import com.psr.psr.global.dto.BaseResponse -import com.psr.psr.global.exception.BaseResponseCode import com.psr.psr.global.jwt.dto.TokenRes import com.psr.psr.user.dto.SignUpReq import com.psr.psr.user.service.UserService +import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* @RestController @@ -17,7 +17,7 @@ class UserController( */ @PostMapping("/signup") @ResponseBody - fun signUp (@RequestBody signUpReq: SignUpReq) : BaseResponse{ + fun signUp (@RequestBody @Validated signUpReq: SignUpReq) : BaseResponse{ return BaseResponse(userService.signUp(signUpReq)) } } \ No newline at end of file diff --git a/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt b/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt index bcdd8be..5c2818a 100644 --- a/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt +++ b/src/main/kotlin/com/psr/psr/user/dto/SignUpReq.kt @@ -1,21 +1,40 @@ package com.psr.psr.user.dto import com.psr.psr.user.entity.* -import java.util.stream.Collector +import jakarta.annotation.Nullable +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotEmpty +import jakarta.validation.constraints.Pattern +import org.jetbrains.annotations.NotNull import java.util.stream.Collectors - - data class SignUpReq ( + @field:NotBlank + @field:Email(message = "올바르지 않은 이메일 형식입니다.") val email: String, + @field:NotBlank + @field:Pattern( + regexp = "^.*(?=^.{8,15}\$)(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!@#\$%^&+=]).*\$", + message = "비밀번호를 숫자, 문자, 특수문자 포함 8~15자리 이내로 입력해주세요" + ) var password: String, + @field:NotBlank val type: String, + @field:Pattern( + regexp = "^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})\$", + message = "올바르지 않은 휴대폰 형식입니다." + ) val phone: String, - val imgKey: String, + @field:Nullable + val imgKey: String? = null, + @field:NotBlank val nickname: String, val marketing: Boolean, + @field:NotNull val notification: Boolean, + @field:NotEmpty val interestList: List ) { fun toEntity(): User { diff --git a/src/main/kotlin/com/psr/psr/user/service/UserService.kt b/src/main/kotlin/com/psr/psr/user/service/UserService.kt index 503fd9d..00bf390 100644 --- a/src/main/kotlin/com/psr/psr/user/service/UserService.kt +++ b/src/main/kotlin/com/psr/psr/user/service/UserService.kt @@ -1,17 +1,11 @@ package com.psr.psr.user.service -import com.fasterxml.jackson.databind.ser.Serializers.Base -import com.psr.psr.global.Constant.User.User.EMAIL_VALIDATION -import com.psr.psr.global.Constant.User.User.PASSWORD_VALIDATION -import com.psr.psr.global.Constant.User.User.PHONE_VALIDATION import com.psr.psr.global.exception.BaseException import com.psr.psr.global.exception.BaseResponseCode import com.psr.psr.global.jwt.dto.TokenRes import com.psr.psr.global.jwt.utils.JwtUtils import com.psr.psr.user.dto.SignUpReq -import com.psr.psr.user.entity.Category import com.psr.psr.user.entity.User -import com.psr.psr.user.entity.UserInterest import com.psr.psr.user.repository.UserInterestRepository import com.psr.psr.user.repository.UserRepository import org.springframework.security.authentication.UsernamePasswordAuthenticationToken @@ -35,13 +29,6 @@ class UserService( // 회원가입 @Transactional fun signUp(signUpReq: SignUpReq): TokenRes { - // 이메일의 형식이 맞는지 확인 - if(!isValidRegularExpression(signUpReq.email, EMAIL_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_EMAIL) - // 비밀번호의 형식이 맞는지 확인 - if(!isValidRegularExpression(signUpReq.password, PASSWORD_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_PASSWORD) - // 휴대폰 번호의 형식이 맞는지 확인 - if(!isValidRegularExpression(signUpReq.phone, PHONE_VALIDATION)) throw BaseException(BaseResponseCode.INVALID_PHONE) - // Category가 알맞은 이름을 갖고 있는지, 값이 중복되어있는지 확인 val categoryCheck = signUpReq.interestList.stream().map { i -> i.checkInterestCategory() }.collect(Collectors.toList()).groupingBy { it }.eachCount().any { it.value > 1 } if(categoryCheck) throw BaseException(BaseResponseCode.INVALID_USER_INTEREST_COUNT) // category 의 사이즈 확인