From 527edda336d8ce9ceb3bcc987b50f369a54fa262 Mon Sep 17 00:00:00 2001 From: jinia91 Date: Sat, 26 Mar 2022 22:22:26 +0900 Subject: [PATCH] =?UTF-8?q?imgupload,=20comment=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=ED=97=A5=EC=82=AC=EA=B3=A0=EB=82=A0=20=EC=95=84=ED=82=A4?= =?UTF-8?q?=ED=85=8D=EC=B3=90=EB=A1=9C=20=EB=A6=AC=EC=95=84=ED=82=A4?= =?UTF-8?q?=ED=85=8D=EC=B3=90=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/imcomming/CategoryController.java | 4 +- .../imcomming/CategoryListValidator.java | 3 +- .../InvalidCategoryRequestException.java | 9 +++ .../incomming}/CommentController.java | 38 +++++----- .../incomming}/CommentForm.java | 2 +- .../InvalidCommentRequestException.java | 9 +++ .../persistence/CommentRepositoryAdapter.java | 48 +++++++++++++ .../persistence/JpaCommentRepository.java} | 4 +- .../MybatisCommentRepository.java} | 4 +- .../CommentService.java | 70 ++++++++++--------- .../port/incomming}/CommentDto.java | 6 +- .../port/incomming}/CommentDtoForLayout.java | 2 +- .../port/incomming/CommentUseCase.java | 13 ++++ .../port/outgoing/CommentRepositoryPort.java | 16 +++++ .../incomming/UploadImgController.java | 20 ++++++ .../incomming/UploadImgForm.java} | 7 +- .../AwsS3ImgUploadStrategyAdapter.java} | 14 ++-- .../GithubRepoImgUploadStrategyAdapter.java} | 8 +-- .../controller/UploadImgController.java | 27 ------- .../blog/imgupload/domain/ImageFile.java | 38 ++++++++++ .../imgupload/service/ImgUploadService.java | 32 +++++++-- .../service/ImgUploadServiceImpl.java | 51 -------------- .../imgupload/service/ImgUploadStrategy.java | 12 ---- .../port/incomming/ImgUploadUseCase.java | 9 +++ .../port/outgoing/ImgUploadStrategyPort.java | 10 +++ .../member/controller/MemberController.java | 4 +- .../shared/exception/CustomFormException.java | 9 --- .../ExceptionRestControllerAdvice.java | 3 +- .../queries/LayoutRenderingQueries.java | 4 +- 29 files changed, 284 insertions(+), 192 deletions(-) create mode 100644 src/main/java/myblog/blog/category/adapter/imcomming/InvalidCategoryRequestException.java rename src/main/java/myblog/blog/comment/{controller => adapter/incomming}/CommentController.java (58%) rename src/main/java/myblog/blog/comment/{dto => adapter/incomming}/CommentForm.java (89%) create mode 100644 src/main/java/myblog/blog/comment/adapter/incomming/InvalidCommentRequestException.java create mode 100644 src/main/java/myblog/blog/comment/adapter/outgoing/persistence/CommentRepositoryAdapter.java rename src/main/java/myblog/blog/comment/{repository/CommentRepository.java => adapter/outgoing/persistence/JpaCommentRepository.java} (87%) rename src/main/java/myblog/blog/comment/{repository/NaCommentRepository.java => adapter/outgoing/persistence/MybatisCommentRepository.java} (72%) rename src/main/java/myblog/blog/comment/{service => application}/CommentService.java (63%) rename src/main/java/myblog/blog/comment/{dto => application/port/incomming}/CommentDto.java (95%) rename src/main/java/myblog/blog/comment/{dto => application/port/incomming}/CommentDtoForLayout.java (90%) create mode 100644 src/main/java/myblog/blog/comment/application/port/incomming/CommentUseCase.java create mode 100644 src/main/java/myblog/blog/comment/application/port/outgoing/CommentRepositoryPort.java create mode 100644 src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgController.java rename src/main/java/myblog/blog/imgupload/{dto/UploadImgDto.java => adapter/incomming/UploadImgForm.java} (58%) rename src/main/java/myblog/blog/imgupload/{service/AwsS3ImgUploadStrategy.java => adapter/outgoing/AwsS3ImgUploadStrategyAdapter.java} (70%) rename src/main/java/myblog/blog/imgupload/{service/GithubRepoImgUploadStrategy.java => adapter/outgoing/GithubRepoImgUploadStrategyAdapter.java} (85%) delete mode 100644 src/main/java/myblog/blog/imgupload/controller/UploadImgController.java create mode 100644 src/main/java/myblog/blog/imgupload/domain/ImageFile.java delete mode 100644 src/main/java/myblog/blog/imgupload/service/ImgUploadServiceImpl.java delete mode 100644 src/main/java/myblog/blog/imgupload/service/ImgUploadStrategy.java create mode 100644 src/main/java/myblog/blog/imgupload/service/port/incomming/ImgUploadUseCase.java create mode 100644 src/main/java/myblog/blog/imgupload/service/port/outgoing/ImgUploadStrategyPort.java delete mode 100644 src/main/java/myblog/blog/shared/exception/CustomFormException.java diff --git a/src/main/java/myblog/blog/category/adapter/imcomming/CategoryController.java b/src/main/java/myblog/blog/category/adapter/imcomming/CategoryController.java index 3a884ca..ba35061 100644 --- a/src/main/java/myblog/blog/category/adapter/imcomming/CategoryController.java +++ b/src/main/java/myblog/blog/category/adapter/imcomming/CategoryController.java @@ -5,8 +5,8 @@ import lombok.RequiredArgsConstructor; import myblog.blog.category.appliacation.port.incomming.CategoryUseCase; import myblog.blog.category.appliacation.port.response.CategoryViewForLayout; import myblog.blog.category.appliacation.port.response.CategorySimpleDto; -import myblog.blog.comment.dto.CommentDtoForLayout; -import myblog.blog.comment.service.CommentService; +import myblog.blog.comment.application.port.incomming.CommentDtoForLayout; +import myblog.blog.comment.application.CommentService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/src/main/java/myblog/blog/category/adapter/imcomming/CategoryListValidator.java b/src/main/java/myblog/blog/category/adapter/imcomming/CategoryListValidator.java index 1d94a72..9583540 100644 --- a/src/main/java/myblog/blog/category/adapter/imcomming/CategoryListValidator.java +++ b/src/main/java/myblog/blog/category/adapter/imcomming/CategoryListValidator.java @@ -1,7 +1,6 @@ package myblog.blog.category.adapter.imcomming; import lombok.RequiredArgsConstructor; -import myblog.blog.shared.exception.CustomFormException; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.Validator; @@ -31,7 +30,7 @@ public class CategoryListValidator implements Validator { springValidatorAdapter.validate(object,errors); } if (errors.hasErrors()) { - throw new CustomFormException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage()); + throw new InvalidCategoryRequestException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage()); } } } diff --git a/src/main/java/myblog/blog/category/adapter/imcomming/InvalidCategoryRequestException.java b/src/main/java/myblog/blog/category/adapter/imcomming/InvalidCategoryRequestException.java new file mode 100644 index 0000000..487d49d --- /dev/null +++ b/src/main/java/myblog/blog/category/adapter/imcomming/InvalidCategoryRequestException.java @@ -0,0 +1,9 @@ +package myblog.blog.category.adapter.imcomming; +/* + - REST 컨트롤러 상태 메세지 전송용 커스텀 에러 +*/ +public class InvalidCategoryRequestException extends RuntimeException { + public InvalidCategoryRequestException(String message) { + super(message); + } +} diff --git a/src/main/java/myblog/blog/comment/controller/CommentController.java b/src/main/java/myblog/blog/comment/adapter/incomming/CommentController.java similarity index 58% rename from src/main/java/myblog/blog/comment/controller/CommentController.java rename to src/main/java/myblog/blog/comment/adapter/incomming/CommentController.java index 6c7cdba..c836f29 100644 --- a/src/main/java/myblog/blog/comment/controller/CommentController.java +++ b/src/main/java/myblog/blog/comment/adapter/incomming/CommentController.java @@ -1,35 +1,31 @@ -package myblog.blog.comment.controller; +package myblog.blog.comment.adapter.incomming; + +import myblog.blog.comment.application.port.incomming.CommentUseCase; +import myblog.blog.comment.application.port.incomming.CommentDto; + +import myblog.blog.member.auth.PrincipalDetails; + +import myblog.blog.member.doamin.Member; import lombok.RequiredArgsConstructor; -import myblog.blog.article.application.port.incomming.ArticleQueriesUseCase; -import myblog.blog.article.domain.Article; -import myblog.blog.article.application.ArticleService; -import myblog.blog.comment.dto.CommentDto; -import myblog.blog.comment.dto.CommentForm; -import myblog.blog.comment.service.CommentService; -import myblog.blog.shared.exception.CustomFormException; -import myblog.blog.member.auth.PrincipalDetails; -import myblog.blog.member.doamin.Member; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.Errors; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Objects; +import java.util.*; @RestController @RequiredArgsConstructor public class CommentController { - private final CommentService commentService; + private final CommentUseCase commentUseCase; /* - 아티클 조회시 아티클에 달린 댓글들 전체 조회 */ @GetMapping("/comment/list/{articleId}") public List getCommentList(@PathVariable Long articleId){ - return CommentDto.listCreateFrom(commentService.getCommentList(articleId),0); + return commentUseCase.getCommentList(articleId); } /* @@ -41,19 +37,19 @@ public class CommentController { @Validated @RequestBody CommentForm commentForm, Errors errors, @AuthenticationPrincipal PrincipalDetails principal){ if (errors.hasErrors()) { - throw new CustomFormException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage()); + throw new InvalidCommentRequestException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage()); } Member member = principal.getMember(); // 부모 댓글인지 자식댓글인지 분기로 저장 if(parentId != null){ - commentService.saveCComment(commentForm, member, articleId, parentId); + commentUseCase.saveCComment(commentForm.getContent(), commentForm.isSecret(), member, articleId, parentId); } else { - commentService.savePComment(commentForm, member, articleId); + commentUseCase.savePComment(commentForm.getContent(), commentForm.isSecret(), member, articleId); } - return CommentDto.listCreateFrom(commentService.getCommentList(articleId),0); + return commentUseCase.getCommentList(articleId); } /* @@ -62,7 +58,7 @@ public class CommentController { @PostMapping("/comment/delete") public List deleteComment(@RequestParam Long articleId, @RequestParam Long commentId) { - commentService.deleteComment(commentId); - return CommentDto.listCreateFrom(commentService.getCommentList(articleId),0); + commentUseCase.deleteComment(commentId); + return commentUseCase.getCommentList(articleId); } } diff --git a/src/main/java/myblog/blog/comment/dto/CommentForm.java b/src/main/java/myblog/blog/comment/adapter/incomming/CommentForm.java similarity index 89% rename from src/main/java/myblog/blog/comment/dto/CommentForm.java rename to src/main/java/myblog/blog/comment/adapter/incomming/CommentForm.java index 4a8ed0c..5958b2a 100644 --- a/src/main/java/myblog/blog/comment/dto/CommentForm.java +++ b/src/main/java/myblog/blog/comment/adapter/incomming/CommentForm.java @@ -1,4 +1,4 @@ -package myblog.blog.comment.dto; +package myblog.blog.comment.adapter.incomming; import lombok.Data; diff --git a/src/main/java/myblog/blog/comment/adapter/incomming/InvalidCommentRequestException.java b/src/main/java/myblog/blog/comment/adapter/incomming/InvalidCommentRequestException.java new file mode 100644 index 0000000..6fdc89d --- /dev/null +++ b/src/main/java/myblog/blog/comment/adapter/incomming/InvalidCommentRequestException.java @@ -0,0 +1,9 @@ +package myblog.blog.comment.adapter.incomming; +/* + - REST 컨트롤러 상태 메세지 전송용 커스텀 에러 +*/ +public class InvalidCommentRequestException extends RuntimeException { + public InvalidCommentRequestException(String message) { + super(message); + } +} diff --git a/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/CommentRepositoryAdapter.java b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/CommentRepositoryAdapter.java new file mode 100644 index 0000000..bfd0c42 --- /dev/null +++ b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/CommentRepositoryAdapter.java @@ -0,0 +1,48 @@ +package myblog.blog.comment.adapter.outgoing.persistence; + +import lombok.RequiredArgsConstructor; +import myblog.blog.comment.application.port.outgoing.CommentRepositoryPort; +import myblog.blog.article.domain.Article; +import myblog.blog.comment.domain.Comment; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class CommentRepositoryAdapter implements CommentRepositoryPort { + private final JpaCommentRepository jpaCommentRepository; + private final MybatisCommentRepository mybatisCommentRepository; + + + @Override + public int countCommentsByArticleAndTier(Article article, int tier) { + return jpaCommentRepository.countCommentsByArticleAndTier(article, tier); + } + + @Override + public void save(Comment comment) { + jpaCommentRepository.save(comment); + } + + @Override + public List findCommentsByArticleId(Long articleId) { + return jpaCommentRepository.findCommentsByArticleId(articleId); + } + + @Override + public void deleteComment(Long commentId) { + mybatisCommentRepository.deleteComment(commentId); + } + + @Override + public List findTop5ByOrderByIdDesc() { + return jpaCommentRepository.findTop5ByOrderByIdDesc(); + } + + @Override + public Optional findById(Long parentId) { + return jpaCommentRepository.findById(parentId); + } +} diff --git a/src/main/java/myblog/blog/comment/repository/CommentRepository.java b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/JpaCommentRepository.java similarity index 87% rename from src/main/java/myblog/blog/comment/repository/CommentRepository.java rename to src/main/java/myblog/blog/comment/adapter/outgoing/persistence/JpaCommentRepository.java index 84dbdd7..5f089a2 100644 --- a/src/main/java/myblog/blog/comment/repository/CommentRepository.java +++ b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/JpaCommentRepository.java @@ -1,4 +1,4 @@ -package myblog.blog.comment.repository; +package myblog.blog.comment.adapter.outgoing.persistence; import myblog.blog.article.domain.Article; import myblog.blog.comment.domain.Comment; @@ -8,7 +8,7 @@ import org.springframework.data.repository.query.Param; import java.util.List; -public interface CommentRepository extends JpaRepository { +public interface JpaCommentRepository extends JpaRepository { /* - 특정 아티클에 해당하는 댓글 리스트 가져오기 diff --git a/src/main/java/myblog/blog/comment/repository/NaCommentRepository.java b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/MybatisCommentRepository.java similarity index 72% rename from src/main/java/myblog/blog/comment/repository/NaCommentRepository.java rename to src/main/java/myblog/blog/comment/adapter/outgoing/persistence/MybatisCommentRepository.java index 0a3d740..7fa9db5 100644 --- a/src/main/java/myblog/blog/comment/repository/NaCommentRepository.java +++ b/src/main/java/myblog/blog/comment/adapter/outgoing/persistence/MybatisCommentRepository.java @@ -1,10 +1,10 @@ -package myblog.blog.comment.repository; +package myblog.blog.comment.adapter.outgoing.persistence; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface NaCommentRepository { +public interface MybatisCommentRepository { /* - cascade 삭제처리 diff --git a/src/main/java/myblog/blog/comment/service/CommentService.java b/src/main/java/myblog/blog/comment/application/CommentService.java similarity index 63% rename from src/main/java/myblog/blog/comment/service/CommentService.java rename to src/main/java/myblog/blog/comment/application/CommentService.java index be405f1..58c47db 100644 --- a/src/main/java/myblog/blog/comment/service/CommentService.java +++ b/src/main/java/myblog/blog/comment/application/CommentService.java @@ -1,57 +1,57 @@ -package myblog.blog.comment.service; +package myblog.blog.comment.application; + +import myblog.blog.article.application.port.incomming.ArticleUseCase; +import myblog.blog.comment.application.port.incomming.CommentUseCase; +import myblog.blog.comment.application.port.incomming.CommentDto; +import myblog.blog.comment.application.port.incomming.CommentDtoForLayout; +import myblog.blog.comment.application.port.outgoing.CommentRepositoryPort; + +import myblog.blog.comment.domain.Comment; +import myblog.blog.article.domain.Article; +import myblog.blog.member.doamin.Member; import lombok.RequiredArgsConstructor; -import myblog.blog.article.application.port.incomming.ArticleUseCase; -import myblog.blog.article.domain.Article; -import myblog.blog.comment.domain.Comment; -import myblog.blog.comment.dto.CommentDtoForLayout; -import myblog.blog.comment.dto.CommentForm; -import myblog.blog.comment.repository.CommentRepository; -import myblog.blog.comment.repository.NaCommentRepository; -import myblog.blog.member.doamin.Member; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - import java.util.List; import java.util.stream.Collectors; @Service @Transactional @RequiredArgsConstructor -public class CommentService { - +public class CommentService implements CommentUseCase { private final ArticleUseCase articleUseCase; - - private final CommentRepository commentRepository; - private final NaCommentRepository naCommentRepository; + private final CommentRepositoryPort commentRepositoryPort; /* - 아티클에 달린 댓글 전체 가져오기 */ - public List getCommentList(Long articleId){ - return commentRepository.findCommentsByArticleId(articleId); + @Override + public List getCommentList(Long articleId){ + return CommentDto.listCreateFrom(commentRepositoryPort.findCommentsByArticleId(articleId),0); } /* - 부모 댓글 저장 */ @CacheEvict(value = "layoutRecentCommentCaching", allEntries = true) - public void savePComment(CommentForm commentForm, Member member, Long articleId){ + @Override + public void savePComment(String content, boolean secret, Member member, Long articleId){ Article article = articleUseCase.getArticle(articleId); Comment comment = Comment.builder() .article(article) - .content(removeDuplicatedEnter(commentForm)) + .content(removeDuplicatedEnter(content)) .tier(0) - .pOrder(commentRepository.countCommentsByArticleAndTier(article,0)+1) + .pOrder(commentRepositoryPort.countCommentsByArticleAndTier(article,0)+1) .member(member) - .secret(commentForm.isSecret()) + .secret(secret) .build(); - commentRepository.save(comment); + commentRepositoryPort.save(comment); } @@ -59,22 +59,24 @@ public class CommentService { - 자식 댓글 저장 */ @CacheEvict(value = "layoutRecentCommentCaching", allEntries = true) - public void saveCComment(CommentForm commentForm, Member member, Long articleId, Long parentId) { + @Override + public void saveCComment(String content, boolean secret, Member member, Long articleId, Long parentId) { Article article = articleUseCase.getArticle(articleId); - Comment pComment = commentRepository.findById(parentId).get(); + Comment pComment = commentRepositoryPort.findById(parentId) + .orElseThrow(() -> new IllegalArgumentException("NotfoundParentCommentException")); Comment comment = Comment.builder() .article(article) - .content(removeDuplicatedEnter(commentForm)) + .content(removeDuplicatedEnter(content)) .tier(1) .pOrder(pComment.getPOrder()) .member(member) .parents(pComment) - .secret(commentForm.isSecret()) + .secret(secret) .build(); - commentRepository.save(comment); + commentRepositoryPort.save(comment); } @@ -82,8 +84,9 @@ public class CommentService { - 댓글 삭제 */ @CacheEvict(value = "layoutRecentCommentCaching", allEntries = true) + @Override public void deleteComment(Long commentId){ - naCommentRepository.deleteComment(commentId); + commentRepositoryPort.deleteComment(commentId); } /* @@ -93,8 +96,9 @@ public class CommentService { DTO 매핑 로직 서비스단에서 처리 */ @Cacheable(value = "layoutRecentCommentCaching", key = "0") + @Override public List recentCommentList(){ - return commentRepository.findTop5ByOrderByIdDesc() + return commentRepositoryPort.findTop5ByOrderByIdDesc() .stream() .map(comment -> new CommentDtoForLayout(comment.getId(), comment.getArticle().getId(), comment.getContent(), comment.isSecret())) @@ -104,15 +108,15 @@ public class CommentService { /* - 중복 개행 개행 하나로 압축 알고리즘 */ - private String removeDuplicatedEnter(CommentForm commentForm) { + private String removeDuplicatedEnter(String content) { - char[] contentBox = new char[commentForm.getContent().length()]; + char[] contentBox = new char[content.length()]; int idx = 0; String zipWord = "\n\n"; - for(int i = 0; i< commentForm.getContent().length(); i++){ + for(int i = 0; i< content.length(); i++){ - contentBox[idx] = commentForm.getContent().charAt(i); + contentBox[idx] = content.charAt(i); if(contentBox[idx] == '\n'&&idx >= 1){ diff --git a/src/main/java/myblog/blog/comment/dto/CommentDto.java b/src/main/java/myblog/blog/comment/application/port/incomming/CommentDto.java similarity index 95% rename from src/main/java/myblog/blog/comment/dto/CommentDto.java rename to src/main/java/myblog/blog/comment/application/port/incomming/CommentDto.java index 0598829..07eea20 100644 --- a/src/main/java/myblog/blog/comment/dto/CommentDto.java +++ b/src/main/java/myblog/blog/comment/application/port/incomming/CommentDto.java @@ -1,13 +1,11 @@ -package myblog.blog.comment.dto; +package myblog.blog.comment.application.port.incomming; import lombok.Getter; import lombok.Setter; import myblog.blog.comment.domain.Comment; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; /* diff --git a/src/main/java/myblog/blog/comment/dto/CommentDtoForLayout.java b/src/main/java/myblog/blog/comment/application/port/incomming/CommentDtoForLayout.java similarity index 90% rename from src/main/java/myblog/blog/comment/dto/CommentDtoForLayout.java rename to src/main/java/myblog/blog/comment/application/port/incomming/CommentDtoForLayout.java index ef3bad5..57e90e9 100644 --- a/src/main/java/myblog/blog/comment/dto/CommentDtoForLayout.java +++ b/src/main/java/myblog/blog/comment/application/port/incomming/CommentDtoForLayout.java @@ -1,4 +1,4 @@ -package myblog.blog.comment.dto; +package myblog.blog.comment.application.port.incomming; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/myblog/blog/comment/application/port/incomming/CommentUseCase.java b/src/main/java/myblog/blog/comment/application/port/incomming/CommentUseCase.java new file mode 100644 index 0000000..b122877 --- /dev/null +++ b/src/main/java/myblog/blog/comment/application/port/incomming/CommentUseCase.java @@ -0,0 +1,13 @@ +package myblog.blog.comment.application.port.incomming; + +import myblog.blog.member.doamin.Member; + +import java.util.List; + +public interface CommentUseCase { + List getCommentList(Long articleId); + void savePComment(String content, boolean secret, Member member, Long articleId); + void saveCComment(String content, boolean secret, Member member, Long articleId, Long parentId); + void deleteComment(Long commentId); + List recentCommentList(); +} diff --git a/src/main/java/myblog/blog/comment/application/port/outgoing/CommentRepositoryPort.java b/src/main/java/myblog/blog/comment/application/port/outgoing/CommentRepositoryPort.java new file mode 100644 index 0000000..2f11289 --- /dev/null +++ b/src/main/java/myblog/blog/comment/application/port/outgoing/CommentRepositoryPort.java @@ -0,0 +1,16 @@ +package myblog.blog.comment.application.port.outgoing; + +import myblog.blog.article.domain.Article; +import myblog.blog.comment.domain.Comment; + +import java.util.List; +import java.util.Optional; + +public interface CommentRepositoryPort { + int countCommentsByArticleAndTier(Article article, int tier); + void save(Comment comment); + List findCommentsByArticleId(Long articleId); + void deleteComment(Long commentId); + List findTop5ByOrderByIdDesc(); + Optional findById(Long parentId); +} diff --git a/src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgController.java b/src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgController.java new file mode 100644 index 0000000..6a2887b --- /dev/null +++ b/src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgController.java @@ -0,0 +1,20 @@ +package myblog.blog.imgupload.adapter.incomming; + +import myblog.blog.imgupload.service.port.incomming.ImgUploadUseCase; + +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; +import java.io.IOException; + +@RestController +@RequiredArgsConstructor +public class UploadImgController { + + private final ImgUploadUseCase imgUploadUseCase; + + @PostMapping("/article/uploadImg") + public @ResponseBody + String imgUpload(@ModelAttribute UploadImgForm uploadImgForm) throws IOException { + return imgUploadUseCase.storeImg(uploadImgForm.getImg()); + } +} diff --git a/src/main/java/myblog/blog/imgupload/dto/UploadImgDto.java b/src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgForm.java similarity index 58% rename from src/main/java/myblog/blog/imgupload/dto/UploadImgDto.java rename to src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgForm.java index af758ae..e5e3149 100644 --- a/src/main/java/myblog/blog/imgupload/dto/UploadImgDto.java +++ b/src/main/java/myblog/blog/imgupload/adapter/incomming/UploadImgForm.java @@ -1,14 +1,11 @@ -package myblog.blog.imgupload.dto; +package myblog.blog.imgupload.adapter.incomming; import lombok.Getter; import lombok.Setter; import org.springframework.web.multipart.MultipartFile; -/* - - 멀티파트 파일 래핑용 DTO -*/ @Getter @Setter -public class UploadImgDto { +public class UploadImgForm { private MultipartFile img; } diff --git a/src/main/java/myblog/blog/imgupload/service/AwsS3ImgUploadStrategy.java b/src/main/java/myblog/blog/imgupload/adapter/outgoing/AwsS3ImgUploadStrategyAdapter.java similarity index 70% rename from src/main/java/myblog/blog/imgupload/service/AwsS3ImgUploadStrategy.java rename to src/main/java/myblog/blog/imgupload/adapter/outgoing/AwsS3ImgUploadStrategyAdapter.java index 8d1beff..dbe1fe3 100644 --- a/src/main/java/myblog/blog/imgupload/service/AwsS3ImgUploadStrategy.java +++ b/src/main/java/myblog/blog/imgupload/adapter/outgoing/AwsS3ImgUploadStrategyAdapter.java @@ -1,8 +1,10 @@ -package myblog.blog.imgupload.service; +package myblog.blog.imgupload.adapter.outgoing; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.*; import lombok.RequiredArgsConstructor; +import myblog.blog.imgupload.domain.ImageFile; +import myblog.blog.imgupload.service.port.outgoing.ImgUploadStrategyPort; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -15,22 +17,22 @@ import java.io.InputStream; */ @RequiredArgsConstructor @Service -public class AwsS3ImgUploadStrategy implements ImgUploadStrategy { +public class AwsS3ImgUploadStrategyAdapter implements ImgUploadStrategyPort { private final AmazonS3 amazonS3; @Value("${cloud.aws.s3.bucket}") private String bucket; - @Override - public String uploadFile(MultipartFile file, String storeFileName) { + public String uploadFile(ImageFile imageFile) { + MultipartFile file = imageFile.getMultipartFile(); ObjectMetadata metadata = createObjectMetadata(file); try(InputStream inputStream = file.getInputStream()) { - amazonS3.putObject(new PutObjectRequest(bucket, storeFileName, inputStream, metadata) + amazonS3.putObject(new PutObjectRequest(bucket, imageFile.getStoredFileName(), inputStream, metadata) .withCannedAcl(CannedAccessControlList.PublicRead)); } catch (IOException e) { throw new IllegalArgumentException("파일 업로드에 실패했습니다."); } - return amazonS3.getUrl(bucket, storeFileName).toString(); + return amazonS3.getUrl(bucket, imageFile.getStoredFileName()).toString(); } /** diff --git a/src/main/java/myblog/blog/imgupload/service/GithubRepoImgUploadStrategy.java b/src/main/java/myblog/blog/imgupload/adapter/outgoing/GithubRepoImgUploadStrategyAdapter.java similarity index 85% rename from src/main/java/myblog/blog/imgupload/service/GithubRepoImgUploadStrategy.java rename to src/main/java/myblog/blog/imgupload/adapter/outgoing/GithubRepoImgUploadStrategyAdapter.java index cb860ec..0f78c13 100644 --- a/src/main/java/myblog/blog/imgupload/service/GithubRepoImgUploadStrategy.java +++ b/src/main/java/myblog/blog/imgupload/adapter/outgoing/GithubRepoImgUploadStrategyAdapter.java @@ -1,11 +1,9 @@ -package myblog.blog.imgupload.service; +package myblog.blog.imgupload.adapter.outgoing; -import lombok.RequiredArgsConstructor; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; import org.kohsuke.github.GitHubBuilder; import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -15,7 +13,8 @@ import java.io.IOException; */ //@RequiredArgsConstructor //@Service -public class GithubRepoImgUploadStrategy implements ImgUploadStrategy { +@Deprecated +public class GithubRepoImgUploadStrategyAdapter { /* - 설정 파일로 잡아놓은 깃헙 이미지 레포지토리와 토큰 @@ -34,7 +33,6 @@ public class GithubRepoImgUploadStrategy implements ImgUploadStrategy { 1. 깃허브 Repo에 이미지 업로드 2. 업로드된 Url 반환 */ - @Override public String uploadFile(MultipartFile multipartFile, String storeFileName) throws IOException { GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build(); GHRepository repository = gitHub.getRepository(gitRepo); diff --git a/src/main/java/myblog/blog/imgupload/controller/UploadImgController.java b/src/main/java/myblog/blog/imgupload/controller/UploadImgController.java deleted file mode 100644 index 4183887..0000000 --- a/src/main/java/myblog/blog/imgupload/controller/UploadImgController.java +++ /dev/null @@ -1,27 +0,0 @@ -package myblog.blog.imgupload.controller; - -import lombok.RequiredArgsConstructor; -import myblog.blog.imgupload.dto.UploadImgDto; -import myblog.blog.imgupload.service.ImgUploadServiceImpl; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; - -@RestController -@RequiredArgsConstructor -public class UploadImgController { - - private final ImgUploadServiceImpl imgUploadServiceImpl; - - /* - - 썸네일 업로드 요청 - */ - @PostMapping("/article/uploadImg") - public @ResponseBody - String imgUpload(@ModelAttribute UploadImgDto uploadImgDto) throws IOException { - return imgUploadServiceImpl.storeImg(uploadImgDto.getImg()); - } -} diff --git a/src/main/java/myblog/blog/imgupload/domain/ImageFile.java b/src/main/java/myblog/blog/imgupload/domain/ImageFile.java new file mode 100644 index 0000000..6510737 --- /dev/null +++ b/src/main/java/myblog/blog/imgupload/domain/ImageFile.java @@ -0,0 +1,38 @@ +package myblog.blog.imgupload.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.web.multipart.MultipartFile; + +import java.util.UUID; + +@Getter +@AllArgsConstructor +public class ImageFile { + String originalFileName; + String storedFileName; + MultipartFile multipartFile; + + static public ImageFile from(MultipartFile multipartFile){ + return new ImageFile(multipartFile.getOriginalFilename(), + createStoreFileName(multipartFile.getOriginalFilename()), + multipartFile + ); + } + + /* + - 이미지 중복 방지용 무작위 파일 이름 생성기 + */ + private static String createStoreFileName(String originalFilename) { + String ext = extractExt(originalFilename); + String uuid = UUID.randomUUID().toString(); + return uuid + "." + ext; + } + /* + - 파일 이름 추출 + */ + private static String extractExt(String originalFilename) { + int pos = originalFilename.lastIndexOf("."); + return originalFilename.substring(pos + 1); + } +} diff --git a/src/main/java/myblog/blog/imgupload/service/ImgUploadService.java b/src/main/java/myblog/blog/imgupload/service/ImgUploadService.java index 7baf9ca..f5813cb 100644 --- a/src/main/java/myblog/blog/imgupload/service/ImgUploadService.java +++ b/src/main/java/myblog/blog/imgupload/service/ImgUploadService.java @@ -1,9 +1,33 @@ package myblog.blog.imgupload.service; +import lombok.RequiredArgsConstructor; +import myblog.blog.imgupload.domain.ImageFile; +import myblog.blog.imgupload.service.port.incomming.ImgUploadUseCase; +import myblog.blog.imgupload.service.port.outgoing.ImgUploadStrategyPort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.util.List; +import java.io.IOException; +import java.util.UUID; -public interface ImgUploadService { - List storeFile(List imgList); -} +@Service +@Transactional +@RequiredArgsConstructor +public class ImgUploadService implements ImgUploadUseCase { + + private final ImgUploadStrategyPort imgUploadStrategyPort; + + @Override + public String storeImg(MultipartFile multipartFile) { + validateFile(multipartFile); + ImageFile imageFile = ImageFile.from(multipartFile); + return imgUploadStrategyPort.uploadFile(imageFile); + } + + private void validateFile(MultipartFile multipartFile) { + if (multipartFile.isEmpty()) { + throw new IllegalArgumentException("이미지가 존재하지 않습니다."); + } + } +} \ No newline at end of file diff --git a/src/main/java/myblog/blog/imgupload/service/ImgUploadServiceImpl.java b/src/main/java/myblog/blog/imgupload/service/ImgUploadServiceImpl.java deleted file mode 100644 index 0a7949a..0000000 --- a/src/main/java/myblog/blog/imgupload/service/ImgUploadServiceImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -package myblog.blog.imgupload.service; - -import lombok.RequiredArgsConstructor; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GitHub; -import org.kohsuke.github.GitHubBuilder; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.util.UUID; - -@Service -@Transactional -@RequiredArgsConstructor -public class ImgUploadServiceImpl { - - private final ImgUploadStrategy imgUploadStrategy; - - public String storeImg(MultipartFile multipartFile) throws IOException { - validateFile(multipartFile); - String storeFileName = createStoreFileName(multipartFile.getOriginalFilename()); - return imgUploadStrategy.uploadFile(multipartFile, storeFileName); - } - - private void validateFile(MultipartFile multipartFile) { - if (multipartFile.isEmpty()) { - throw new IllegalArgumentException("이미지가 존재하지 않습니다."); - } - } - - /* - - 이미지 중복 방지용 무작위 파일 이름 생성기 - */ - private String createStoreFileName(String originalFilename) { - String ext = extractExt(originalFilename); - String uuid = UUID.randomUUID().toString(); - return uuid + "." + ext; - } - - /* - - 파일 이름 추출 - */ - private String extractExt(String originalFilename) { - int pos = originalFilename.lastIndexOf("."); - return originalFilename.substring(pos + 1); - } - -} \ No newline at end of file diff --git a/src/main/java/myblog/blog/imgupload/service/ImgUploadStrategy.java b/src/main/java/myblog/blog/imgupload/service/ImgUploadStrategy.java deleted file mode 100644 index db6f32f..0000000 --- a/src/main/java/myblog/blog/imgupload/service/ImgUploadStrategy.java +++ /dev/null @@ -1,12 +0,0 @@ -package myblog.blog.imgupload.service; - -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; - -/** - * 파일 업로드 전략패턴 추상화 인터페이스 - */ -public interface ImgUploadStrategy { - String uploadFile(MultipartFile file, String storeFileName) throws IOException; -} diff --git a/src/main/java/myblog/blog/imgupload/service/port/incomming/ImgUploadUseCase.java b/src/main/java/myblog/blog/imgupload/service/port/incomming/ImgUploadUseCase.java new file mode 100644 index 0000000..1cae642 --- /dev/null +++ b/src/main/java/myblog/blog/imgupload/service/port/incomming/ImgUploadUseCase.java @@ -0,0 +1,9 @@ +package myblog.blog.imgupload.service.port.incomming; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +public interface ImgUploadUseCase { + String storeImg(MultipartFile img); +} diff --git a/src/main/java/myblog/blog/imgupload/service/port/outgoing/ImgUploadStrategyPort.java b/src/main/java/myblog/blog/imgupload/service/port/outgoing/ImgUploadStrategyPort.java new file mode 100644 index 0000000..92dc274 --- /dev/null +++ b/src/main/java/myblog/blog/imgupload/service/port/outgoing/ImgUploadStrategyPort.java @@ -0,0 +1,10 @@ +package myblog.blog.imgupload.service.port.outgoing; + +import myblog.blog.imgupload.domain.ImageFile; + +/** + * 파일 업로드 전략패턴 추상화 인터페이스 + */ +public interface ImgUploadStrategyPort { + String uploadFile(ImageFile imageFile); +} diff --git a/src/main/java/myblog/blog/member/controller/MemberController.java b/src/main/java/myblog/blog/member/controller/MemberController.java index d04ec30..0577906 100644 --- a/src/main/java/myblog/blog/member/controller/MemberController.java +++ b/src/main/java/myblog/blog/member/controller/MemberController.java @@ -3,8 +3,8 @@ package myblog.blog.member.controller; import lombok.RequiredArgsConstructor; import myblog.blog.category.appliacation.port.response.CategoryViewForLayout; import myblog.blog.category.appliacation.CategoryService; -import myblog.blog.comment.dto.CommentDtoForLayout; -import myblog.blog.comment.service.CommentService; +import myblog.blog.comment.application.port.incomming.CommentDtoForLayout; +import myblog.blog.comment.application.CommentService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/myblog/blog/shared/exception/CustomFormException.java b/src/main/java/myblog/blog/shared/exception/CustomFormException.java deleted file mode 100644 index 3af30fa..0000000 --- a/src/main/java/myblog/blog/shared/exception/CustomFormException.java +++ /dev/null @@ -1,9 +0,0 @@ -package myblog.blog.shared.exception; -/* - - REST 컨트롤러 상태 메세지 전송용 커스텀 에러 -*/ -public class CustomFormException extends RuntimeException { - public CustomFormException(String message) { - super(message); - } -} diff --git a/src/main/java/myblog/blog/shared/exception/ExceptionRestControllerAdvice.java b/src/main/java/myblog/blog/shared/exception/ExceptionRestControllerAdvice.java index 96910c5..309f272 100644 --- a/src/main/java/myblog/blog/shared/exception/ExceptionRestControllerAdvice.java +++ b/src/main/java/myblog/blog/shared/exception/ExceptionRestControllerAdvice.java @@ -1,5 +1,6 @@ package myblog.blog.shared.exception; +import myblog.blog.comment.adapter.incomming.InvalidCommentRequestException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -10,7 +11,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; */ @RestControllerAdvice public class ExceptionRestControllerAdvice { - @ExceptionHandler(CustomFormException.class) + @ExceptionHandler(InvalidCommentRequestException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleCategoryControllerException(RuntimeException e) { return e.getMessage(); diff --git a/src/main/java/myblog/blog/shared/queries/LayoutRenderingQueries.java b/src/main/java/myblog/blog/shared/queries/LayoutRenderingQueries.java index 6538605..4f93174 100644 --- a/src/main/java/myblog/blog/shared/queries/LayoutRenderingQueries.java +++ b/src/main/java/myblog/blog/shared/queries/LayoutRenderingQueries.java @@ -3,8 +3,8 @@ package myblog.blog.shared.queries; import lombok.RequiredArgsConstructor; import myblog.blog.category.appliacation.port.incomming.CategoryUseCase; import myblog.blog.category.appliacation.port.response.CategoryViewForLayout; -import myblog.blog.comment.dto.CommentDtoForLayout; -import myblog.blog.comment.service.CommentService; +import myblog.blog.comment.application.port.incomming.CommentDtoForLayout; +import myblog.blog.comment.application.CommentService; import org.springframework.stereotype.Component; import org.springframework.ui.Model;