From ad5006c4072256ca6ce3990d5c194458b5e7a942 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:46:05 +0900 Subject: [PATCH 01/47] =?UTF-8?q?stlye:=20annotation=20=EB=B0=8F=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=AA=85=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EB=AA=A9=EC=A0=81=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 설정 클래스 -> configuration --- .../backendoori/ootw/common/image/MiniOImageServiceImpl.java | 4 ++-- src/main/java/com/backendoori/ootw/config/MiniOConfig.java | 4 ++-- ...rviceImplTest.java => MiniOImageServiceImplTestValid.java} | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) rename src/test/java/com/backendoori/ootw/common/image/{MiniOImageServiceImplTest.java => MiniOImageServiceImplTestValid.java} (92%) diff --git a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java b/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java index 9a01a397..97138a29 100644 --- a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java +++ b/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java @@ -10,12 +10,12 @@ import io.minio.http.Method; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Controller; +import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @Slf4j -@Controller +@Service @RequiredArgsConstructor public class MiniOImageServiceImpl implements ImageService { diff --git a/src/main/java/com/backendoori/ootw/config/MiniOConfig.java b/src/main/java/com/backendoori/ootw/config/MiniOConfig.java index c317d8de..358ce4c9 100644 --- a/src/main/java/com/backendoori/ootw/config/MiniOConfig.java +++ b/src/main/java/com/backendoori/ootw/config/MiniOConfig.java @@ -5,9 +5,9 @@ import io.minio.MinioClient; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; +import org.springframework.context.annotation.Configuration; -@Component +@Configuration @RequiredArgsConstructor public class MiniOConfig { diff --git a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java similarity index 92% rename from src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java rename to src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java index 7ce4a909..2498a7e8 100644 --- a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java +++ b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThatCode; -import com.backendoori.ootw.common.image.ImageService; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,7 +12,7 @@ @SpringBootTest @AutoConfigureMockMvc -class MiniOImageServiceImplTest { +class MiniOImageServiceImplTestValid { @Autowired MockMvc mockMvc; From 3ae1e065c761c4dc03d50a31cc9fa06e9dd4ef01 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:46:54 +0900 Subject: [PATCH 02/47] =?UTF-8?q?refactoring:=20controller=20=EC=97=90=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=ED=95=98=EB=8A=94=20exceptionhandling=20Glob?= =?UTF-8?q?alControllerAdvice=EB=A1=9C=20=EC=9D=B4=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalControllerAdvice.java | 41 +++++++++++++++++++ .../ootw/post/controller/PostController.java | 35 ---------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index aa52b3c9..bbd06f7d 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -1,13 +1,18 @@ package com.backendoori.ootw.exception; +import java.util.List; import java.util.NoSuchElementException; +import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DuplicateKeyException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.security.core.AuthenticationException; +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.HandlerMethodValidationException; @Slf4j @RestControllerAdvice @@ -37,6 +42,42 @@ public ResponseEntity handleDuplicateKeyException(DuplicateKeyExc .body(errorResponse); } + @ExceptionHandler(HandlerMethodValidationException.class) + public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { + String errorMessage = e.getAllValidationResults().get(0) + .getResolvableErrors() + .get(0) + .getDefaultMessage(); + ErrorResponse errorResponse = new ErrorResponse(errorMessage); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(HttpMessageNotReadableException.class) + public ResponseEntity httpMessageNotReadableException(HttpMessageNotReadableException e) { + ErrorResponse errorResponse = new ErrorResponse(ErrorMessage.JSON_CONVERT_ERROR.getMessage()); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity>> handleMethodArgumentNotValidException( + MethodArgumentNotValidException e + ) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ExceptionResponse.from(e)); + } + + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity> handleIllegalArgumentException( + IllegalArgumentException e + ) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ExceptionResponse.from(e)); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); diff --git a/src/main/java/com/backendoori/ootw/post/controller/PostController.java b/src/main/java/com/backendoori/ootw/post/controller/PostController.java index 17e82ea2..5c3ba93a 100644 --- a/src/main/java/com/backendoori/ootw/post/controller/PostController.java +++ b/src/main/java/com/backendoori/ootw/post/controller/PostController.java @@ -2,9 +2,6 @@ import java.net.URI; import java.util.List; -import java.util.NoSuchElementException; -import com.backendoori.ootw.exception.ExceptionResponse; -import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import com.backendoori.ootw.post.dto.PostReadResponse; import com.backendoori.ootw.post.dto.PostSaveRequest; import com.backendoori.ootw.post.dto.PostSaveResponse; @@ -13,8 +10,6 @@ import lombok.RequiredArgsConstructor; 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.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -55,34 +50,4 @@ public ResponseEntity> readAll() { .body(postService.getAll()); } - @ExceptionHandler(Exception.class) - public ResponseEntity> handleException(Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ExceptionResponse.from(e)); - } - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity> handleIllegalArgumentException( - IllegalArgumentException e - ) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(ExceptionResponse.from(e)); - } - - @ExceptionHandler(NoSuchElementException.class) - public ResponseEntity> handleNoSuchElementException( - NoSuchElementException e - ) { - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .body(ExceptionResponse.from(e)); - } - - @ExceptionHandler(MethodArgumentNotValidException.class) - public ResponseEntity>> handleMethodArgumentNotValidException( - MethodArgumentNotValidException e - ) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(ExceptionResponse.from(e)); - } - } From 2a62844ba32dd49edaf32d4da605f07bc7b0467b Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:47:29 +0900 Subject: [PATCH 03/47] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=8B=B4=EB=8A=94=20enum=20=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이 방식으로 진행하는 것은 어떤가 제한합니다.(한 곳에서 message 관리) --- .../backendoori/ootw/exception/ErrorMessage.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/exception/ErrorMessage.java diff --git a/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java b/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java new file mode 100644 index 00000000..35ac114d --- /dev/null +++ b/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java @@ -0,0 +1,15 @@ +package com.backendoori.ootw.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ErrorMessage { + + JSON_CONVERT_ERROR("해당 요청을 읽을 수 없습니다."); + + private final String message; + +} From 25a5f1b86d178947d0e23921a92261668bfb635d Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:48:59 +0900 Subject: [PATCH 04/47] =?UTF-8?q?feat:=20spring=20tomcat=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=B0=9B=EC=9D=84=20=EC=88=98=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EC=82=AC=EC=A7=84=EC=9D=98=20=EC=B5=9C=EB=8C=80=20=ED=81=AC?= =?UTF-8?q?=EA=B8=B0=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit default값 : 1MB -> 10MB로 변경 --- .../ootw/common/image/MultipartConfig.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java diff --git a/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java b/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java new file mode 100644 index 00000000..ad1e2fa6 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java @@ -0,0 +1,27 @@ +package com.backendoori.ootw.common.image; + +import jakarta.servlet.MultipartConfigElement; +import org.springframework.boot.web.servlet.MultipartConfigFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.unit.DataSize; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.support.StandardServletMultipartResolver; + +@Configuration +public class MultipartConfig { + + @Bean + public MultipartResolver multipartResolver() { + return new StandardServletMultipartResolver(); + } + + @Bean + public MultipartConfigElement multipartConfigElement() { + MultipartConfigFactory factory = new MultipartConfigFactory(); + factory.setMaxRequestSize(DataSize.ofMegabytes(100L)); + factory.setMaxFileSize(DataSize.ofMegabytes(100L)); + + return factory.createMultipartConfig(); + } +} From dd6c648da4b9fce209a92bd4a58a5ead621357bc Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:49:41 +0900 Subject: [PATCH 05/47] =?UTF-8?q?feat:=20avatar=20image=20validation?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20custom=20enum,=20validator=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/common/validation/ImageValid.java | 23 +++++++++++++++++ .../common/validation/ImageValidator.java | 25 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/common/validation/ImageValid.java create mode 100644 src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageValid.java b/src/main/java/com/backendoori/ootw/common/validation/ImageValid.java new file mode 100644 index 00000000..6c15fa8b --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/validation/ImageValid.java @@ -0,0 +1,23 @@ +package com.backendoori.ootw.common.validation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +@Target(value = ElementType.PARAMETER) +@Retention(value = RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ImageValidator.class) +public @interface ImageValid { + + String message = "유효하지 않은 이미지를 업로드하였습니다. 다른 이미지를 업로드 해주세요"; + + String message() default message; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java b/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java new file mode 100644 index 00000000..6e5e6270 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java @@ -0,0 +1,25 @@ +package com.backendoori.ootw.common.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.springframework.web.multipart.MultipartFile; + +public class ImageValidator implements ConstraintValidator { + + @Override + public boolean isValid(MultipartFile img, ConstraintValidatorContext context) { + if(img == null || img.isEmpty()){ + return false; + } + if(img.getSize() > 10_000_000){ + return false; + } + String contentType = img.getContentType(); + if(!contentType.startsWith("image")){ + return false; + } + + return true; + } + +} From 7530f96a2c8fd6e17811319dc9d0fd981986e917 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:50:11 +0900 Subject: [PATCH 06/47] =?UTF-8?q?feat:=20item=20type=20validation=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EC=9D=84=20=EC=9C=84=ED=95=9C=20custom=20enu?= =?UTF-8?q?m,=20validator=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/common/image/MultipartConfig.java | 6 ++-- .../ootw/common/validation/ItemTypeValid.java | 23 +++++++++++++ .../common/validation/ItemTypeValidator.java | 33 +++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java create mode 100644 src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java diff --git a/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java b/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java index ad1e2fa6..2568e3eb 100644 --- a/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java +++ b/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java @@ -10,7 +10,7 @@ @Configuration public class MultipartConfig { - + @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); @@ -19,8 +19,8 @@ public MultipartResolver multipartResolver() { @Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); - factory.setMaxRequestSize(DataSize.ofMegabytes(100L)); - factory.setMaxFileSize(DataSize.ofMegabytes(100L)); + factory.setMaxRequestSize(DataSize.ofMegabytes(10L)); + factory.setMaxFileSize(DataSize.ofMegabytes(10L)); return factory.createMultipartConfig(); } diff --git a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java new file mode 100644 index 00000000..2fe0137a --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java @@ -0,0 +1,23 @@ +package com.backendoori.ootw.common.validation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +@Target(value = {ElementType.PARAMETER, ElementType.FIELD}) +@Retention(value = RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ItemTypeValidator.class) +public @interface ItemTypeValid { + + String message = "유효하지 않은 값입니다. 다시 입력해주세요"; + + String message() default message; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java new file mode 100644 index 00000000..eca40f2b --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java @@ -0,0 +1,33 @@ +package com.backendoori.ootw.common.validation; + +import java.util.Arrays; +import java.util.List; +import com.backendoori.ootw.avatar.domain.Type; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class ItemTypeValidator implements ConstraintValidator { + + private ItemTypeValid annotation; + + @Override + public void initialize(ItemTypeValid constraintAnnotation) { + this.annotation = constraintAnnotation; + } + + @Override + public boolean isValid(String type, ConstraintValidatorContext context) { + if (type == null) { + return false; + } + List enumList = Arrays.stream(Type.class.getEnumConstants()) + .map(Enum::name) + .toList(); + if (!enumList.contains(type)) { + return false; + } + + return true; + } + +} From 04c866330cc0627db4ce0b5635d9205a05855422 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:51:11 +0900 Subject: [PATCH 07/47] =?UTF-8?q?feat:=20AvatarItemRequest=EC=97=90=20vali?= =?UTF-8?q?dation=EC=9D=84=20=EC=9C=84=ED=95=9C=20annotation=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/avatar/dto/AvatarItemRequest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java index 9baed1a7..2d9e2cfb 100644 --- a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java +++ b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java @@ -1,7 +1,12 @@ package com.backendoori.ootw.avatar.dto; +import com.backendoori.ootw.common.validation.ItemTypeValid; +import jakarta.validation.constraints.NotNull; + public record AvatarItemRequest( + @ItemTypeValid String type, + @NotNull boolean sex ) { From 811a840386d5199d8676c3a1c5dff68c015f6b05 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:51:27 +0900 Subject: [PATCH 08/47] =?UTF-8?q?feat:=20validation=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20Con?= =?UTF-8?q?troller=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/avatar/controller/AvatarItemController.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java b/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java index d66ad894..c2539f69 100644 --- a/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java +++ b/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java @@ -3,27 +3,28 @@ import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.dto.AvatarItemResponse; import com.backendoori.ootw.avatar.service.AvatarItemService; +import com.backendoori.ootw.common.validation.ImageValid; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; 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.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController -@RequestMapping("/api/v1/image") +@RequestMapping("/api/v1/avatar-items") @RequiredArgsConstructor public class AvatarItemController { private final AvatarItemService appearanceService; @PostMapping - public ResponseEntity uploadImage(@RequestPart("file") MultipartFile file, - @RequestBody AvatarItemRequest requestDto) { - AvatarItemResponse avatarItem = appearanceService.uploadItem(file, requestDto); + public ResponseEntity uploadImage(@RequestPart @ImageValid MultipartFile file, + @RequestPart @Valid AvatarItemRequest request) { + AvatarItemResponse avatarItem = appearanceService.uploadItem(file, request); return ResponseEntity.status(HttpStatus.CREATED).body(avatarItem); } From 557f10f6044ab8486e3d44642d93b9156a25fcb1 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 18:52:52 +0900 Subject: [PATCH 09/47] =?UTF-8?q?feat:=20avatarItem=20dto=20validation=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AvatarItemControllerTest.java | 89 +++++++++++++++++-- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java index d1702f51..3def0c19 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -3,11 +3,15 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.nio.charset.StandardCharsets; import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.service.AvatarItemService; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -32,22 +36,89 @@ class AvatarItemControllerTest { @Test @WithMockUser - @DisplayName("아바타 이미지 업로드 api 테스트") + @DisplayName("아바타 이미지를 정상적으로 등록한다.") public void imageUploadTest() throws Exception { //given MockMultipartFile file = new MockMultipartFile("file", "filename.txt", - "text/plain", "some xml".getBytes()); - AvatarItemRequest request = new AvatarItemRequest("HAIR", true); - String requestJson = objectMapper.writeValueAsString(request); + "image/jpeg", "some xml".getBytes()); + AvatarItemRequest requestDto = new AvatarItemRequest("HAIR", true); + MockMultipartFile request = new MockMultipartFile("request", "filename.txt", + "application/json", objectMapper.writeValueAsBytes(requestDto)); //when, then - mockMvc.perform(multipart("/api/v1/image") + mockMvc.perform(multipart("/api/v1/avatar-items") .file(file) - .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .content(requestJson) - .contentType(MediaType.APPLICATION_JSON) - .characterEncoding("utf-8")) + .file(request) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8)) .andExpect(status().isCreated()); } + @WithMockUser + @ParameterizedTest(name = "[{index}] content-type 이 {0}인 경우") + @ValueSource(strings = {"text/plain", "application/json"}) + @DisplayName("아바타 이미지 업로드 시 파일의 유형이 이미지가 아닌 경우 에러가 난다.") + public void imageUpLoadWithInvalidContentType(String contentType) throws Exception { + //given + MockMultipartFile file = new MockMultipartFile("file", "filename.txt", + contentType, "some xml".getBytes()); + AvatarItemRequest dto = new AvatarItemRequest("HAIR", true); + MockMultipartFile requestDto = new MockMultipartFile("request", "filename.json", + MediaType.APPLICATION_JSON_VALUE, objectMapper.writeValueAsBytes(dto)); + + //when, then + mockMvc.perform(multipart("/api/v1/avatar-items") + .file(file) + .file(requestDto) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8)) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser + @DisplayName("아바타 이미지 업로드 시 이미지 파일이 없는 경우 에러가 발생한다.") + public void noImageUpLoad() throws Exception { + //given + MockMultipartFile file = new MockMultipartFile("file", "", "image/png", new byte[0]); + AvatarItemRequest dto = new AvatarItemRequest("HAIR", true); + MockMultipartFile requestDto = new MockMultipartFile("request", "filename.json", + MediaType.APPLICATION_JSON_VALUE, objectMapper.writeValueAsBytes(dto)); + + + //when, then + mockMvc.perform(multipart("/api/v1/avatar-items") + .file(file) + .file(requestDto) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8)) + .andExpect(status().isBadRequest()); + } + + @WithMockUser + @ParameterizedTest(name = "[{index}] item type으로 {0}가 들어오는 경우") + @ValueSource(strings = {"afsee", "", " ", "hair"}) + @NullSource + @DisplayName("아바타 이미지 업로드 시 아이템 타입이 존재하지 않는 경우 에러가 난다.") + public void UpLoadWithInvalidRequest(String type) throws Exception { + //given + MockMultipartFile file = new MockMultipartFile("file", "filename.txt", + "image/jpeg", "some xml".getBytes()); + AvatarItemRequest requestDto = new AvatarItemRequest(type, true); + MockMultipartFile request = new MockMultipartFile("request", "filename.txt", + "application/json", objectMapper.writeValueAsBytes(requestDto)); + + + //when, then + mockMvc.perform(multipart("/api/v1/avatar-items") + .file(file) + .file(request) + .contentType(MediaType.MULTIPART_FORM_DATA) + .accept(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8)) + .andExpect(status().isBadRequest()); + } } From 4d46d248fc29a860b0ba588d9868c6cd8962f4b2 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Sat, 6 Jan 2024 21:14:40 +0900 Subject: [PATCH 10/47] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20error=20=EC=A7=80=EC=9A=B0?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존에 Enum type으로 requestDto에서 값을 받을 때 Enum에 존재하지 않는 값을 받으면 삭제한 에러가 나오는 현상이 있었는데 지금은 String으로 바꿔서 사용하지 않아 삭제 --- .../backendoori/ootw/exception/ErrorMessage.java | 15 --------------- .../ootw/exception/GlobalControllerAdvice.java | 9 --------- 2 files changed, 24 deletions(-) delete mode 100644 src/main/java/com/backendoori/ootw/exception/ErrorMessage.java diff --git a/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java b/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java deleted file mode 100644 index 35ac114d..00000000 --- a/src/main/java/com/backendoori/ootw/exception/ErrorMessage.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.backendoori.ootw.exception; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum ErrorMessage { - - JSON_CONVERT_ERROR("해당 요청을 읽을 수 없습니다."); - - private final String message; - -} diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index bbd06f7d..544aa0ee 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -7,7 +7,6 @@ import org.springframework.dao.DuplicateKeyException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -54,14 +53,6 @@ public ResponseEntity handlerMethodValidationException(HandlerMet .body(errorResponse); } - @ExceptionHandler(HttpMessageNotReadableException.class) - public ResponseEntity httpMessageNotReadableException(HttpMessageNotReadableException e) { - ErrorResponse errorResponse = new ErrorResponse(ErrorMessage.JSON_CONVERT_ERROR.getMessage()); - - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(errorResponse); - } - @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity>> handleMethodArgumentNotValidException( MethodArgumentNotValidException e From 20d9f38569411fc74581b54eaa7248ec139c2a16 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:44:02 +0900 Subject: [PATCH 11/47] =?UTF-8?q?style:=20Test=20class=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ServiceImplTestValid.java => MiniOImageServiceImplTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/com/backendoori/ootw/common/image/{MiniOImageServiceImplTestValid.java => MiniOImageServiceImplTest.java} (96%) diff --git a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java similarity index 96% rename from src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java rename to src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java index 2498a7e8..7eba159f 100644 --- a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTestValid.java +++ b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java @@ -12,7 +12,7 @@ @SpringBootTest @AutoConfigureMockMvc -class MiniOImageServiceImplTestValid { +class MiniOImageServiceImplTest { @Autowired MockMvc mockMvc; From 89e85ec501b8325fa0b922bd539eb76e3e2ab594 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:44:34 +0900 Subject: [PATCH 12/47] =?UTF-8?q?feat:=20ImageUpload=20=EC=8B=9C=20?= =?UTF-8?q?=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20Exception=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/common/image/MiniOImageServiceImpl.java | 5 +++-- .../ootw/exception/GlobalControllerAdvice.java | 13 ++++++++----- .../ootw/exception/ImageUploadException.java | 12 ++++++++++++ 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/backendoori/ootw/exception/ImageUploadException.java diff --git a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java b/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java index 97138a29..a0634ca2 100644 --- a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java +++ b/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java @@ -4,6 +4,7 @@ import java.nio.file.Path; import java.util.concurrent.TimeUnit; import com.backendoori.ootw.config.MiniOConfig; +import com.backendoori.ootw.exception.ImageUploadException; import io.minio.GetPresignedObjectUrlArgs; import io.minio.MinioClient; import io.minio.PutObjectArgs; @@ -37,7 +38,7 @@ public String uploadImage(MultipartFile file) { .build(); minioClient.putObject(args); } catch (Exception e) { - log.warn("Exception occurred while saving contents : {}", e.getMessage(), e); + throw new ImageUploadException(); } return getUrl(); @@ -54,7 +55,7 @@ private String getUrl() { .expiry(12, TimeUnit.HOURS) .build()); } catch (Exception e) { - log.warn("Exception Occurred while getting: {}", e.getMessage(), e); + throw new ImageUploadException(); } return url; diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 544aa0ee..5191e4c8 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -55,20 +55,23 @@ public ResponseEntity handlerMethodValidationException(HandlerMet @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity>> handleMethodArgumentNotValidException( - MethodArgumentNotValidException e - ) { + MethodArgumentNotValidException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(ExceptionResponse.from(e)); } @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity> handleIllegalArgumentException( - IllegalArgumentException e - ) { + public ResponseEntity> handleIllegalArgumentException(IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(ExceptionResponse.from(e)); } + @ExceptionHandler(ImageUploadException.class) + public ResponseEntity> handleImageUploadException(ImageUploadException e) { + return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY) + .body(ExceptionResponse.from(e)); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); diff --git a/src/main/java/com/backendoori/ootw/exception/ImageUploadException.java b/src/main/java/com/backendoori/ootw/exception/ImageUploadException.java new file mode 100644 index 00000000..b9646bc0 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/exception/ImageUploadException.java @@ -0,0 +1,12 @@ +package com.backendoori.ootw.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class ImageUploadException extends RuntimeException{ + + private final String message = "이미지 업로드 중 예외가 발생했습니다."; + +} From 61313307189c06c24326bfeb88999ef1218ecfb4 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:45:13 +0900 Subject: [PATCH 13/47] =?UTF-8?q?refactor:=20stream=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EA=B0=84=EA=B2=B0=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/common/validation/ItemTypeValidator.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java index eca40f2b..1e848d3b 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java +++ b/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java @@ -20,14 +20,9 @@ public boolean isValid(String type, ConstraintValidatorContext context) { if (type == null) { return false; } - List enumList = Arrays.stream(Type.class.getEnumConstants()) - .map(Enum::name) - .toList(); - if (!enumList.contains(type)) { - return false; - } - return true; + return Arrays.stream(Type.class.getEnumConstants()) + .anyMatch(e -> e.name().equals(type)); } } From fc069b3533be998973843a08c2dcacc364526ac1 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:45:56 +0900 Subject: [PATCH 14/47] =?UTF-8?q?style:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=AA=85=20=EA=B0=80=EB=8F=85=EC=84=B1=20=EC=A2=8B=EA=B2=8C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD(@DisplyName)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/avatar/controller/AvatarItemControllerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java index 3def0c19..861a199a 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -58,7 +58,7 @@ public void imageUploadTest() throws Exception { @WithMockUser @ParameterizedTest(name = "[{index}] content-type 이 {0}인 경우") @ValueSource(strings = {"text/plain", "application/json"}) - @DisplayName("아바타 이미지 업로드 시 파일의 유형이 이미지가 아닌 경우 에러가 난다.") + @DisplayName("아바타 이미지 업로드 시 파일의 유형이 이미지가 아닌 경우 예외가 발생한다.") public void imageUpLoadWithInvalidContentType(String contentType) throws Exception { //given MockMultipartFile file = new MockMultipartFile("file", "filename.txt", @@ -79,7 +79,7 @@ public void imageUpLoadWithInvalidContentType(String contentType) throws Excepti @Test @WithMockUser - @DisplayName("아바타 이미지 업로드 시 이미지 파일이 없는 경우 에러가 발생한다.") + @DisplayName("아바타 이미지 업로드 시 이미지 파일이 없는 경우 예외가 발생한다.") public void noImageUpLoad() throws Exception { //given MockMultipartFile file = new MockMultipartFile("file", "", "image/png", new byte[0]); @@ -102,7 +102,7 @@ public void noImageUpLoad() throws Exception { @ParameterizedTest(name = "[{index}] item type으로 {0}가 들어오는 경우") @ValueSource(strings = {"afsee", "", " ", "hair"}) @NullSource - @DisplayName("아바타 이미지 업로드 시 아이템 타입이 존재하지 않는 경우 에러가 난다.") + @DisplayName("아바타 이미지 업로드 시 아이템 타입이 존재하지 않는 경우 예외가 발생한다.") public void UpLoadWithInvalidRequest(String type) throws Exception { //given MockMultipartFile file = new MockMultipartFile("file", "filename.txt", From 61a2d06848e1a3bf6549616d138e60a2254546f2 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:59:42 +0900 Subject: [PATCH 15/47] =?UTF-8?q?refactor:=20file=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=A6=88=20=EC=84=A4=EC=A0=95=20yaml=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=97=90=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 직접 bean 생성 -> yaml 파일 등록 --- .idea/codeStyles/codeStyleConfig.xml | 4 +-- .../ootw/common/image/MultipartConfig.java | 27 ------------------- src/main/resources/application.yaml | 4 +++ 3 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index c5678b63..41aee021 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,5 @@ - - + \ No newline at end of file diff --git a/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java b/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java deleted file mode 100644 index 2568e3eb..00000000 --- a/src/main/java/com/backendoori/ootw/common/image/MultipartConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.backendoori.ootw.common.image; - -import jakarta.servlet.MultipartConfigElement; -import org.springframework.boot.web.servlet.MultipartConfigFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.unit.DataSize; -import org.springframework.web.multipart.MultipartResolver; -import org.springframework.web.multipart.support.StandardServletMultipartResolver; - -@Configuration -public class MultipartConfig { - - @Bean - public MultipartResolver multipartResolver() { - return new StandardServletMultipartResolver(); - } - - @Bean - public MultipartConfigElement multipartConfigElement() { - MultipartConfigFactory factory = new MultipartConfigFactory(); - factory.setMaxRequestSize(DataSize.ofMegabytes(10L)); - factory.setMaxFileSize(DataSize.ofMegabytes(10L)); - - return factory.createMultipartConfig(); - } -} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 38cd9025..54ffb834 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -8,6 +8,10 @@ spring: hibernate: ddl-auto: validate open-in-view: false + servlet: + multipart: + max-file-size: 10MB + maxRequestSize: 10MB minio: url: ${MINIO_URL} bucket: ${MINIO_BUCKET} From 693dd2a1d4992106613e9ebe1f850203da18fbc0 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 04:38:06 +0900 Subject: [PATCH 16/47] =?UTF-8?q?feat:=20user=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=8B=9C=20email=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/backendoori/ootw/user/dto/SignupDto.java | 3 +-- .../java/com/backendoori/ootw/user/service/UserService.java | 1 - .../com/backendoori/ootw/post/service/PostServiceTest.java | 3 --- .../backendoori/ootw/user/controller/UserControllerTest.java | 2 +- .../com/backendoori/ootw/user/service/UserServiceTest.java | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index fea29628..956f35ed 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -3,8 +3,7 @@ public record SignupDto( String email, String password, - String nickname, - String image + String nickname ) { } diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 72707bc9..52c655c4 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -36,7 +36,6 @@ public UserDto signup(SignupDto signupDto) { .email(signupDto.email()) .password(passwordEncoder.encode(signupDto.password())) .nickname(signupDto.nickname()) - .image(signupDto.image()) .build(); userRepository.save(user); diff --git a/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java b/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java index 028d19b4..3f8aff68 100644 --- a/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java +++ b/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java @@ -109,9 +109,6 @@ void saveFailUserNotFound() { // given setAuthentication(user.getId() + 1); - System.out.println(user.getId() + 1); - System.out.println(userRepository.findAll().stream().map(User::getId).toList()); - WeatherDto weatherDto = new WeatherDto(0.0, -10.0, 10.0, 1, 1); PostSaveRequest postSaveRequest = diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index a7e42092..46ce8f2e 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -170,7 +170,7 @@ private SignupDto generateSignupDto() { String nickname = faker.internet().username(); String image = faker.internet().url(); - return new SignupDto(email, password, nickname, image); + return new SignupDto(email, password, nickname); } private UserDto createUser(SignupDto signupDto) { diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index 7f36f59f..b6ae5b97 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -140,7 +140,7 @@ private SignupDto generateSignupDto() { String nickname = faker.internet().username(); String image = faker.internet().url(); - return new SignupDto(email, password, nickname, image); + return new SignupDto(email, password, nickname); } private User generateUser(String password) { From 7679024f1a36e8a9b7b03ecacbaf35e3b78262e6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:20:48 +0900 Subject: [PATCH 17/47] =?UTF-8?q?feat:=20assert=20util=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/common/AssertUtil.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/common/AssertUtil.java diff --git a/src/main/java/com/backendoori/ootw/common/AssertUtil.java b/src/main/java/com/backendoori/ootw/common/AssertUtil.java new file mode 100644 index 00000000..e083b4e2 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/common/AssertUtil.java @@ -0,0 +1,33 @@ +package com.backendoori.ootw.common; + +import java.util.Objects; +import java.util.function.Supplier; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class AssertUtil extends Assert { + + public static void notBlank(@Nullable String string, String message) { + if (string == null || string.isBlank()) { + throw new IllegalArgumentException(message); + } + } + + public static void hasPattern(@Nullable String string, @Nullable String pattern, String message) { + notNull(string, message); + + if (!string.matches(Objects.requireNonNull(pattern))) { + throw new IllegalArgumentException(message); + } + } + + public static void throwIf(boolean state, Supplier exceptionSupplier) { + if (state) { + throw exceptionSupplier.get(); + } + } + +} From 6d8f183e9ac1118237fdb1df4bfe17f9d7d7af17 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:21:22 +0900 Subject: [PATCH 18/47] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=9C=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/validation/RFC5322.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/user/validation/RFC5322.java diff --git a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java new file mode 100644 index 00000000..8e44b1ec --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java @@ -0,0 +1,12 @@ +package com.backendoori.ootw.user.validation; + +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RFC5322 { + + public static final String REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; + +} From 59dcee680815f05c0dc0f0c42dae62145b6295d2 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:22:13 +0900 Subject: [PATCH 19/47] =?UTF-8?q?feat:=20dto=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20annotation=EA=B3=BC=20validator=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 메시지를 담은 상수 클래스도 추가 --- .../ootw/user/validation/Message.java | 18 ++++++++++ .../ootw/user/validation/Password.java | 23 ++++++++++++ .../user/validation/PasswordValidator.java | 35 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/user/validation/Message.java create mode 100644 src/main/java/com/backendoori/ootw/user/validation/Password.java create mode 100644 src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java diff --git a/src/main/java/com/backendoori/ootw/user/validation/Message.java b/src/main/java/com/backendoori/ootw/user/validation/Message.java new file mode 100644 index 00000000..04bf0676 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/Message.java @@ -0,0 +1,18 @@ +package com.backendoori.ootw.user.validation; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class Message { + + public static final String INVALID_EMAIL = "이메일 형식이 올바르지 않습니다."; + + public static final String INVALID_PASSWORD = "비밀번호는 숫자, 영문자, 특수문자를 포함한 " + + PasswordValidator.MIN_SIZE + "자 이상, " + + PasswordValidator.MAX_SIZE + "자 이내의 문자여야 합니다."; + + public static final String BLANK_PASSWORD = "비밀번호는 공백일 수 없습니다."; + public static final String BLANK_NICKNAME = "닉네임은 공백일 수 없습니다."; + +} diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java new file mode 100644 index 00000000..f3a0c02a --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -0,0 +1,23 @@ +package com.backendoori.ootw.user.validation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +@Documented +@Constraint(validatedBy = PasswordValidator.class) +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Password { + + String message() default Message.INVALID_PASSWORD; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java new file mode 100644 index 00000000..2cdf2fb8 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -0,0 +1,35 @@ +package com.backendoori.ootw.user.validation; + +import java.util.Objects; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class PasswordValidator implements ConstraintValidator { + + public static final int MIN_SIZE = 8; + public static final int MAX_SIZE = 30; + public static final String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; + + @Override + public boolean isValid(String password, ConstraintValidatorContext context) { + if (Objects.isNull(password) || password.isBlank()) { + return violateWithMessage(context, Message.BLANK_PASSWORD); + } + + if (!password.matches(PATTERN)) { + return violateWithMessage(context, Message.INVALID_PASSWORD); + } + + return true; + } + + private boolean violateWithMessage(ConstraintValidatorContext context, String message) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message) + .addConstraintViolation(); + + return false; + } + +} From 9286e2bf6176f01a5278efcd237d547494cfe05a Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:23:14 +0900 Subject: [PATCH 20/47] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20dto=EC=97=90=20validation=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/dto/SignupDto.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index 956f35ed..f53c5008 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -1,8 +1,23 @@ package com.backendoori.ootw.user.dto; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.Password; +import com.backendoori.ootw.user.validation.RFC5322; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + public record SignupDto( + @NotNull + @Email(regexp = RFC5322.REGEX) String email, + + @NotNull + @Password String password, + + @NotNull + @NotBlank(message = Message.BLANK_NICKNAME) String nickname ) { From b2f4dad4bcdc2550c4972660158a93e703b783f8 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:23:34 +0900 Subject: [PATCH 21/47] =?UTF-8?q?feat:=20user=20entity=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20validation=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/domain/User.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/domain/User.java b/src/main/java/com/backendoori/ootw/user/domain/User.java index 6fdecfff..a50d51ed 100644 --- a/src/main/java/com/backendoori/ootw/user/domain/User.java +++ b/src/main/java/com/backendoori/ootw/user/domain/User.java @@ -1,6 +1,9 @@ package com.backendoori.ootw.user.domain; +import com.backendoori.ootw.common.AssertUtil; import com.backendoori.ootw.common.BaseEntity; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.RFC5322; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -8,7 +11,6 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AccessLevel; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -18,7 +20,6 @@ @Getter @Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) public class User extends BaseEntity { @Id @@ -38,4 +39,16 @@ public class User extends BaseEntity { @Column(name = "image") private String image; + public User(Long id, String email, String password, String nickname, String image) { + AssertUtil.hasPattern(email, RFC5322.REGEX, Message.INVALID_EMAIL); + AssertUtil.notBlank(password,Message.BLANK_PASSWORD); + AssertUtil.notBlank(nickname, Message.BLANK_NICKNAME); + + this.id = id; + this.email = email; + this.password = password; + this.nickname = nickname; + this.image = image; + } + } From fb86531ad414eb694c8a20b866ac7d4d183691b6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:24:17 +0900 Subject: [PATCH 22/47] =?UTF-8?q?feat:=20service=EC=97=90=EC=84=9C=20user?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20password=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/service/UserService.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 52c655c4..747143e0 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -1,5 +1,7 @@ package com.backendoori.ootw.user.service; +import java.util.Objects; +import com.backendoori.ootw.common.AssertUtil; import com.backendoori.ootw.exception.AlreadyExistEmailException; import com.backendoori.ootw.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; @@ -10,6 +12,9 @@ import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.repository.UserRepository; +import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.PasswordValidator; +import com.backendoori.ootw.user.validation.RFC5322; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -28,15 +33,10 @@ public UserDto signup(SignupDto signupDto) { boolean isAlreadyExistEmail = userRepository.findByEmail(signupDto.email()) .isPresent(); - if (isAlreadyExistEmail) { - throw new AlreadyExistEmailException(); - } + AssertUtil.throwIf(isAlreadyExistEmail, AlreadyExistEmailException::new); + AssertUtil.isTrue(isValidPassword(signupDto.password()), Message.INVALID_PASSWORD); - User user = User.builder() - .email(signupDto.email()) - .password(passwordEncoder.encode(signupDto.password())) - .nickname(signupDto.nickname()) - .build(); + User user = buildUser(signupDto); userRepository.save(user); @@ -46,14 +46,29 @@ public UserDto signup(SignupDto signupDto) { public TokenDto login(LoginDto loginDto) { User user = userRepository.findByEmail(loginDto.email()) .orElseThrow(UserNotFoundException::new); + boolean isIncorrectPassword = !matchPassword(loginDto.password(), user.getPassword()); - if (!passwordEncoder.matches(loginDto.password(), user.getPassword())) { - throw new IncorrectPasswordException(); - } + AssertUtil.throwIf(isIncorrectPassword, IncorrectPasswordException::new); String token = tokenProvider.createToken(user.getId()); return new TokenDto(token); } + private User buildUser(SignupDto signupDto) { + return User.builder() + .email(signupDto.email()) + .password(passwordEncoder.encode(signupDto.password())) + .nickname(signupDto.nickname()) + .build(); + } + + private boolean matchPassword(String decrypted, String encrypted) { + return passwordEncoder.matches(decrypted, encrypted); + } + + private boolean isValidPassword(String password) { + return Objects.nonNull(password) && password.matches(PasswordValidator.PATTERN); + } + } From 9e1cc983a6da6335fb31edbce894555af0644653 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:24:46 +0900 Subject: [PATCH 23/47] =?UTF-8?q?test:=20user=20entity=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/domain/UserTest.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/test/java/com/backendoori/ootw/user/domain/UserTest.java diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java new file mode 100644 index 00000000..2d3bbdba --- /dev/null +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -0,0 +1,120 @@ +package com.backendoori.ootw.user.domain; + +import static org.assertj.core.api.Assertions.assertThatException; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.util.stream.Stream; +import com.backendoori.ootw.user.validation.Message; +import net.datafaker.Faker; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; + +class UserTest { + + static final Faker faker = new Faker(); + + Long id; + String email; + String password; + String nickname; + String image; + + @BeforeEach + void setup() { + id = (long) faker.number().positive(); + email = faker.internet().emailAddress(); + password = faker.internet().password(); + nickname = faker.internet().username(); + image = faker.internet().url(); + } + + @DisplayName("instance 생성에 성공한다.") + @Test + void testCreate() { + // given + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatNoException().isThrownBy(createUser); + } + + @DisplayName("잘못된 형식의 이메일인 경우 생성에 실패한다.") + @NullAndEmptySource + @MethodSource("generateInvalidEmails") + @ParameterizedTest() + void testCreateInvalidEmail(String email) { + // given + this.email = email; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.INVALID_EMAIL); + } + + @DisplayName("비밀번호가 공백인 경우 생성에 실패한다.") + @NullAndEmptySource + @ParameterizedTest + void testCreateBlankPassword(String password) { + // given + this.password = password; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.BLANK_PASSWORD); + } + + @DisplayName("닉네임이 공백인 경우 생성에 실패한다.") + @NullAndEmptySource + @ParameterizedTest + void testCreateBlankNickName(String nickname) { + // given + this.nickname = nickname; + + // when + ThrowingCallable createUser = this::buildUser; + + // then + assertThatIllegalArgumentException() + .isThrownBy(createUser) + .withMessage(Message.BLANK_NICKNAME); + } + + private static Stream generateInvalidEmails() { + return Stream.of( + Arguments.of(faker.app().name()), + Arguments.of(faker.name().fullName()), + Arguments.of(faker.internet().url()), + Arguments.of(faker.internet().domainName()), + Arguments.of(faker.internet().webdomain()), + Arguments.of(faker.internet().botUserAgentAny()) + ); + } + + private User buildUser() { + return User.builder() + .id(id) + .email(email) + .password(password) + .nickname(nickname) + .image(image) + .build(); + } + +} From 9acff2b591b776a0f38d8392e5eda1cba9d90cdd Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:49:17 +0900 Subject: [PATCH 24/47] =?UTF-8?q?refactor:=20exception=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => user}/exception/AlreadyExistEmailException.java | 2 +- .../{ => user}/exception/IncorrectPasswordException.java | 2 +- .../com/backendoori/ootw/user/service/UserService.java | 5 ++--- .../ootw/user/controller/UserControllerTest.java | 4 ++-- .../com/backendoori/ootw/user/service/UserServiceTest.java | 7 +++---- 5 files changed, 9 insertions(+), 11 deletions(-) rename src/main/java/com/backendoori/ootw/{ => user}/exception/AlreadyExistEmailException.java (87%) rename src/main/java/com/backendoori/ootw/{ => user}/exception/IncorrectPasswordException.java (87%) diff --git a/src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java b/src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java similarity index 87% rename from src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java rename to src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java index 16ae8ab6..d8ec3ae4 100644 --- a/src/main/java/com/backendoori/ootw/exception/AlreadyExistEmailException.java +++ b/src/main/java/com/backendoori/ootw/user/exception/AlreadyExistEmailException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.exception; +package com.backendoori.ootw.user.exception; import org.springframework.dao.DuplicateKeyException; diff --git a/src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java b/src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java similarity index 87% rename from src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java rename to src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java index cea57a9b..474f996e 100644 --- a/src/main/java/com/backendoori/ootw/exception/IncorrectPasswordException.java +++ b/src/main/java/com/backendoori/ootw/user/exception/IncorrectPasswordException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.exception; +package com.backendoori.ootw.user.exception; import org.springframework.security.core.AuthenticationException; diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 747143e0..e3c77242 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -2,8 +2,8 @@ import java.util.Objects; import com.backendoori.ootw.common.AssertUtil; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.domain.User; @@ -14,7 +14,6 @@ import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.PasswordValidator; -import com.backendoori.ootw.user.validation.RFC5322; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index 46ce8f2e..012612d2 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -10,8 +10,8 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.dto.LoginDto; diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index b6ae5b97..da05966e 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -4,8 +4,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatNoException; -import com.backendoori.ootw.exception.AlreadyExistEmailException; -import com.backendoori.ootw.exception.IncorrectPasswordException; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.user.domain.User; import com.backendoori.ootw.user.dto.LoginDto; @@ -136,9 +136,8 @@ void failIncorrectPassword() { private SignupDto generateSignupDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); - String image = faker.internet().url(); return new SignupDto(email, password, nickname); } From 98a4d1e02a34d54c28615cae5029dbe2ba48b7f6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:49:36 +0900 Subject: [PATCH 25/47] =?UTF-8?q?style:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20import=20=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/backendoori/ootw/user/validation/RFC5322.java | 1 - src/test/java/com/backendoori/ootw/user/domain/UserTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java index 8e44b1ec..1180e8f2 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java +++ b/src/main/java/com/backendoori/ootw/user/validation/RFC5322.java @@ -1,6 +1,5 @@ package com.backendoori.ootw.user.validation; -import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java index 2d3bbdba..1444316e 100644 --- a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -1,6 +1,5 @@ package com.backendoori.ootw.user.domain; -import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; From d5881edfa0a6642befe5b5fbe5295c3fbfb21a63 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 07:52:48 +0900 Subject: [PATCH 26/47] =?UTF-8?q?refactor:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EA=B4=80=EB=A0=A8=20=EC=83=81=EC=88=98=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/service/UserService.java | 3 ++- .../java/com/backendoori/ootw/user/validation/Message.java | 4 ++-- .../com/backendoori/ootw/user/validation/Password.java | 5 +++++ .../ootw/user/validation/PasswordValidator.java | 7 +------ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index e3c77242..d9e3b047 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -13,6 +13,7 @@ import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; +import com.backendoori.ootw.user.validation.Password; import com.backendoori.ootw.user.validation.PasswordValidator; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; @@ -67,7 +68,7 @@ private boolean matchPassword(String decrypted, String encrypted) { } private boolean isValidPassword(String password) { - return Objects.nonNull(password) && password.matches(PasswordValidator.PATTERN); + return Objects.nonNull(password) && password.matches(Password.PATTERN); } } diff --git a/src/main/java/com/backendoori/ootw/user/validation/Message.java b/src/main/java/com/backendoori/ootw/user/validation/Message.java index 04bf0676..22e4f08b 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Message.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Message.java @@ -9,8 +9,8 @@ public final class Message { public static final String INVALID_EMAIL = "이메일 형식이 올바르지 않습니다."; public static final String INVALID_PASSWORD = "비밀번호는 숫자, 영문자, 특수문자를 포함한 " - + PasswordValidator.MIN_SIZE + "자 이상, " - + PasswordValidator.MAX_SIZE + "자 이내의 문자여야 합니다."; + + Password.MIN_SIZE + "자 이상, " + + Password.MAX_SIZE + "자 이내의 문자여야 합니다."; public static final String BLANK_PASSWORD = "비밀번호는 공백일 수 없습니다."; public static final String BLANK_NICKNAME = "닉네임은 공백일 수 없습니다."; diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java index f3a0c02a..32f02ba9 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Password.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -14,6 +14,11 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Password { + int MIN_SIZE = 8; + int MAX_SIZE = 30; + String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; + String message() default Message.INVALID_PASSWORD; Class[] groups() default {}; diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java index 2cdf2fb8..a6c07301 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -6,18 +6,13 @@ public class PasswordValidator implements ConstraintValidator { - public static final int MIN_SIZE = 8; - public static final int MAX_SIZE = 30; - public static final String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + - "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; - @Override public boolean isValid(String password, ConstraintValidatorContext context) { if (Objects.isNull(password) || password.isBlank()) { return violateWithMessage(context, Message.BLANK_PASSWORD); } - if (!password.matches(PATTERN)) { + if (!password.matches(Password.PATTERN)) { return violateWithMessage(context, Message.INVALID_PASSWORD); } From 4bf407825eb2471317dbb7ef4c3cc6777d8ab05d Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:32:41 +0900 Subject: [PATCH 27/47] style: rename field --- .../java/com/backendoori/ootw/user/service/UserService.java | 4 ++-- .../java/com/backendoori/ootw/user/validation/Password.java | 2 +- .../backendoori/ootw/user/validation/PasswordValidator.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index d9e3b047..967aa091 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -14,11 +14,11 @@ import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.Password; -import com.backendoori.ootw.user.validation.PasswordValidator; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; @Service @RequiredArgsConstructor @@ -68,7 +68,7 @@ private boolean matchPassword(String decrypted, String encrypted) { } private boolean isValidPassword(String password) { - return Objects.nonNull(password) && password.matches(Password.PATTERN); + return StringUtils.hasLength(password) && password.matches(Password.REGEX); } } diff --git a/src/main/java/com/backendoori/ootw/user/validation/Password.java b/src/main/java/com/backendoori/ootw/user/validation/Password.java index 32f02ba9..764f3095 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/Password.java +++ b/src/main/java/com/backendoori/ootw/user/validation/Password.java @@ -16,7 +16,7 @@ int MIN_SIZE = 8; int MAX_SIZE = 30; - String PATTERN = "^(?=.*[A-Za-z])(?=.*[0-9])(?=.*[$@$!%%*#?&])[A-Za-z[0-9]$@$!%%*#?&]" + + String REGEX = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&^])[A-Za-z\\d@$!%*#?&^]" + "{" + MIN_SIZE + "," + MAX_SIZE + "}$"; String message() default Message.INVALID_PASSWORD; diff --git a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java index a6c07301..2fb653e8 100644 --- a/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java +++ b/src/main/java/com/backendoori/ootw/user/validation/PasswordValidator.java @@ -12,7 +12,7 @@ public boolean isValid(String password, ConstraintValidatorContext context) { return violateWithMessage(context, Message.BLANK_PASSWORD); } - if (!password.matches(Password.PATTERN)) { + if (!password.matches(Password.REGEX)) { return violateWithMessage(context, Message.INVALID_PASSWORD); } From bb578b2c40639932c4241e62f6e74a59fcdabd3d Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:32:59 +0900 Subject: [PATCH 28/47] =?UTF-8?q?test:=20user=20service=20=EB=B9=84?= =?UTF-8?q?=EB=B0=80=EB=B2=88=ED=98=B8=20=EA=B2=80=EC=A6=9D=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/service/UserServiceTest.java | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java index da05966e..401f3c7b 100644 --- a/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java +++ b/src/test/java/com/backendoori/ootw/user/service/UserServiceTest.java @@ -1,17 +1,21 @@ package com.backendoori.ootw.user.service; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatException; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatNoException; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; +import java.util.stream.Stream; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.user.domain.User; import com.backendoori.ootw.user.dto.LoginDto; import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.repository.UserRepository; +import com.backendoori.ootw.user.validation.Message; import net.datafaker.Faker; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.AfterEach; @@ -21,6 +25,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.crypto.password.PasswordEncoder; @@ -73,10 +81,37 @@ void failAlreadyExistUser() { ThrowingCallable signup = () -> userService.signup(signupDto); // then - assertThatExceptionOfType(AlreadyExistEmailException.class).isThrownBy(signup) + assertThatExceptionOfType(AlreadyExistEmailException.class) + .isThrownBy(signup) .withMessage(AlreadyExistEmailException.DEFAULT_MESSAGE); } + @DisplayName("비밀번호 형식이 올바르지 않을 경우 회원가입에 실패한다") + @NullAndEmptySource + @MethodSource("generateInvalidPasswords") + @ParameterizedTest + void failInvalidPassword(String password) { + // given + SignupDto signupDto = generateSignupDto(password); + + // when + ThrowingCallable signup = () -> userService.signup(signupDto); + + // then + assertThatIllegalArgumentException() + .isThrownBy(signup) + .withMessage(Message.INVALID_PASSWORD); + } + + private static Stream generateInvalidPasswords() { + return Stream.of( + faker.internet().password(1, 7, true, true, true), + faker.internet().password(31, 50, true, true, true), + faker.internet().password(8, 30, true, false, true), + faker.internet().password(8, 30, true, true, false) + ); + } + } @DisplayName("로그인 테스트") @@ -95,14 +130,15 @@ void success() { TokenDto tokenDto = userService.login(loginDto); // then - assertThat(tokenDto.token()).isInstanceOf(String.class) + assertThat(tokenDto.token()) + .isInstanceOf(String.class) .isNotNull() .isNotBlank(); } @DisplayName("email이 일치하는 사용자가 없으면 로그인에 실패한다") @Test - void failNotExistUser() { + void failUserNotFound() { // given String password = faker.internet().password(); User user = generateUser(password); @@ -112,7 +148,8 @@ void failNotExistUser() { ThrowingCallable login = () -> userService.login(loginDto); // then - assertThatExceptionOfType(UserNotFoundException.class).isThrownBy(login) + assertThatExceptionOfType(UserNotFoundException.class) + .isThrownBy(login) .withMessage(UserNotFoundException.DEFAULT_MESSAGE); } @@ -128,15 +165,19 @@ void failIncorrectPassword() { ThrowingCallable login = () -> userService.login(loginDto); // then - assertThatExceptionOfType(IncorrectPasswordException.class).isThrownBy(login) + assertThatExceptionOfType(IncorrectPasswordException.class) + .isThrownBy(login) .withMessage(IncorrectPasswordException.DEFAULT_MESSAGE); } } private SignupDto generateSignupDto() { + return generateSignupDto(faker.internet().password(8, 30, true, true, true)); + } + + private SignupDto generateSignupDto(String password) { String email = faker.internet().emailAddress(); - String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); return new SignupDto(email, password, nickname); From 4b3322e16a316f1e90f3de669d98e01dde18a7f6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:34:52 +0900 Subject: [PATCH 29/47] style: reformat file --- src/main/java/com/backendoori/ootw/user/domain/User.java | 2 +- .../java/com/backendoori/ootw/user/service/UserService.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/user/domain/User.java b/src/main/java/com/backendoori/ootw/user/domain/User.java index a50d51ed..35f4a99a 100644 --- a/src/main/java/com/backendoori/ootw/user/domain/User.java +++ b/src/main/java/com/backendoori/ootw/user/domain/User.java @@ -41,7 +41,7 @@ public class User extends BaseEntity { public User(Long id, String email, String password, String nickname, String image) { AssertUtil.hasPattern(email, RFC5322.REGEX, Message.INVALID_EMAIL); - AssertUtil.notBlank(password,Message.BLANK_PASSWORD); + AssertUtil.notBlank(password, Message.BLANK_PASSWORD); AssertUtil.notBlank(nickname, Message.BLANK_NICKNAME); this.id = id; diff --git a/src/main/java/com/backendoori/ootw/user/service/UserService.java b/src/main/java/com/backendoori/ootw/user/service/UserService.java index 967aa091..082615bc 100644 --- a/src/main/java/com/backendoori/ootw/user/service/UserService.java +++ b/src/main/java/com/backendoori/ootw/user/service/UserService.java @@ -1,9 +1,6 @@ package com.backendoori.ootw.user.service; -import java.util.Objects; import com.backendoori.ootw.common.AssertUtil; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.domain.User; @@ -11,6 +8,8 @@ import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.repository.UserRepository; import com.backendoori.ootw.user.validation.Message; import com.backendoori.ootw.user.validation.Password; From 053ab2dc9e9ed30ce7297774060e46764985cf18 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 08:38:55 +0900 Subject: [PATCH 30/47] =?UTF-8?q?feat:=20400=20status=20handler=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/exception/GlobalControllerAdvice.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index aa52b3c9..04509400 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -13,6 +13,14 @@ @RestControllerAdvice public class GlobalControllerAdvice { + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { + ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + @ExceptionHandler(AuthenticationException.class) public ResponseEntity handleAuthenticationException(AuthenticationException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); From 0c38ff0162f0a10f1b908418f7146d5b231fa575 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:16:15 +0900 Subject: [PATCH 31/47] =?UTF-8?q?test:=20=ED=95=84=EC=9A=94=20=EC=97=86?= =?UTF-8?q?=EB=8A=94=20wrapping=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/domain/UserTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java index 1444316e..3f1d58d4 100644 --- a/src/test/java/com/backendoori/ootw/user/domain/UserTest.java +++ b/src/test/java/com/backendoori/ootw/user/domain/UserTest.java @@ -11,7 +11,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.NullAndEmptySource; @@ -95,14 +94,14 @@ void testCreateBlankNickName(String nickname) { .withMessage(Message.BLANK_NICKNAME); } - private static Stream generateInvalidEmails() { + private static Stream generateInvalidEmails() { return Stream.of( - Arguments.of(faker.app().name()), - Arguments.of(faker.name().fullName()), - Arguments.of(faker.internet().url()), - Arguments.of(faker.internet().domainName()), - Arguments.of(faker.internet().webdomain()), - Arguments.of(faker.internet().botUserAgentAny()) + faker.app().name(), + faker.name().fullName(), + faker.internet().url(), + faker.internet().domainName(), + faker.internet().webdomain(), + faker.internet().botUserAgentAny() ); } From 315f3a1225d8130d6424bdba2930cbb64c7e45c6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:16:42 +0900 Subject: [PATCH 32/47] =?UTF-8?q?feat:=20user=20controller=20validation=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/user/controller/UserController.java | 3 ++- src/main/java/com/backendoori/ootw/user/dto/SignupDto.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/user/controller/UserController.java b/src/main/java/com/backendoori/ootw/user/controller/UserController.java index fc97f46d..30a62917 100644 --- a/src/main/java/com/backendoori/ootw/user/controller/UserController.java +++ b/src/main/java/com/backendoori/ootw/user/controller/UserController.java @@ -6,6 +6,7 @@ import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; import com.backendoori.ootw.user.service.UserService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -23,7 +24,7 @@ public class UserController { private final UserService userService; @PostMapping("/signup") - public ResponseEntity signup(@RequestBody SignupDto signupDto) { + public ResponseEntity signup(@RequestBody @Valid SignupDto signupDto) { UserDto userDto = userService.signup(signupDto); return ResponseEntity.status(HttpStatus.CREATED) diff --git a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java index f53c5008..59b368c3 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/SignupDto.java @@ -9,6 +9,7 @@ public record SignupDto( @NotNull + @NotBlank @Email(regexp = RFC5322.REGEX) String email, From 55210c0f029406af16ca463374b5a421369efe03 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:17:27 +0900 Subject: [PATCH 33/47] =?UTF-8?q?feat:=20jakarta=20annotation=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20handler=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalControllerAdvice.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 04509400..721a4671 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -1,11 +1,16 @@ package com.backendoori.ootw.exception; +import java.util.List; import java.util.NoSuchElementException; +import java.util.Objects; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DuplicateKeyException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -21,6 +26,21 @@ public ResponseEntity handleIllegalArgumentException(IllegalArgum .body(errorResponse); } + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + List errors = e.getFieldErrors(); + String message = errors.stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(); + + ErrorResponse errorResponse = new ErrorResponse(message); + + return ResponseEntity.badRequest() + .body(errorResponse); + } + @ExceptionHandler(AuthenticationException.class) public ResponseEntity handleAuthenticationException(AuthenticationException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); @@ -55,4 +75,5 @@ public ResponseEntity handleException(Exception e) { .body(errorResponse); } + } From 222898d24e0a2344168709c127ad78cd89760161 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:18:00 +0900 Subject: [PATCH 34/47] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index 012612d2..a632612c 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -10,20 +10,24 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import com.backendoori.ootw.user.exception.AlreadyExistEmailException; -import com.backendoori.ootw.user.exception.IncorrectPasswordException; +import java.util.stream.Stream; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.security.jwt.TokenProvider; import com.backendoori.ootw.user.dto.LoginDto; import com.backendoori.ootw.user.dto.SignupDto; import com.backendoori.ootw.user.dto.TokenDto; import com.backendoori.ootw.user.dto.UserDto; +import com.backendoori.ootw.user.exception.AlreadyExistEmailException; +import com.backendoori.ootw.user.exception.IncorrectPasswordException; import com.backendoori.ootw.user.service.UserService; import com.fasterxml.jackson.databind.ObjectMapper; import net.datafaker.Faker; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -78,6 +82,27 @@ void created() throws Exception { .andExpect(jsonPath("$.updatedAt", startsWith(removeMills(userDto.updatedAt())))); } + @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") + @NullAndEmptySource + @MethodSource("generateInvalidEmails") + @ParameterizedTest + void badRequestInvalidEmail(String email) throws Exception { + // given + String password = faker.internet().password(8, 30, true, true, true); + String nickname = faker.internet().username(); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { @@ -97,6 +122,17 @@ void unauthorizedAlreadyExistEmail() throws Exception { actions.andExpect(status().isConflict()); } + private static Stream generateInvalidEmails() { + return Stream.of( + faker.app().name(), + faker.name().fullName(), + faker.internet().url(), + faker.internet().domainName(), + faker.internet().webdomain(), + faker.internet().botUserAgentAny() + ); + } + } @DisplayName("로그인 테스트") @@ -166,9 +202,8 @@ void unauthorizedIncorrectPassword() throws Exception { private SignupDto generateSignupDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); String nickname = faker.internet().username(); - String image = faker.internet().url(); return new SignupDto(email, password, nickname); } From ea4877642dc9cdf995a31816de7dea642ac9a516 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:21:04 +0900 Subject: [PATCH 35/47] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=9E=98=EB=AA=BB=EB=90=9C=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=EC=9D=98=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index a632612c..e83cfaaa 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -103,6 +103,27 @@ void badRequestInvalidEmail(String email) throws Exception { actions.andExpect(status().isBadRequest()); } + @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") + @NullAndEmptySource + @MethodSource("generateInvalidPasswords") + @ParameterizedTest + void badRequestInvalidPassword(String password) throws Exception { + // given + String email = faker.internet().emailAddress(); + String nickname = faker.internet().username(); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { @@ -133,6 +154,15 @@ private static Stream generateInvalidEmails() { ); } + private static Stream generateInvalidPasswords() { + return Stream.of( + faker.internet().password(1, 7, true, true, true), + faker.internet().password(31, 50, true, true, true), + faker.internet().password(8, 30, true, false, true), + faker.internet().password(8, 30, true, true, false) + ); + } + } @DisplayName("로그인 테스트") From 091e43a9caeeec7cf9e8e64304e099fa1e8c30d6 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:23:39 +0900 Subject: [PATCH 36/47] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EA=B3=B5=EB=B0=B1=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index e83cfaaa..d140292b 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -124,6 +124,26 @@ void badRequestInvalidPassword(String password) throws Exception { actions.andExpect(status().isBadRequest()); } + @DisplayName("닉네임이 공백일 경우 400 status를 반환한다") + @NullAndEmptySource + @ParameterizedTest + void badRequestBlankNickname(String nickname) throws Exception { + // given + String email = faker.internet().emailAddress(); + String password = faker.internet().password(8, 30, true, true, true); + SignupDto signupDto = new SignupDto(email, password, nickname); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/signup") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signupDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("이미 등록된 email일 경우 409 status를 반환한다") @Test void unauthorizedAlreadyExistEmail() throws Exception { From 4da69ac63c862c88eb1aa12cef31f87802eeea72 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:25:37 +0900 Subject: [PATCH 37/47] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B0=92=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/user/controller/UserController.java | 2 +- .../java/com/backendoori/ootw/user/dto/LoginDto.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/user/controller/UserController.java b/src/main/java/com/backendoori/ootw/user/controller/UserController.java index 30a62917..bf9eb119 100644 --- a/src/main/java/com/backendoori/ootw/user/controller/UserController.java +++ b/src/main/java/com/backendoori/ootw/user/controller/UserController.java @@ -32,7 +32,7 @@ public ResponseEntity signup(@RequestBody @Valid SignupDto signupDto) { } @PostMapping("/login") - public ResponseEntity login(@RequestBody LoginDto loginDto) { + public ResponseEntity login(@RequestBody @Valid LoginDto loginDto) { TokenDto tokenDto = userService.login(loginDto); HttpHeaders httpHeaders = new HttpHeaders(); diff --git a/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java b/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java index 1add5ec0..a2667b18 100644 --- a/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java +++ b/src/main/java/com/backendoori/ootw/user/dto/LoginDto.java @@ -1,7 +1,19 @@ package com.backendoori.ootw.user.dto; +import com.backendoori.ootw.user.validation.Password; +import com.backendoori.ootw.user.validation.RFC5322; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + public record LoginDto( + @NotNull + @NotBlank + @Email(regexp = RFC5322.REGEX) String email, + + @NotNull + @Password String password ) { From f927ce4b6ed8708c76ca7bbdbe0752fbb8a5e2cf Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 09:33:05 +0900 Subject: [PATCH 38/47] =?UTF-8?q?feat:=20global=20controller=20advice=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/exception/GlobalControllerAdvice.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 721a4671..2a375a51 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -18,6 +18,8 @@ @RestControllerAdvice public class GlobalControllerAdvice { + public static final String DEFAULT_MESSAGE = "유효하지 않은 요청 입니다."; + @ExceptionHandler(IllegalArgumentException.class) public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); @@ -33,7 +35,7 @@ public ResponseEntity handleMethodArgumentNotValidException(Metho .map(DefaultMessageSourceResolvable::getDefaultMessage) .filter(Objects::nonNull) .findFirst() - .orElseThrow(); + .orElse(DEFAULT_MESSAGE); ErrorResponse errorResponse = new ErrorResponse(message); From 475eaa7ea1f102e1f88e630eb66ed8a13cb4b1a7 Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 10:24:39 +0900 Subject: [PATCH 39/47] =?UTF-8?q?test:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backendoori/ootw/user/controller/UserControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index d140292b..d56b7fd4 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -272,7 +272,7 @@ private UserDto createUser(SignupDto signupDto) { private LoginDto generateLoginDto() { String email = faker.internet().emailAddress(); - String password = faker.internet().password(); + String password = faker.internet().password(8, 30, true, true, true); return new LoginDto(email, password); } From edf3674718c29f7b355918b0e023404fb4ca0d1e Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 10:40:25 +0900 Subject: [PATCH 40/47] =?UTF-8?q?test:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC,=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserControllerTest.java | 99 ++++++++++++++----- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java index d56b7fd4..3280063e 100644 --- a/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java +++ b/src/test/java/com/backendoori/ootw/user/controller/UserControllerTest.java @@ -25,8 +25,11 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; @@ -84,7 +87,7 @@ void created() throws Exception { @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") @NullAndEmptySource - @MethodSource("generateInvalidEmails") + @ArgumentsSource(InvalidEmailProvider.class) @ParameterizedTest void badRequestInvalidEmail(String email) throws Exception { // given @@ -105,7 +108,7 @@ void badRequestInvalidEmail(String email) throws Exception { @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") @NullAndEmptySource - @MethodSource("generateInvalidPasswords") + @ArgumentsSource(InvalidPasswordProvider.class) @ParameterizedTest void badRequestInvalidPassword(String password) throws Exception { // given @@ -163,26 +166,6 @@ void unauthorizedAlreadyExistEmail() throws Exception { actions.andExpect(status().isConflict()); } - private static Stream generateInvalidEmails() { - return Stream.of( - faker.app().name(), - faker.name().fullName(), - faker.internet().url(), - faker.internet().domainName(), - faker.internet().webdomain(), - faker.internet().botUserAgentAny() - ); - } - - private static Stream generateInvalidPasswords() { - return Stream.of( - faker.internet().password(1, 7, true, true, true), - faker.internet().password(31, 50, true, true, true), - faker.internet().password(8, 30, true, false, true), - faker.internet().password(8, 30, true, true, false) - ); - } - } @DisplayName("로그인 테스트") @@ -210,6 +193,26 @@ void created() throws Exception { .andExpect(jsonPath("$.token", is(tokenDto.token()))); } + @DisplayName("잘못된 형식의 email일 경우 400 status를 반환한다") + @NullAndEmptySource + @ArgumentsSource(InvalidEmailProvider.class) + @ParameterizedTest + void badRequestInvalidEmail(String email) throws Exception { + // given + String password = faker.internet().password(8, 30, true, true, true); + LoginDto loginDto = new LoginDto(email, password); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("email이 일치하는 사용자가 없으면 404 status를 반환한다") @Test void unauthorizedNotExistUser() throws Exception { @@ -229,6 +232,26 @@ void unauthorizedNotExistUser() throws Exception { actions.andExpect(status().isNotFound()); } + @DisplayName("잘못된 형식의 비밀번호의 경우 400 status를 반환한다") + @NullAndEmptySource + @ArgumentsSource(InvalidPasswordProvider.class) + @ParameterizedTest + void badRequestInvalidPassword(String password) throws Exception { + // given + String email = faker.internet().emailAddress(); + LoginDto loginDto = new LoginDto(email, password); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/auth/login") + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginDto))); + + // then + actions.andExpect(status().isBadRequest()); + } + @DisplayName("비밀번호가 일치하지 않으면 401 status를 반환한다") @Test void unauthorizedIncorrectPassword() throws Exception { @@ -281,4 +304,34 @@ private String removeMills(LocalDateTime localDateTime) { return localDateTime.truncatedTo(ChronoUnit.SECONDS).toString(); } + static class InvalidEmailProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(faker.app().name()), + Arguments.of(faker.name().fullName()), + Arguments.of(faker.internet().url()), + Arguments.of(faker.internet().domainName()), + Arguments.of(faker.internet().webdomain()), + Arguments.of(faker.internet().botUserAgentAny()) + ); + } + + } + + static class InvalidPasswordProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(faker.internet().password(1, 7, true, true, true)), + Arguments.of(faker.internet().password(31, 50, true, true, true)), + Arguments.of(faker.internet().password(8, 30, true, false, true)), + Arguments.of(faker.internet().password(8, 30, true, true, false)) + ); + } + + } + } From e16c065a8b079663f49961c9cd68a31144376836 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 10:44:44 +0900 Subject: [PATCH 41/47] =?UTF-8?q?style:=20annotation=20=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/avatar/controller/AvatarItemController.java | 4 ++-- .../ootw/common/validation/{ImageValid.java => Image.java} | 2 +- .../backendoori/ootw/common/validation/ImageValidator.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/com/backendoori/ootw/common/validation/{ImageValid.java => Image.java} (95%) diff --git a/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java b/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java index c2539f69..6050fc13 100644 --- a/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java +++ b/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java @@ -3,7 +3,7 @@ import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.dto.AvatarItemResponse; import com.backendoori.ootw.avatar.service.AvatarItemService; -import com.backendoori.ootw.common.validation.ImageValid; +import com.backendoori.ootw.common.validation.Image; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; @@ -22,7 +22,7 @@ public class AvatarItemController { private final AvatarItemService appearanceService; @PostMapping - public ResponseEntity uploadImage(@RequestPart @ImageValid MultipartFile file, + public ResponseEntity uploadImage(@RequestPart @Image MultipartFile file, @RequestPart @Valid AvatarItemRequest request) { AvatarItemResponse avatarItem = appearanceService.uploadItem(file, request); diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageValid.java b/src/main/java/com/backendoori/ootw/common/validation/Image.java similarity index 95% rename from src/main/java/com/backendoori/ootw/common/validation/ImageValid.java rename to src/main/java/com/backendoori/ootw/common/validation/Image.java index 6c15fa8b..6376e9ce 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ImageValid.java +++ b/src/main/java/com/backendoori/ootw/common/validation/Image.java @@ -10,7 +10,7 @@ @Target(value = ElementType.PARAMETER) @Retention(value = RetentionPolicy.RUNTIME) @Constraint(validatedBy = ImageValidator.class) -public @interface ImageValid { +public @interface Image { String message = "유효하지 않은 이미지를 업로드하였습니다. 다른 이미지를 업로드 해주세요"; diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java b/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java index 6e5e6270..778c713f 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java +++ b/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java @@ -4,7 +4,7 @@ import jakarta.validation.ConstraintValidatorContext; import org.springframework.web.multipart.MultipartFile; -public class ImageValidator implements ConstraintValidator { +public class ImageValidator implements ConstraintValidator { @Override public boolean isValid(MultipartFile img, ConstraintValidatorContext context) { From 95be2e1783ade5cb71371dcc3057b5956598f7c6 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 10:46:16 +0900 Subject: [PATCH 42/47] =?UTF-8?q?style:=20enum=20=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(Type=20->=20ItemType)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/backendoori/ootw/avatar/domain/AvatarItem.java | 4 ++-- .../ootw/avatar/domain/{Type.java => ItemType.java} | 2 +- .../com/backendoori/ootw/avatar/dto/AvatarItemResponse.java | 2 +- .../com/backendoori/ootw/avatar/domain/AvatarItemTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/com/backendoori/ootw/avatar/domain/{Type.java => ItemType.java} (80%) diff --git a/src/main/java/com/backendoori/ootw/avatar/domain/AvatarItem.java b/src/main/java/com/backendoori/ootw/avatar/domain/AvatarItem.java index d4bbd125..fcd6b6da 100644 --- a/src/main/java/com/backendoori/ootw/avatar/domain/AvatarItem.java +++ b/src/main/java/com/backendoori/ootw/avatar/domain/AvatarItem.java @@ -29,14 +29,14 @@ public class AvatarItem { @Column(name = "type", nullable = false, columnDefinition = "varchar(30)") @Enumerated(EnumType.STRING) - private Type type; + private ItemType itemType; @Column(name = "sex", nullable = false, columnDefinition = "tinyint") private boolean sex; private AvatarItem(String image, String type, boolean sex) { this.image = image; - this.type = Type.valueOf(type); + this.itemType = ItemType.valueOf(type); this.sex = sex; } diff --git a/src/main/java/com/backendoori/ootw/avatar/domain/Type.java b/src/main/java/com/backendoori/ootw/avatar/domain/ItemType.java similarity index 80% rename from src/main/java/com/backendoori/ootw/avatar/domain/Type.java rename to src/main/java/com/backendoori/ootw/avatar/domain/ItemType.java index 274757f6..ee2d5f60 100644 --- a/src/main/java/com/backendoori/ootw/avatar/domain/Type.java +++ b/src/main/java/com/backendoori/ootw/avatar/domain/ItemType.java @@ -1,5 +1,5 @@ package com.backendoori.ootw.avatar.domain; -public enum Type { +public enum ItemType { HAIR, TOP, PANTS, ACCESSORY, SHOES, BACKGROUND } diff --git a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemResponse.java b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemResponse.java index 2b32b5ba..b69bc3df 100644 --- a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemResponse.java +++ b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemResponse.java @@ -9,7 +9,7 @@ public record AvatarItemResponse( ) { public static AvatarItemResponse from(AvatarItem avatarItem) { - return new AvatarItemResponse(avatarItem.getType().name(), + return new AvatarItemResponse(avatarItem.getItemType().name(), avatarItem.isSex(), avatarItem.getImage()); } diff --git a/src/test/java/com/backendoori/ootw/avatar/domain/AvatarItemTest.java b/src/test/java/com/backendoori/ootw/avatar/domain/AvatarItemTest.java index 9a262312..b282fe2a 100644 --- a/src/test/java/com/backendoori/ootw/avatar/domain/AvatarItemTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/domain/AvatarItemTest.java @@ -20,7 +20,7 @@ public void createTest() throws Exception { //then - assertThat(request.type()).isEqualTo(avatarItem.getType().name()); + assertThat(request.type()).isEqualTo(avatarItem.getItemType().name()); assertThat(request.sex()).isEqualTo(avatarItem.isSex()); } From cd19d5f61090decefda3ba781fe2dd90ec592c7b Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 10:47:35 +0900 Subject: [PATCH 43/47] =?UTF-8?q?refactor:=20Type=EC=9D=84=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=ED=95=98=EB=8D=98=20Validator=EB=A5=BC=20Enum=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9D=84=20=EB=AA=A8=EB=91=90=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/avatar/dto/AvatarItemRequest.java | 5 +++-- .../validation/{ItemTypeValid.java => Enum.java} | 11 ++++------- .../{ItemTypeValidator.java => EnumValidator.java} | 10 ++++------ 3 files changed, 11 insertions(+), 15 deletions(-) rename src/main/java/com/backendoori/ootw/common/validation/{ItemTypeValid.java => Enum.java} (69%) rename src/main/java/com/backendoori/ootw/common/validation/{ItemTypeValidator.java => EnumValidator.java} (59%) diff --git a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java index 2d9e2cfb..0a5f2bf2 100644 --- a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java +++ b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java @@ -1,10 +1,11 @@ package com.backendoori.ootw.avatar.dto; -import com.backendoori.ootw.common.validation.ItemTypeValid; +import com.backendoori.ootw.avatar.domain.ItemType; +import com.backendoori.ootw.common.validation.Enum; import jakarta.validation.constraints.NotNull; public record AvatarItemRequest( - @ItemTypeValid + @Enum(enumClass = ItemType.class) String type, @NotNull boolean sex diff --git a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java b/src/main/java/com/backendoori/ootw/common/validation/Enum.java similarity index 69% rename from src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java rename to src/main/java/com/backendoori/ootw/common/validation/Enum.java index 2fe0137a..de8c6e93 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValid.java +++ b/src/main/java/com/backendoori/ootw/common/validation/Enum.java @@ -9,15 +9,12 @@ @Target(value = {ElementType.PARAMETER, ElementType.FIELD}) @Retention(value = RetentionPolicy.RUNTIME) -@Constraint(validatedBy = ItemTypeValidator.class) -public @interface ItemTypeValid { - - String message = "유효하지 않은 값입니다. 다시 입력해주세요"; - - String message() default message; +@Constraint(validatedBy = EnumValidator.class) +public @interface Enum { + String message() default "유효하지 않은 값입니다 다시 입력해주세요"; Class[] groups() default {}; - Class[] payload() default {}; + Class> enumClass(); } diff --git a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java b/src/main/java/com/backendoori/ootw/common/validation/EnumValidator.java similarity index 59% rename from src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java rename to src/main/java/com/backendoori/ootw/common/validation/EnumValidator.java index 1e848d3b..0f3fc64b 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ItemTypeValidator.java +++ b/src/main/java/com/backendoori/ootw/common/validation/EnumValidator.java @@ -1,17 +1,15 @@ package com.backendoori.ootw.common.validation; import java.util.Arrays; -import java.util.List; -import com.backendoori.ootw.avatar.domain.Type; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; -public class ItemTypeValidator implements ConstraintValidator { +public class EnumValidator implements ConstraintValidator { - private ItemTypeValid annotation; + private Enum annotation; @Override - public void initialize(ItemTypeValid constraintAnnotation) { + public void initialize(Enum constraintAnnotation) { this.annotation = constraintAnnotation; } @@ -21,7 +19,7 @@ public boolean isValid(String type, ConstraintValidatorContext context) { return false; } - return Arrays.stream(Type.class.getEnumConstants()) + return Arrays.stream(this.annotation.enumClass().getEnumConstants()) .anyMatch(e -> e.name().equals(type)); } From eb3224abbfaa2680a4a261ca1c6d99699516b2cd Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 14:02:03 +0900 Subject: [PATCH 44/47] =?UTF-8?q?style:=20=EC=A4=84=EB=B0=94=EA=BF=88=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/backendoori/ootw/exception/GlobalControllerAdvice.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 5191e4c8..fd1072f5 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -43,7 +43,8 @@ public ResponseEntity handleDuplicateKeyException(DuplicateKeyExc @ExceptionHandler(HandlerMethodValidationException.class) public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { - String errorMessage = e.getAllValidationResults().get(0) + String errorMessage = e.getAllValidationResults() + .get(0) .getResolvableErrors() .get(0) .getDefaultMessage(); From 287a134e8d495f9ccae3ca7484097a1bc9a27325 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 14:06:33 +0900 Subject: [PATCH 45/47] =?UTF-8?q?style:=20@WithMockUser=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EB=8B=A8=EC=9C=84=EB=A1=9C=20=EB=84=A3?= =?UTF-8?q?=EC=96=B4=EB=86=93=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 메서드마다 붙어있던 어노테이션 클래스 단위로 붙이기 --- .../ootw/avatar/controller/AvatarItemControllerTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java index 861a199a..08623b4b 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -21,6 +21,7 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; +@WithMockUser @AutoConfigureMockMvc @SpringBootTest class AvatarItemControllerTest { @@ -35,7 +36,6 @@ class AvatarItemControllerTest { ObjectMapper objectMapper; @Test - @WithMockUser @DisplayName("아바타 이미지를 정상적으로 등록한다.") public void imageUploadTest() throws Exception { //given @@ -55,7 +55,6 @@ public void imageUploadTest() throws Exception { .andExpect(status().isCreated()); } - @WithMockUser @ParameterizedTest(name = "[{index}] content-type 이 {0}인 경우") @ValueSource(strings = {"text/plain", "application/json"}) @DisplayName("아바타 이미지 업로드 시 파일의 유형이 이미지가 아닌 경우 예외가 발생한다.") @@ -78,7 +77,6 @@ public void imageUpLoadWithInvalidContentType(String contentType) throws Excepti } @Test - @WithMockUser @DisplayName("아바타 이미지 업로드 시 이미지 파일이 없는 경우 예외가 발생한다.") public void noImageUpLoad() throws Exception { //given @@ -98,7 +96,6 @@ public void noImageUpLoad() throws Exception { .andExpect(status().isBadRequest()); } - @WithMockUser @ParameterizedTest(name = "[{index}] item type으로 {0}가 들어오는 경우") @ValueSource(strings = {"afsee", "", " ", "hair"}) @NullSource From efe88e163e991a1a915331c95929ea54fa6777e7 Mon Sep 17 00:00:00 2001 From: shoeone96 Date: Mon, 8 Jan 2024 14:09:38 +0900 Subject: [PATCH 46/47] =?UTF-8?q?refactor:=20=EA=B3=B5=EB=B0=B1=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20->=20@NullAndEmptySource=20=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/avatar/controller/AvatarItemControllerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java index 08623b4b..f24167e1 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; @@ -97,8 +98,8 @@ public void noImageUpLoad() throws Exception { } @ParameterizedTest(name = "[{index}] item type으로 {0}가 들어오는 경우") - @ValueSource(strings = {"afsee", "", " ", "hair"}) - @NullSource + @ValueSource(strings = {"afsee", "hair"}) + @NullAndEmptySource @DisplayName("아바타 이미지 업로드 시 아이템 타입이 존재하지 않는 경우 예외가 발생한다.") public void UpLoadWithInvalidRequest(String type) throws Exception { //given From 5bb4948a212284a079661129b4b2040290ba605a Mon Sep 17 00:00:00 2001 From: ASak1104 Date: Mon, 8 Jan 2024 15:03:39 +0900 Subject: [PATCH 47/47] =?UTF-8?q?refactor:=20error=20response=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/exception/ExceptionResponse.java | 38 ----------------- .../exception/GlobalControllerAdvice.java | 42 ++++++++----------- .../post/controller/PostControllerTest.java | 16 +++---- 3 files changed, 23 insertions(+), 73 deletions(-) delete mode 100644 src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java diff --git a/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java b/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java deleted file mode 100644 index 242cfd29..00000000 --- a/src/main/java/com/backendoori/ootw/exception/ExceptionResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.backendoori.ootw.exception; - -import java.util.List; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.MethodArgumentNotValidException; - -public record ExceptionResponse( - T error -) { - - public static ExceptionResponse> from( - MethodArgumentNotValidException e) { - List errors = e.getBindingResult() - .getFieldErrors() - .stream() - .map(fieldError -> - new FieldErrorDetail(fieldError.getField(), fieldError.getDefaultMessage())) - .toList(); - - return new ExceptionResponse<>(errors); - } - - public static ExceptionResponse from(E e) { - return new ExceptionResponse<>(e.getMessage()); - } - - @RequiredArgsConstructor(access = AccessLevel.PROTECTED) - @Getter - public static class FieldErrorDetail { - - private final String field; - private final String defaultMessage; - - } - -} diff --git a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java index 94d11067..cf184ae0 100644 --- a/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/exception/GlobalControllerAdvice.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; -import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import lombok.extern.slf4j.Slf4j; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DuplicateKeyException; @@ -41,7 +40,20 @@ public ResponseEntity handleMethodArgumentNotValidException(Metho ErrorResponse errorResponse = new ErrorResponse(message); - return ResponseEntity.badRequest() + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(errorResponse); + } + + @ExceptionHandler(HandlerMethodValidationException.class) + public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { + String errorMessage = e.getAllValidationResults() + .get(0) + .getResolvableErrors() + .get(0) + .getDefaultMessage(); + ErrorResponse errorResponse = new ErrorResponse(errorMessage); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(errorResponse); } @@ -69,29 +81,12 @@ public ResponseEntity handleDuplicateKeyException(DuplicateKeyExc .body(errorResponse); } - @ExceptionHandler(HandlerMethodValidationException.class) - public ResponseEntity handlerMethodValidationException(HandlerMethodValidationException e) { - String errorMessage = e.getAllValidationResults() - .get(0) - .getResolvableErrors() - .get(0) - .getDefaultMessage(); - ErrorResponse errorResponse = new ErrorResponse(errorMessage); - - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(errorResponse); - } - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity> handleIllegalArgumentException(IllegalArgumentException e) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body(ExceptionResponse.from(e)); - } - @ExceptionHandler(ImageUploadException.class) - public ResponseEntity> handleImageUploadException(ImageUploadException e) { + public ResponseEntity handleImageUploadException(ImageUploadException e) { + ErrorResponse errorResponse = new ErrorResponse(e.getMessage()); + return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY) - .body(ExceptionResponse.from(e)); + .body(errorResponse); } @ExceptionHandler(Exception.class) @@ -104,5 +99,4 @@ public ResponseEntity handleException(Exception e) { .body(errorResponse); } - } diff --git a/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java b/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java index 1f216ea8..8403ad94 100644 --- a/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java +++ b/src/test/java/com/backendoori/ootw/post/controller/PostControllerTest.java @@ -3,15 +3,15 @@ import static com.backendoori.ootw.security.jwt.JwtAuthenticationFilter.TOKEN_HEADER; import static com.backendoori.ootw.security.jwt.JwtAuthenticationFilter.TOKEN_PREFIX; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.instanceOf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.nio.charset.StandardCharsets; import java.util.List; -import com.backendoori.ootw.exception.ExceptionResponse; -import com.backendoori.ootw.exception.ExceptionResponse.FieldErrorDetail; import com.backendoori.ootw.post.dto.PostReadResponse; import com.backendoori.ootw.post.dto.PostSaveRequest; import com.backendoori.ootw.post.dto.PostSaveResponse; @@ -173,16 +173,10 @@ void saveFailByMethodArgumentNotValidException() throws Exception { .accept(MediaType.APPLICATION_JSON); // then - String response = mockMvc.perform(requestBuilder) + mockMvc.perform(requestBuilder) .andExpect(status().isBadRequest()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andReturn() - .getResponse() - .getContentAsString(StandardCharsets.UTF_8); - - ExceptionResponse> exceptionResponse = - objectMapper.readValue(response, ExceptionResponse.class); - assertThat(exceptionResponse.error()).hasSize(1); + .andExpect(jsonPath("$.message", instanceOf(String.class))) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } @Test