From 82f51ea1a1ea5d86a662c2daabd4a5c13cbea160 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Thu, 18 Jan 2024 11:18:26 +0900 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20image=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20image=20directory=EB=A1=9C=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AvatarItemController.java | 2 +- .../avatar/service/AvatarItemService.java | 6 ++--- .../backendoori/ootw/image/domain/Image.java | 22 ++++++++++++++++ .../image => image/dto}/ImageFile.java | 2 +- .../exception/ImageControllerAdvice.java | 2 +- .../image/exception/ImageException.java | 2 +- .../image/exception/SaveException.java | 2 +- .../image => image/service}/ImageService.java | 3 ++- .../service}/MiniOImageServiceImpl.java | 15 +++++------ .../ootw/image/validation/Enum.java | 20 ++++++++++++++ .../ootw/image/validation/EnumValidator.java | 26 +++++++++++++++++++ .../{common => image}/validation/Image.java | 2 +- .../validation/ImageAnnotationValidator.java | 2 +- .../validation/ImageValidator.java | 2 +- .../ootw/post/controller/PostController.java | 2 +- .../ootw/post/service/PostService.java | 6 ++--- .../controller/AvatarItemControllerTest.java | 4 +-- .../avatar/service/AvatarItemServiceTest.java | 2 +- .../image/MiniOImageServiceImplTest.java | 4 ++- .../ootw/post/service/PostServiceTest.java | 6 ++--- 20 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/backendoori/ootw/image/domain/Image.java rename src/main/java/com/backendoori/ootw/{common/image => image/dto}/ImageFile.java (61%) rename src/main/java/com/backendoori/ootw/{common => }/image/exception/ImageControllerAdvice.java (95%) rename src/main/java/com/backendoori/ootw/{common => }/image/exception/ImageException.java (88%) rename src/main/java/com/backendoori/ootw/{common => }/image/exception/SaveException.java (84%) rename src/main/java/com/backendoori/ootw/{common/image => image/service}/ImageService.java (64%) rename src/main/java/com/backendoori/ootw/{common/image => image/service}/MiniOImageServiceImpl.java (78%) create mode 100644 src/main/java/com/backendoori/ootw/image/validation/Enum.java create mode 100644 src/main/java/com/backendoori/ootw/image/validation/EnumValidator.java rename src/main/java/com/backendoori/ootw/{common => image}/validation/Image.java (93%) rename src/main/java/com/backendoori/ootw/{common => image}/validation/ImageAnnotationValidator.java (95%) rename src/main/java/com/backendoori/ootw/{common => image}/validation/ImageValidator.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 6e0c4c1b..0785a06a 100644 --- a/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java +++ b/src/main/java/com/backendoori/ootw/avatar/controller/AvatarItemController.java @@ -4,7 +4,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.Image; +import com.backendoori.ootw.image.validation.Image; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/backendoori/ootw/avatar/service/AvatarItemService.java b/src/main/java/com/backendoori/ootw/avatar/service/AvatarItemService.java index b66b0ff1..94d9bbcb 100644 --- a/src/main/java/com/backendoori/ootw/avatar/service/AvatarItemService.java +++ b/src/main/java/com/backendoori/ootw/avatar/service/AvatarItemService.java @@ -5,9 +5,9 @@ import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.dto.AvatarItemResponse; import com.backendoori.ootw.avatar.repository.AvatarItemRepository; -import com.backendoori.ootw.common.image.ImageFile; -import com.backendoori.ootw.common.image.ImageService; -import com.backendoori.ootw.common.image.exception.SaveException; +import com.backendoori.ootw.image.dto.ImageFile; +import com.backendoori.ootw.image.service.ImageService; +import com.backendoori.ootw.image.exception.SaveException; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/backendoori/ootw/image/domain/Image.java b/src/main/java/com/backendoori/ootw/image/domain/Image.java new file mode 100644 index 00000000..f79b38d2 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/image/domain/Image.java @@ -0,0 +1,22 @@ +package com.backendoori.ootw.image.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Table(name = "image") +@Entity +public class Image { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "image_url", unique = true) + private String ImageUrl; + @Column(name = "fileName") + private String fileName; + +} diff --git a/src/main/java/com/backendoori/ootw/common/image/ImageFile.java b/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java similarity index 61% rename from src/main/java/com/backendoori/ootw/common/image/ImageFile.java rename to src/main/java/com/backendoori/ootw/image/dto/ImageFile.java index 1aabf702..c96aed90 100644 --- a/src/main/java/com/backendoori/ootw/common/image/ImageFile.java +++ b/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.image; +package com.backendoori.ootw.image.dto; public record ImageFile( String url, diff --git a/src/main/java/com/backendoori/ootw/common/image/exception/ImageControllerAdvice.java b/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java similarity index 95% rename from src/main/java/com/backendoori/ootw/common/image/exception/ImageControllerAdvice.java rename to src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java index 91a9b179..2e6fae1d 100644 --- a/src/main/java/com/backendoori/ootw/common/image/exception/ImageControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.image.exception; +package com.backendoori.ootw.image.exception; import com.backendoori.ootw.exception.ErrorResponse; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/backendoori/ootw/common/image/exception/ImageException.java b/src/main/java/com/backendoori/ootw/image/exception/ImageException.java similarity index 88% rename from src/main/java/com/backendoori/ootw/common/image/exception/ImageException.java rename to src/main/java/com/backendoori/ootw/image/exception/ImageException.java index 2109c917..0f4be035 100644 --- a/src/main/java/com/backendoori/ootw/common/image/exception/ImageException.java +++ b/src/main/java/com/backendoori/ootw/image/exception/ImageException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.image.exception; +package com.backendoori.ootw.image.exception; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/backendoori/ootw/common/image/exception/SaveException.java b/src/main/java/com/backendoori/ootw/image/exception/SaveException.java similarity index 84% rename from src/main/java/com/backendoori/ootw/common/image/exception/SaveException.java rename to src/main/java/com/backendoori/ootw/image/exception/SaveException.java index 4ec98d5c..a3b647a5 100644 --- a/src/main/java/com/backendoori/ootw/common/image/exception/SaveException.java +++ b/src/main/java/com/backendoori/ootw/image/exception/SaveException.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.image.exception; +package com.backendoori.ootw.image.exception; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/backendoori/ootw/common/image/ImageService.java b/src/main/java/com/backendoori/ootw/image/service/ImageService.java similarity index 64% rename from src/main/java/com/backendoori/ootw/common/image/ImageService.java rename to src/main/java/com/backendoori/ootw/image/service/ImageService.java index 1064f453..0a6e5a17 100644 --- a/src/main/java/com/backendoori/ootw/common/image/ImageService.java +++ b/src/main/java/com/backendoori/ootw/image/service/ImageService.java @@ -1,5 +1,6 @@ -package com.backendoori.ootw.common.image; +package com.backendoori.ootw.image.service; +import com.backendoori.ootw.image.dto.ImageFile; import org.springframework.web.multipart.MultipartFile; public interface ImageService { diff --git a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java b/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java similarity index 78% rename from src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java rename to src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java index 5dee94e9..d08c6a7b 100644 --- a/src/main/java/com/backendoori/ootw/common/image/MiniOImageServiceImpl.java +++ b/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java @@ -1,13 +1,12 @@ -package com.backendoori.ootw.common.image; +package com.backendoori.ootw.image.service; -import static com.backendoori.ootw.common.image.exception.ImageException.IMAGE_ROLLBACK_FAIL_MESSAGE; -import static com.backendoori.ootw.common.image.exception.ImageException.IMAGE_UPLOAD_FAIL_MESSAGE; -import static com.backendoori.ootw.common.validation.ImageValidator.validateImage; +import static com.backendoori.ootw.image.validation.ImageValidator.validateImage; import java.io.InputStream; import java.nio.file.Path; import java.util.concurrent.TimeUnit; -import com.backendoori.ootw.common.image.exception.ImageException; +import com.backendoori.ootw.image.dto.ImageFile; +import com.backendoori.ootw.image.exception.ImageException; import com.backendoori.ootw.config.MiniOConfig; import io.minio.GetPresignedObjectUrlArgs; import io.minio.MinioClient; @@ -47,7 +46,7 @@ public ImageFile upload(MultipartFile file) { minioClient.putObject(args); return new ImageFile(getUrl(), path.toString()); } catch (Exception e) { - throw new ImageException(IMAGE_UPLOAD_FAIL_MESSAGE); + throw new ImageException(ImageException.IMAGE_UPLOAD_FAIL_MESSAGE); } } @@ -59,7 +58,7 @@ public void delete(String fileName) { .object(fileName) .build()); } catch (Exception e) { - throw new ImageException(IMAGE_ROLLBACK_FAIL_MESSAGE); + throw new ImageException(ImageException.IMAGE_ROLLBACK_FAIL_MESSAGE); } } @@ -73,7 +72,7 @@ private String getUrl() { .expiry(DURATION, TimeUnit.HOURS) .build()); } catch (Exception e) { - throw new ImageException(IMAGE_UPLOAD_FAIL_MESSAGE); + throw new ImageException(ImageException.IMAGE_UPLOAD_FAIL_MESSAGE); } } diff --git a/src/main/java/com/backendoori/ootw/image/validation/Enum.java b/src/main/java/com/backendoori/ootw/image/validation/Enum.java new file mode 100644 index 00000000..00cc7084 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/image/validation/Enum.java @@ -0,0 +1,20 @@ +package com.backendoori.ootw.image.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 = 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/image/validation/EnumValidator.java b/src/main/java/com/backendoori/ootw/image/validation/EnumValidator.java new file mode 100644 index 00000000..72a966b4 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/image/validation/EnumValidator.java @@ -0,0 +1,26 @@ +package com.backendoori.ootw.image.validation; + +import java.util.Arrays; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class EnumValidator implements ConstraintValidator { + + private Enum annotation; + + @Override + public void initialize(Enum constraintAnnotation) { + this.annotation = constraintAnnotation; + } + + @Override + public boolean isValid(String type, ConstraintValidatorContext context) { + if (type == null) { + return false; + } + + return Arrays.stream(this.annotation.enumClass().getEnumConstants()) + .anyMatch(e -> e.name().equals(type)); + } + +} diff --git a/src/main/java/com/backendoori/ootw/common/validation/Image.java b/src/main/java/com/backendoori/ootw/image/validation/Image.java similarity index 93% rename from src/main/java/com/backendoori/ootw/common/validation/Image.java rename to src/main/java/com/backendoori/ootw/image/validation/Image.java index 23ccc5dc..71719824 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/Image.java +++ b/src/main/java/com/backendoori/ootw/image/validation/Image.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.validation; +package com.backendoori.ootw.image.validation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageAnnotationValidator.java b/src/main/java/com/backendoori/ootw/image/validation/ImageAnnotationValidator.java similarity index 95% rename from src/main/java/com/backendoori/ootw/common/validation/ImageAnnotationValidator.java rename to src/main/java/com/backendoori/ootw/image/validation/ImageAnnotationValidator.java index e6db8849..db677131 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ImageAnnotationValidator.java +++ b/src/main/java/com/backendoori/ootw/image/validation/ImageAnnotationValidator.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.validation; +package com.backendoori.ootw.image.validation; import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; diff --git a/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java b/src/main/java/com/backendoori/ootw/image/validation/ImageValidator.java similarity index 95% rename from src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java rename to src/main/java/com/backendoori/ootw/image/validation/ImageValidator.java index d32e4e35..07172a72 100644 --- a/src/main/java/com/backendoori/ootw/common/validation/ImageValidator.java +++ b/src/main/java/com/backendoori/ootw/image/validation/ImageValidator.java @@ -1,4 +1,4 @@ -package com.backendoori.ootw.common.validation; +package com.backendoori.ootw.image.validation; import io.jsonwebtoken.lang.Assert; import lombok.AccessLevel; 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 91946cb6..4be1c93b 100644 --- a/src/main/java/com/backendoori/ootw/post/controller/PostController.java +++ b/src/main/java/com/backendoori/ootw/post/controller/PostController.java @@ -2,7 +2,7 @@ import java.net.URI; import java.util.List; -import com.backendoori.ootw.common.validation.Image; +import com.backendoori.ootw.image.validation.Image; import com.backendoori.ootw.post.dto.request.PostSaveRequest; import com.backendoori.ootw.post.dto.request.PostUpdateRequest; import com.backendoori.ootw.post.dto.response.PostReadResponse; diff --git a/src/main/java/com/backendoori/ootw/post/service/PostService.java b/src/main/java/com/backendoori/ootw/post/service/PostService.java index b16e643c..8d641b38 100644 --- a/src/main/java/com/backendoori/ootw/post/service/PostService.java +++ b/src/main/java/com/backendoori/ootw/post/service/PostService.java @@ -7,9 +7,9 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; -import com.backendoori.ootw.common.image.ImageFile; -import com.backendoori.ootw.common.image.ImageService; -import com.backendoori.ootw.common.image.exception.SaveException; +import com.backendoori.ootw.image.dto.ImageFile; +import com.backendoori.ootw.image.service.ImageService; +import com.backendoori.ootw.image.exception.SaveException; import com.backendoori.ootw.exception.PermissionException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.like.domain.Like; 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 bc366268..4acccbb3 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -12,8 +12,8 @@ import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.repository.AvatarItemRepository; import com.backendoori.ootw.avatar.service.AvatarItemService; -import com.backendoori.ootw.common.image.exception.ImageException; -import com.backendoori.ootw.common.image.exception.SaveException; +import com.backendoori.ootw.image.exception.ImageException; +import com.backendoori.ootw.image.exception.SaveException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/backendoori/ootw/avatar/service/AvatarItemServiceTest.java b/src/test/java/com/backendoori/ootw/avatar/service/AvatarItemServiceTest.java index 9aa81dcc..7e6d60a6 100644 --- a/src/test/java/com/backendoori/ootw/avatar/service/AvatarItemServiceTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/service/AvatarItemServiceTest.java @@ -10,7 +10,7 @@ import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.dto.AvatarItemResponse; import com.backendoori.ootw.avatar.repository.AvatarItemRepository; -import com.backendoori.ootw.common.image.exception.SaveException; +import com.backendoori.ootw.image.exception.SaveException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java index b4ba4816..983cdc4d 100644 --- a/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java +++ b/src/test/java/com/backendoori/ootw/common/image/MiniOImageServiceImplTest.java @@ -7,7 +7,9 @@ import static org.mockito.Mockito.when; import java.util.stream.Stream; -import com.backendoori.ootw.common.image.exception.ImageException; +import com.backendoori.ootw.image.service.ImageService; +import com.backendoori.ootw.image.service.MiniOImageServiceImpl; +import com.backendoori.ootw.image.exception.ImageException; import com.backendoori.ootw.config.MiniOConfig; import io.minio.GetPresignedObjectUrlArgs; import io.minio.MinioClient; 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 59f913a5..765be6e0 100644 --- a/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java +++ b/src/test/java/com/backendoori/ootw/post/service/PostServiceTest.java @@ -20,9 +20,9 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.stream.Stream; -import com.backendoori.ootw.common.image.ImageFile; -import com.backendoori.ootw.common.image.ImageService; -import com.backendoori.ootw.common.image.exception.SaveException; +import com.backendoori.ootw.image.dto.ImageFile; +import com.backendoori.ootw.image.service.ImageService; +import com.backendoori.ootw.image.exception.SaveException; import com.backendoori.ootw.exception.PermissionException; import com.backendoori.ootw.exception.UserNotFoundException; import com.backendoori.ootw.like.repository.LikeRepository; From 0bd8a1f1f6f1604d07a5240c1daf5b5c2f5bef4e Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:36:04 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20image=20table=20=EB=B0=8F=20entity?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/schema.sql | 9 +++++++++ .../com/backendoori/ootw/image/domain/Image.java | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql/schema.sql b/mysql/schema.sql index 35e9beee..903237b0 100644 --- a/mysql/schema.sql +++ b/mysql/schema.sql @@ -57,3 +57,12 @@ CREATE TABLE likes FOREIGN KEY (user_id) REFERENCES users (id), FOREIGN KEY (post_id) REFERENCES posts (id) ); + + +CREATE TABLE images +( + id BIGINT AUTO_INCREMENT, + image_url varchar(500) NOT NULL, + filename varchar(255) NOT NULL, + CONSTRAINT images_pk PRIMARY KEY (id), +); diff --git a/src/main/java/com/backendoori/ootw/image/domain/Image.java b/src/main/java/com/backendoori/ootw/image/domain/Image.java index f79b38d2..59e88967 100644 --- a/src/main/java/com/backendoori/ootw/image/domain/Image.java +++ b/src/main/java/com/backendoori/ootw/image/domain/Image.java @@ -6,16 +6,27 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; -@Table(name = "image") +@Table(name = "images") +@Getter @Entity +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Image { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "image_url", unique = true) private String ImageUrl; + @Column(name = "fileName") private String fileName; From 88c5d92e12234513d8ca9be69fc5a8d165bb5e1e Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:37:20 +0900 Subject: [PATCH 3/9] =?UTF-8?q?refactor:=20Image=20db=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=83=9D=EC=84=B1=EA=B3=BC=20file=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20unique=20=ED=95=98=EA=B2=8C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=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 --- .../image/service/MiniOImageServiceImpl.java | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java b/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java index d08c6a7b..959dc883 100644 --- a/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java +++ b/src/main/java/com/backendoori/ootw/image/service/MiniOImageServiceImpl.java @@ -3,18 +3,24 @@ import static com.backendoori.ootw.image.validation.ImageValidator.validateImage; import java.io.InputStream; -import java.nio.file.Path; +import java.util.UUID; import java.util.concurrent.TimeUnit; +import com.backendoori.ootw.image.domain.Image; import com.backendoori.ootw.image.dto.ImageFile; import com.backendoori.ootw.image.exception.ImageException; import com.backendoori.ootw.config.MiniOConfig; +import com.backendoori.ootw.image.repository.ImageRepository; import io.minio.GetPresignedObjectUrlArgs; import io.minio.MinioClient; import io.minio.PutObjectArgs; import io.minio.RemoveObjectArgs; import io.minio.http.Method; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -28,28 +34,46 @@ public class MiniOImageServiceImpl implements ImageService { private final MinioClient minioClient; private final MiniOConfig miniOConfig; - private Path path; + private final ImageRepository imageRepository; @Override public ImageFile upload(MultipartFile file) { validateImage(file); + String randomFileName = getUniqueFileName(file); try { - path = Path.of(file.getOriginalFilename()); InputStream inputStream = file.getInputStream(); String contentType = file.getContentType(); PutObjectArgs args = PutObjectArgs.builder() .bucket(miniOConfig.getBucket()) - .object(path.toString()) + .object(randomFileName) .stream(inputStream, inputStream.available(), -1) .contentType(contentType) .build(); minioClient.putObject(args); - return new ImageFile(getUrl(), path.toString()); + String url = getUrl(randomFileName); + Image image = saveImage(url, randomFileName); + imageRepository.save(image); + return ImageFile.from(image); } catch (Exception e) { throw new ImageException(ImageException.IMAGE_UPLOAD_FAIL_MESSAGE); } } + private static Image saveImage(String url, String randomFileName) { + return Image.builder() + .ImageUrl(url) + .fileName(randomFileName) + .build(); + } + + @NotNull + private static String getUniqueFileName(MultipartFile file) { + String randomUUID = UUID.randomUUID().toString(); + String originalFileName = file.getOriginalFilename(); + + return randomUUID + originalFileName; + } + @Override public void delete(String fileName) { try { @@ -62,13 +86,13 @@ public void delete(String fileName) { } } - private String getUrl() { + private String getUrl(String fileName) { try { return minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(miniOConfig.getBucket()) - .object(path.toString()) + .object(fileName) .expiry(DURATION, TimeUnit.HOURS) .build()); } catch (Exception e) { From e83f62ceab956df44adc1b61b69a3f12f19083a5 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:37:41 +0900 Subject: [PATCH 4/9] =?UTF-8?q?feat:=20ImageFile=20=EC=A0=95=EC=A0=81=20st?= =?UTF-8?q?atic=20method=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/backendoori/ootw/image/dto/ImageFile.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java b/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java index c96aed90..2e2a3cca 100644 --- a/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java +++ b/src/main/java/com/backendoori/ootw/image/dto/ImageFile.java @@ -1,8 +1,12 @@ package com.backendoori.ootw.image.dto; +import com.backendoori.ootw.image.domain.Image; + public record ImageFile( String url, String fileName ) { - + public static ImageFile from(Image image){ + return new ImageFile(image.getImageUrl(), image.getFileName()); + } } From bebc18a6adfa8f7954e475c04a1ff04d7ed44106 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:37:55 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20image=20=EC=A0=80=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20repository=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/image/repository/ImageRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/image/repository/ImageRepository.java diff --git a/src/main/java/com/backendoori/ootw/image/repository/ImageRepository.java b/src/main/java/com/backendoori/ootw/image/repository/ImageRepository.java new file mode 100644 index 00000000..2fe3e51f --- /dev/null +++ b/src/main/java/com/backendoori/ootw/image/repository/ImageRepository.java @@ -0,0 +1,8 @@ +package com.backendoori.ootw.image.repository; + +import com.backendoori.ootw.image.domain.Image; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ImageRepository extends JpaRepository { + +} From 300b564aea59d94c5c476b222bd049a02f4d18ea Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:38:23 +0900 Subject: [PATCH 6/9] =?UTF-8?q?feat:=20=ED=95=9C=20=EB=8B=AC=EC=97=90=20?= =?UTF-8?q?=ED=95=9C=EB=B2=88=20=EC=82=AC=EC=9A=A9=EC=95=88=ED=95=98?= =?UTF-8?q?=EB=8A=94=20image=20=EC=82=AD=EC=A0=9C=20=EB=A1=9C=EC=A7=81=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/OotwApplication.java | 2 + .../image/service/ImageUpdateService.java | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/main/java/com/backendoori/ootw/image/service/ImageUpdateService.java diff --git a/src/main/java/com/backendoori/ootw/OotwApplication.java b/src/main/java/com/backendoori/ootw/OotwApplication.java index d1869f36..93d4312b 100644 --- a/src/main/java/com/backendoori/ootw/OotwApplication.java +++ b/src/main/java/com/backendoori/ootw/OotwApplication.java @@ -5,7 +5,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.scheduling.annotation.EnableScheduling; +@EnableScheduling @SpringBootApplication @ConfigurationPropertiesScan public class OotwApplication { diff --git a/src/main/java/com/backendoori/ootw/image/service/ImageUpdateService.java b/src/main/java/com/backendoori/ootw/image/service/ImageUpdateService.java new file mode 100644 index 00000000..1fe6ab52 --- /dev/null +++ b/src/main/java/com/backendoori/ootw/image/service/ImageUpdateService.java @@ -0,0 +1,55 @@ +package com.backendoori.ootw.image.service; + +import java.util.ArrayList; +import java.util.List; +import com.backendoori.ootw.avatar.domain.AvatarItem; +import com.backendoori.ootw.avatar.repository.AvatarItemRepository; +import com.backendoori.ootw.image.domain.Image; +import com.backendoori.ootw.image.repository.ImageRepository; +import com.backendoori.ootw.post.domain.Post; +import com.backendoori.ootw.post.repository.PostRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ImageUpdateService { + + private final PostRepository postRepository; + private final AvatarItemRepository avatarItemRepository; + private final ImageRepository imageRepository; + private final ImageService imageService; + public static final String TIMEZONE = "Asia/Seoul"; + public static final String CRON = "0 20 00 10 * ?"; + + @Scheduled(cron = CRON, zone = TIMEZONE) // 매월 20일 오전 00시 10분에 실행 + @Async + @Transactional + public void deleteUnused(){ + + List urls = new ArrayList<>(); + + postRepository.findAll() + .stream() + .map(Post::getImageUrl) + .forEach(urls::add); + + avatarItemRepository.findAll() + .stream() + .map(AvatarItem::getImageUrl) + .forEach(urls::add); + + List images = imageRepository.findAll(); + + for(Image image : images){ + if(!urls.contains(image.getImageUrl())){ + imageService.delete(image.getFileName()); + } + } + + } + +} From ed3bb10a43874b1e71bc3a25aec08a0c3b5cbb90 Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:07:37 +0900 Subject: [PATCH 7/9] =?UTF-8?q?feat:=20schema,=20Entity=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=94=EA=B8=B0=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9=EC=95=88?= =?UTF-8?q?=ED=95=98=EB=8A=94=20import=20=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/schema.sql | 2 +- .../java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java | 1 - src/main/java/com/backendoori/ootw/image/domain/Image.java | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql/schema.sql b/mysql/schema.sql index 903237b0..53c497b2 100644 --- a/mysql/schema.sql +++ b/mysql/schema.sql @@ -64,5 +64,5 @@ CREATE TABLE images id BIGINT AUTO_INCREMENT, image_url varchar(500) NOT NULL, filename varchar(255) NOT NULL, - CONSTRAINT images_pk PRIMARY KEY (id), + CONSTRAINT images_pk PRIMARY KEY (id) ); 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 6285c895..3ec5e1ea 100644 --- a/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java +++ b/src/main/java/com/backendoori/ootw/avatar/dto/AvatarItemRequest.java @@ -3,7 +3,6 @@ import com.backendoori.ootw.avatar.domain.ItemType; import com.backendoori.ootw.avatar.domain.Sex; import com.backendoori.ootw.common.validation.Enum; -import jakarta.validation.constraints.NotNull; public record AvatarItemRequest( @Enum(enumClass = ItemType.class) diff --git a/src/main/java/com/backendoori/ootw/image/domain/Image.java b/src/main/java/com/backendoori/ootw/image/domain/Image.java index 59e88967..2470f6cf 100644 --- a/src/main/java/com/backendoori/ootw/image/domain/Image.java +++ b/src/main/java/com/backendoori/ootw/image/domain/Image.java @@ -27,7 +27,7 @@ public class Image { @Column(name = "image_url", unique = true) private String ImageUrl; - @Column(name = "fileName") + @Column(name = "filename") private String fileName; } From de94e13277854cff3595abe3e7cca710f965f0cc Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:07:57 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20ImageException=20=EC=9D=84=20?= =?UTF-8?q?=EB=AA=BB=EC=9E=A1=EC=95=84=EB=82=B4=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ootw/image/exception/ImageControllerAdvice.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java b/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java index 2e6fae1d..ac74aafc 100644 --- a/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java +++ b/src/main/java/com/backendoori/ootw/image/exception/ImageControllerAdvice.java @@ -2,6 +2,8 @@ import com.backendoori.ootw.exception.ErrorResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -9,6 +11,7 @@ @Slf4j @RestControllerAdvice +@Order(Ordered.HIGHEST_PRECEDENCE) public class ImageControllerAdvice { private static final String IMAGE_RELATED_EXCEPTION = "업로드 요청 중 문제가 발생했습니다."; @@ -30,4 +33,5 @@ public ResponseEntity handleSaveException(SaveException e) { return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY) .body(errorResponse); } + } From ff039e89173a89648015a541cc2d341d4f2b7bbd Mon Sep 17 00:00:00 2001 From: LEE JUNGWON <85065626+shoeone96@users.noreply.github.com> Date: Fri, 19 Jan 2024 23:51:59 +0900 Subject: [PATCH 9/9] =?UTF-8?q?test:=20=EC=95=84=EB=B0=94=ED=83=80=20ItemR?= =?UTF-8?q?equest=20validation=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/index.html | 310 +++++++++--------- .../controller/AvatarItemControllerTest.java | 39 +++ 2 files changed, 194 insertions(+), 155 deletions(-) diff --git a/src/docs/asciidoc/index.html b/src/docs/asciidoc/index.html index 88a73c93..4f465e00 100644 --- a/src/docs/asciidoc/index.html +++ b/src/docs/asciidoc/index.html @@ -573,9 +573,9 @@

Request

{
-  "email" : "gavin.lakin@hotmail.com",
-  "password" : "BNc@^R!#tM&Prm0WcOIf5Jm1w",
-  "nickname" : "esteban.haag"
+  "email" : "shaniqua.effertz@yahoo.com",
+  "password" : "R87zL7mO&",
+  "nickname" : "nolan.wisozk"
 }
@@ -616,13 +616,13 @@

Request examp
POST /api/v1/auth/signup HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Content-Length: 116
+Content-Length: 103
 Host: docs.api.com
 
 {
-  "email" : "gavin.lakin@hotmail.com",
-  "password" : "BNc@^R!#tM&Prm0WcOIf5Jm1w",
-  "nickname" : "esteban.haag"
+  "email" : "shaniqua.effertz@yahoo.com",
+  "password" : "R87zL7mO&",
+  "nickname" : "nolan.wisozk"
 }
@@ -664,8 +664,8 @@

Request

{
-  "email" : "williams.flatley@yahoo.com",
-  "password" : "Xz#0^3%v8$yk0o%o"
+  "email" : "otto.jacobson@gmail.com",
+  "password" : "D&2t0el8"
 }
@@ -701,12 +701,12 @@

Request e
POST /api/v1/auth/login HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Content-Length: 79
+Content-Length: 68
 Host: docs.api.com
 
 {
-  "email" : "williams.flatley@yahoo.com",
-  "password" : "Xz#0^3%v8$yk0o%o"
+  "email" : "otto.jacobson@gmail.com",
+  "password" : "D&2t0el8"
 }
@@ -717,7 +717,7 @@

Response

{
-  "token" : "a5fbfa1c2fd6a064babe4b7234f141fe57733ee9c53839bb31a0284a7b0a3a49b2894252b81e86078ecc0d9a7e24dc81372376b006d457ede46a8d9d1ea0ff93"
+  "token" : "f8cc772b2b817f5e4ec4b03aaaf6605bcdc99d9d86d494cbbe5c4a18e037c512855b5547445262680dd6173685c2e1eb5daf700e4f0563afb98b32088c980909"
 }
@@ -750,12 +750,12 @@

Respons Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers -Authorization: Bearer a5fbfa1c2fd6a064babe4b7234f141fe57733ee9c53839bb31a0284a7b0a3a49b2894252b81e86078ecc0d9a7e24dc81372376b006d457ede46a8d9d1ea0ff93 +Authorization: Bearer f8cc772b2b817f5e4ec4b03aaaf6605bcdc99d9d86d494cbbe5c4a18e037c512855b5547445262680dd6173685c2e1eb5daf700e4f0563afb98b32088c980909 Content-Type: application/json Content-Length: 146 { - "token" : "a5fbfa1c2fd6a064babe4b7234f141fe57733ee9c53839bb31a0284a7b0a3a49b2894252b81e86078ecc0d9a7e24dc81372376b006d457ede46a8d9d1ea0ff93" + "token" : "f8cc772b2b817f5e4ec4b03aaaf6605bcdc99d9d86d494cbbe5c4a18e037c512855b5547445262680dd6173685c2e1eb5daf700e4f0563afb98b32088c980909" } @@ -802,7 +802,7 @@

Request

Request example

-
PATCH /api/v1/auth/certificate?email=magnolia.becker@yahoo.com HTTP/1.1
+
PATCH /api/v1/auth/certificate?email=kendall.rowe@gmail.com HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Host: docs.api.com
@@ -868,7 +868,7 @@

Request

Request example

-
PATCH /api/v1/auth/certify?email=emery.kutch@example.com&code=Q8K940 HTTP/1.1
+
PATCH /api/v1/auth/certify?email=catalina.bartell@example.com&code=3ZGzHj HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Host: docs.api.com
@@ -992,7 +992,7 @@

Request e

@@ -1118,12 +1118,12 @@

Response

"avatarItemId" : 1, "type" : "HAIR", "sex" : "MALE", - "url" : "http://www.williams-crooks.biz/" + "url" : "http://www.gabriel-stanton.biz:13515/laborum?saepe=aliquam&nesciunt=dicta" }, { "avatarItemId" : 2, "type" : "TOP", "sex" : "FEMALE", - "url" : "https://www.elyse-volkman.io/earum/eius?voluptas=rerum&voluptas=exercitationem#vel" + "url" : "https://www.cordelia-bruen.io:52191/" } ]
@@ -1172,18 +1172,18 @@

Respons Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json -Content-Length: 270 +Content-Length: 266 [ { "avatarItemId" : 1, "type" : "HAIR", "sex" : "MALE", - "url" : "http://www.williams-crooks.biz/" + "url" : "http://www.gabriel-stanton.biz:13515/laborum?saepe=aliquam&nesciunt=dicta" }, { "avatarItemId" : 2, "type" : "TOP", "sex" : "FEMALE", - "url" : "https://www.elyse-volkman.io/earum/eius?voluptas=rerum&voluptas=exercitationem#vel" + "url" : "https://www.cordelia-bruen.io:52191/" } ] @@ -1302,7 +1302,7 @@

Request e
POST /api/v1/posts HTTP/1.1
 Content-Type: multipart/form-data;charset=UTF-8; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg0LCJleHAiOjE3MDU1NzQ1ODQsInVzZXJfaWQiOjF9.mTcgBjKPrrKkjVtfmEk0MJyDI-8PQyKuXrzwr2w1_I8mwQq5lT6PkW9eMPNfCee2vdtxCj6HF_U2rN_yqcbgRA
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzY1LCJleHAiOjE3MDU2Nzc5NjUsInVzZXJfaWQiOjF9.7YEbtfN90q-vWJ47IdoUy79KtHJdjSEjVn16sm4glP5UUzuJG705VSJR740ZlBdwKCn5AUDGnOPRpxwSeUC6aA
 Accept: application/json
 Host: docs.api.com
 
@@ -1310,7 +1310,7 @@ 

Request e Content-Disposition: form-data; name=request; filename=request.json Content-Type: application/json -{"title":"Arms and the Man","content":"Tin","coordinate":{"nx":50,"ny":127}} +{"title":"The Grapes of Wrath","content":"Bromine","coordinate":{"nx":50,"ny":127}} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm Content-Disposition: form-data; name=postImg; filename=image.jpeg Content-Type: image/jpeg @@ -1327,11 +1327,11 @@

Response

{
   "postId" : 1,
-  "title" : "Arms and the Man",
-  "content" : "Tin",
-  "image" : "https://www.arnulfo-runolfsdottir.info/?architecto=ut&impedit=aperiam",
-  "createdAt" : "2024-01-18T18:43:04.877194",
-  "updatedAt" : "2024-01-18T18:43:04.877208",
+  "title" : "The Grapes of Wrath",
+  "content" : "Bromine",
+  "image" : "https://www.mac-kertzmann.info:56449/voluptas/optio#ipsam",
+  "createdAt" : "2024-01-19T23:26:05.615107",
+  "updatedAt" : "2024-01-19T23:26:05.615121",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
@@ -1405,15 +1405,15 @@ 

Respons Vary: Access-Control-Request-Headers Location: /api/v1/posts/1 Content-Type: application/json -Content-Length: 314 +Content-Length: 309 { "postId" : 1, - "title" : "Arms and the Man", - "content" : "Tin", - "image" : "https://www.arnulfo-runolfsdottir.info/?architecto=ut&impedit=aperiam", - "createdAt" : "2024-01-18T18:43:04.877194", - "updatedAt" : "2024-01-18T18:43:04.877208", + "title" : "The Grapes of Wrath", + "content" : "Bromine", + "image" : "https://www.mac-kertzmann.info:56449/voluptas/optio#ipsam", + "createdAt" : "2024-01-19T23:26:05.615107", + "updatedAt" : "2024-01-19T23:26:05.615121", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 @@ -1489,9 +1489,9 @@

Request H

Request example

-
GET /api/v1/posts/1803095596 HTTP/1.1
+
GET /api/v1/posts/1452329854 HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg0LCJleHAiOjE3MDU1NzQ1ODQsInVzZXJfaWQiOjF9.mTcgBjKPrrKkjVtfmEk0MJyDI-8PQyKuXrzwr2w1_I8mwQq5lT6PkW9eMPNfCee2vdtxCj6HF_U2rN_yqcbgRA
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzY1LCJleHAiOjE3MDU2Nzc5NjUsInVzZXJfaWQiOjF9.7YEbtfN90q-vWJ47IdoUy79KtHJdjSEjVn16sm4glP5UUzuJG705VSJR740ZlBdwKCn5AUDGnOPRpxwSeUC6aA
 Accept: application/json
 Host: docs.api.com
@@ -1503,22 +1503,22 @@

Response

{
-  "postId" : 1803095596,
+  "postId" : 1452329854,
   "writer" : {
-    "userId" : 412308604,
-    "nickname" : "jay.grimes",
-    "image" : "http://www.wyatt-terry.biz/?et=incidunt&possimus=saepe#maxime"
+    "userId" : 301376391,
+    "nickname" : "forrest.windler",
+    "image" : "http://www.kathy-little.io:64848/est/velitsunt"
   },
-  "title" : "The Lathe of Heaven",
-  "content" : "Californium",
-  "image" : "https://www.breanne-waelchi.org:43673/ullam/sequiodio#earum",
-  "createdAt" : "2024-01-18T18:43:04.832065",
-  "updatedAt" : "2024-01-18T18:43:04.832079",
+  "title" : "Arms and the Man",
+  "content" : "Gallium",
+  "image" : "http://www.lesa-becker.info/et?ea=quis&laudantium=voluptas#suscipit",
+  "createdAt" : "2024-01-19T23:26:05.484459",
+  "updatedAt" : "2024-01-19T23:26:05.484469",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
   },
-  "likeCnt" : 33,
+  "likeCnt" : 66,
   "isLike" : 0
 }
@@ -1613,25 +1613,25 @@

Respons Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json -Content-Length: 513 +Content-Length: 504 { - "postId" : 1803095596, + "postId" : 1452329854, "writer" : { - "userId" : 412308604, - "nickname" : "jay.grimes", - "image" : "http://www.wyatt-terry.biz/?et=incidunt&possimus=saepe#maxime" + "userId" : 301376391, + "nickname" : "forrest.windler", + "image" : "http://www.kathy-little.io:64848/est/velitsunt" }, - "title" : "The Lathe of Heaven", - "content" : "Californium", - "image" : "https://www.breanne-waelchi.org:43673/ullam/sequiodio#earum", - "createdAt" : "2024-01-18T18:43:04.832065", - "updatedAt" : "2024-01-18T18:43:04.832079", + "title" : "Arms and the Man", + "content" : "Gallium", + "image" : "http://www.lesa-becker.info/et?ea=quis&laudantium=voluptas#suscipit", + "createdAt" : "2024-01-19T23:26:05.484459", + "updatedAt" : "2024-01-19T23:26:05.484469", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 }, - "likeCnt" : 33, + "likeCnt" : 66, "isLike" : 0 }

@@ -1687,7 +1687,7 @@

Request e
GET /api/v1/posts HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg0LCJleHAiOjE3MDU1NzQ1ODQsInVzZXJfaWQiOjF9.mTcgBjKPrrKkjVtfmEk0MJyDI-8PQyKuXrzwr2w1_I8mwQq5lT6PkW9eMPNfCee2vdtxCj6HF_U2rN_yqcbgRA
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzY1LCJleHAiOjE3MDU2Nzc5NjUsInVzZXJfaWQiOjF9.7YEbtfN90q-vWJ47IdoUy79KtHJdjSEjVn16sm4glP5UUzuJG705VSJR740ZlBdwKCn5AUDGnOPRpxwSeUC6aA
 Accept: application/json
 Host: docs.api.com
@@ -1699,58 +1699,58 @@

Response

[ {
-  "postId" : 1908042653,
+  "postId" : 391756997,
   "writer" : {
-    "userId" : 934467639,
-    "nickname" : "alfredo.schmidt",
-    "image" : "http://www.king-huels.com:45991/nemo/et?quas=vero&debitis=consequatur#ut"
+    "userId" : 563328115,
+    "nickname" : "kraig.waters",
+    "image" : "http://www.ethyl-rau.net/fuga#et"
   },
-  "title" : "An Acceptable Time",
-  "content" : "Cobalt",
-  "image" : "https://www.lowell-rogahn.io:60654/#molestias",
-  "createdAt" : "2024-01-18T18:43:04.779531",
-  "updatedAt" : "2024-01-18T18:43:04.779548",
+  "title" : "The Green Bay Tree",
+  "content" : "Gold",
+  "image" : "https://www.andreas-waelchi.io:32924/",
+  "createdAt" : "2024-01-19T23:26:05.330447",
+  "updatedAt" : "2024-01-19T23:26:05.330461",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
   },
-  "likeCnt" : 54,
+  "likeCnt" : 93,
   "isLike" : 0
 }, {
-  "postId" : 976739760,
+  "postId" : 411854187,
   "writer" : {
-    "userId" : 1468392497,
-    "nickname" : "georgianne.yundt",
-    "image" : "http://www.sherilyn-pollich.org/dolores?cumque=magnam&dolor=nulla#deleniti"
+    "userId" : 845471690,
+    "nickname" : "eugena.spencer",
+    "image" : "https://www.chance-quitzon.io/explicabo/quo?fugiat=nesciunt&sit=necessitatibus#dicta"
   },
-  "title" : "The Little Foxes",
-  "content" : "Helium",
-  "image" : "https://www.georgette-hirthe.net/aperiam/optio?eum=molestiae&aut=officiis#illum",
-  "createdAt" : "2024-01-18T18:43:04.782134",
-  "updatedAt" : "2024-01-18T18:43:04.78215",
+  "title" : "Ah, Wilderness!",
+  "content" : "Cesium",
+  "image" : "https://www.lauralee-lowe.info/odio/non?vel=culpa&autem=sit",
+  "createdAt" : "2024-01-19T23:26:05.334196",
+  "updatedAt" : "2024-01-19T23:26:05.334205",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
   },
-  "likeCnt" : 55,
+  "likeCnt" : 58,
   "isLike" : 0
 }, {
-  "postId" : 1153411505,
+  "postId" : 1984546333,
   "writer" : {
-    "userId" : 682342469,
-    "nickname" : "marlin.nienow",
-    "image" : "https://www.darrick-kozey.io:61868/perspiciatis#quae"
+    "userId" : 1189354801,
+    "nickname" : "khalilah.kunze",
+    "image" : "https://www.rick-marquardt.info:65501/non/voluptatem"
   },
-  "title" : "Precious Bane",
-  "content" : "Potassium",
-  "image" : "http://www.corrine-west.biz/a/dolorem?sit=dolorem&molestias=aliquid",
-  "createdAt" : "2024-01-18T18:43:04.78255",
-  "updatedAt" : "2024-01-18T18:43:04.782565",
+  "title" : "Fair Stood the Wind for France",
+  "content" : "Lutetium",
+  "image" : "https://www.stephane-weber.co:62304/",
+  "createdAt" : "2024-01-19T23:26:05.334755",
+  "updatedAt" : "2024-01-19T23:26:05.334763",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
   },
-  "likeCnt" : 70,
+  "likeCnt" : 45,
   "isLike" : 0
 } ]
@@ -1845,61 +1845,61 @@

Respons Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Type: application/json -Content-Length: 1566 +Content-Length: 1487 [ { - "postId" : 1908042653, + "postId" : 391756997, "writer" : { - "userId" : 934467639, - "nickname" : "alfredo.schmidt", - "image" : "http://www.king-huels.com:45991/nemo/et?quas=vero&debitis=consequatur#ut" + "userId" : 563328115, + "nickname" : "kraig.waters", + "image" : "http://www.ethyl-rau.net/fuga#et" }, - "title" : "An Acceptable Time", - "content" : "Cobalt", - "image" : "https://www.lowell-rogahn.io:60654/#molestias", - "createdAt" : "2024-01-18T18:43:04.779531", - "updatedAt" : "2024-01-18T18:43:04.779548", + "title" : "The Green Bay Tree", + "content" : "Gold", + "image" : "https://www.andreas-waelchi.io:32924/", + "createdAt" : "2024-01-19T23:26:05.330447", + "updatedAt" : "2024-01-19T23:26:05.330461", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 }, - "likeCnt" : 54, + "likeCnt" : 93, "isLike" : 0 }, { - "postId" : 976739760, + "postId" : 411854187, "writer" : { - "userId" : 1468392497, - "nickname" : "georgianne.yundt", - "image" : "http://www.sherilyn-pollich.org/dolores?cumque=magnam&dolor=nulla#deleniti" + "userId" : 845471690, + "nickname" : "eugena.spencer", + "image" : "https://www.chance-quitzon.io/explicabo/quo?fugiat=nesciunt&sit=necessitatibus#dicta" }, - "title" : "The Little Foxes", - "content" : "Helium", - "image" : "https://www.georgette-hirthe.net/aperiam/optio?eum=molestiae&aut=officiis#illum", - "createdAt" : "2024-01-18T18:43:04.782134", - "updatedAt" : "2024-01-18T18:43:04.78215", + "title" : "Ah, Wilderness!", + "content" : "Cesium", + "image" : "https://www.lauralee-lowe.info/odio/non?vel=culpa&autem=sit", + "createdAt" : "2024-01-19T23:26:05.334196", + "updatedAt" : "2024-01-19T23:26:05.334205", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 }, - "likeCnt" : 55, + "likeCnt" : 58, "isLike" : 0 }, { - "postId" : 1153411505, + "postId" : 1984546333, "writer" : { - "userId" : 682342469, - "nickname" : "marlin.nienow", - "image" : "https://www.darrick-kozey.io:61868/perspiciatis#quae" + "userId" : 1189354801, + "nickname" : "khalilah.kunze", + "image" : "https://www.rick-marquardt.info:65501/non/voluptatem" }, - "title" : "Precious Bane", - "content" : "Potassium", - "image" : "http://www.corrine-west.biz/a/dolorem?sit=dolorem&molestias=aliquid", - "createdAt" : "2024-01-18T18:43:04.78255", - "updatedAt" : "2024-01-18T18:43:04.782565", + "title" : "Fair Stood the Wind for France", + "content" : "Lutetium", + "image" : "https://www.stephane-weber.co:62304/", + "createdAt" : "2024-01-19T23:26:05.334755", + "updatedAt" : "2024-01-19T23:26:05.334763", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 }, - "likeCnt" : 70, + "likeCnt" : 45, "isLike" : 0 } ]

@@ -2003,7 +2003,7 @@

Request
PUT /api/v1/posts/2 HTTP/1.1
 Content-Type: multipart/form-data;charset=UTF-8; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg0LCJleHAiOjE3MDU1NzQ1ODQsInVzZXJfaWQiOjF9.mTcgBjKPrrKkjVtfmEk0MJyDI-8PQyKuXrzwr2w1_I8mwQq5lT6PkW9eMPNfCee2vdtxCj6HF_U2rN_yqcbgRA
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzY1LCJleHAiOjE3MDU2Nzc5NjUsInVzZXJfaWQiOjF9.7YEbtfN90q-vWJ47IdoUy79KtHJdjSEjVn16sm4glP5UUzuJG705VSJR740ZlBdwKCn5AUDGnOPRpxwSeUC6aA
 Accept: application/json
 Host: docs.api.com
 
@@ -2011,7 +2011,7 @@ 

Request Content-Disposition: form-data; name=request; filename=request.json Content-Type: application/json -{"title":"Absalom, Absalom!","content":"Neodymium"} +{"title":"The Little Foxes","content":"Flerovium"} --6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm Content-Disposition: form-data; name=postImg; filename=image.jpeg Content-Type: image/jpeg @@ -2028,11 +2028,11 @@

Response

{
   "postId" : 2,
-  "title" : "Absalom, Absalom!",
-  "content" : "Neodymium",
-  "image" : "https://www.shelby-schaefer.name:21573/et/distinctiofugiat?magnam=consequatur&consectetur=doloremque#corrupti",
-  "createdAt" : "2024-01-18T18:43:04.934907",
-  "updatedAt" : "2024-01-18T18:43:04.934923",
+  "title" : "The Little Foxes",
+  "content" : "Flerovium",
+  "image" : "https://www.whitney-bogisich.org:25925/voluptas/sunt#reiciendis",
+  "createdAt" : "2024-01-19T23:26:05.741933",
+  "updatedAt" : "2024-01-19T23:26:05.741948",
   "temperatureArrange" : {
     "min" : 0.0,
     "max" : 15.0
@@ -2106,15 +2106,15 @@ 

Respo Vary: Access-Control-Request-Headers Location: /api/v1/posts/2 Content-Type: application/json -Content-Length: 361 +Content-Length: 314 { "postId" : 2, - "title" : "Absalom, Absalom!", - "content" : "Neodymium", - "image" : "https://www.shelby-schaefer.name:21573/et/distinctiofugiat?magnam=consequatur&consectetur=doloremque#corrupti", - "createdAt" : "2024-01-18T18:43:04.934907", - "updatedAt" : "2024-01-18T18:43:04.934923", + "title" : "The Little Foxes", + "content" : "Flerovium", + "image" : "https://www.whitney-bogisich.org:25925/voluptas/sunt#reiciendis", + "createdAt" : "2024-01-19T23:26:05.741933", + "updatedAt" : "2024-01-19T23:26:05.741948", "temperatureArrange" : { "min" : 0.0, "max" : 15.0 @@ -2190,8 +2190,8 @@

Request H

Request example

-
DELETE /api/v1/posts/1744803171 HTTP/1.1
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg0LCJleHAiOjE3MDU1NzQ1ODQsInVzZXJfaWQiOjF9.mTcgBjKPrrKkjVtfmEk0MJyDI-8PQyKuXrzwr2w1_I8mwQq5lT6PkW9eMPNfCee2vdtxCj6HF_U2rN_yqcbgRA
+
DELETE /api/v1/posts/367321063 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzY1LCJleHAiOjE3MDU2Nzc5NjUsInVzZXJfaWQiOjF9.7YEbtfN90q-vWJ47IdoUy79KtHJdjSEjVn16sm4glP5UUzuJG705VSJR740ZlBdwKCn5AUDGnOPRpxwSeUC6aA
 Host: docs.api.com
@@ -2256,7 +2256,7 @@

Request H
{
-  "postId" : 1251693879
+  "postId" : 134978164
 }
@@ -2286,15 +2286,15 @@

Request H

Request example

-
POST /api/v1/posts/1251693879/likes HTTP/1.1
+
POST /api/v1/posts/134978164/likes HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTgzLCJleHAiOjE3MDU1NzQ1ODMsInVzZXJfaWQiOjIxNDIzNzM3MjN9.soHfQaFbqHJl5xPC3moiDjk4fXWy9l0oTTliB9oSzqsfArjZKeBV5KuWtc_1cm4e1AO-PhBr2V4_m9h2Et_3vg
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzYyLCJleHAiOjE3MDU2Nzc5NjIsInVzZXJfaWQiOjExMjQ5OTI2Mn0.PeuawdOnk4BzLdNZY9_Hi_yz_1M6Di1-DM_Y10aBgj_EM0So8KEMOFhF4sjY-Wod8IAAr6K4UCYLo3ZoYlChww
 Accept: application/json
-Content-Length: 27
+Content-Length: 26
 Host: docs.api.com
 
 {
-  "postId" : 1251693879
+  "postId" : 134978164
 }
@@ -2305,9 +2305,9 @@

Response

@@ -2446,7 +2446,7 @@

Request
GET /api/v1/weather?nx=50&ny=127 HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1NTcwOTg3LCJleHAiOjE3MDU1NzQ1ODcsInVzZXJfaWQiOjF9.PXvjVy9boT_qqEC9Vt0SWy2OjUPPj3wbUtTJ5iUyh21-u3C9WfWh_gH2AvAqo3Cj6XWP0twgbUmBUlM_XYChFw
+Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvb3R3IiwiaWF0IjoxNzA1Njc0MzcyLCJleHAiOjE3MDU2Nzc5NzIsInVzZXJfaWQiOjF9.lvIkeLYQpvhX-M6GBQHaKGBKXKRolg_UMSGNMdfGmGqn2qTSNFVYmETKa6xHMxroNHXtsTy-9DlnRaCALseZ-g
 Accept: application/json
 Host: docs.api.com
@@ -2528,7 +2528,7 @@

Respo 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 4acccbb3..417607da 100644 --- a/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java +++ b/src/test/java/com/backendoori/ootw/avatar/controller/AvatarItemControllerTest.java @@ -8,6 +8,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; import com.backendoori.ootw.avatar.domain.Sex; import com.backendoori.ootw.avatar.dto.AvatarItemRequest; import com.backendoori.ootw.avatar.repository.AvatarItemRepository; @@ -18,6 +19,8 @@ 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; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; @@ -67,6 +70,27 @@ public void imageUploadTest() throws Exception { .andExpect(status().isCreated()); } + @ParameterizedTest + @MethodSource("provideInvalidAvatarImageInfo") + @DisplayName("아바타 이미지를 등록 시 ItemRequest 가 잘못되면 예외가 발생한다.") + public void imageUploadFailWithInvalidItemRequest(String itemType, String sex) throws Exception { + //given + MockMultipartFile file = new MockMultipartFile("file", "filename.txt", + "image/jpeg", "some xml".getBytes()); + AvatarItemRequest requestDto = new AvatarItemRequest(itemType, sex); + 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()); + } + @Test @DisplayName("아바타 등록 요청 중 이미지 등록 중 예외가 발생하면 커스텀 예외가 발생한다.") public void imageUploadException() throws Exception { @@ -185,4 +209,19 @@ public void getItemList() throws Exception { .andExpect(status().isOk()) .andDo(print()); } + + static Stream provideInvalidAvatarImageInfo() { + String validType = "HAIR"; + String validSex = "MALE"; + return java.util.stream.Stream.of( + Arguments.of(null, validSex), + Arguments.of(validType, null), + Arguments.of("", validSex), + Arguments.of(validType, ""), + Arguments.of(" ", validSex), + Arguments.of(validType, " "), + Arguments.of("hair", validSex), + Arguments.of(validType, "female") + ); + } }