imgupload, comment 모듈 헥사고날 아키텍쳐로 리아키텍쳐링
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package myblog.blog.category.adapter.imcomming;
|
||||
/*
|
||||
- REST 컨트롤러 상태 메세지 전송용 커스텀 에러
|
||||
*/
|
||||
public class InvalidCategoryRequestException extends RuntimeException {
|
||||
public InvalidCategoryRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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<CommentDto> 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<CommentDto> deleteComment(@RequestParam Long articleId,
|
||||
@RequestParam Long commentId) {
|
||||
commentService.deleteComment(commentId);
|
||||
return CommentDto.listCreateFrom(commentService.getCommentList(articleId),0);
|
||||
commentUseCase.deleteComment(commentId);
|
||||
return commentUseCase.getCommentList(articleId);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.comment.dto;
|
||||
package myblog.blog.comment.adapter.incomming;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package myblog.blog.comment.adapter.incomming;
|
||||
/*
|
||||
- REST 컨트롤러 상태 메세지 전송용 커스텀 에러
|
||||
*/
|
||||
public class InvalidCommentRequestException extends RuntimeException {
|
||||
public InvalidCommentRequestException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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<Comment> findCommentsByArticleId(Long articleId) {
|
||||
return jpaCommentRepository.findCommentsByArticleId(articleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteComment(Long commentId) {
|
||||
mybatisCommentRepository.deleteComment(commentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Comment> findTop5ByOrderByIdDesc() {
|
||||
return jpaCommentRepository.findTop5ByOrderByIdDesc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Comment> findById(Long parentId) {
|
||||
return jpaCommentRepository.findById(parentId);
|
||||
}
|
||||
}
|
||||
@@ -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<Comment, Long> {
|
||||
public interface JpaCommentRepository extends JpaRepository<Comment, Long> {
|
||||
|
||||
/*
|
||||
- 특정 아티클에 해당하는 댓글 리스트 가져오기
|
||||
@@ -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 삭제처리
|
||||
@@ -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<Comment> getCommentList(Long articleId){
|
||||
return commentRepository.findCommentsByArticleId(articleId);
|
||||
@Override
|
||||
public List<CommentDto> 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<CommentDtoForLayout> 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){
|
||||
|
||||
@@ -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.*;
|
||||
|
||||
|
||||
/*
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.comment.dto;
|
||||
package myblog.blog.comment.application.port.incomming;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -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<CommentDto> 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<CommentDtoForLayout> recentCommentList();
|
||||
}
|
||||
@@ -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<Comment> findCommentsByArticleId(Long articleId);
|
||||
void deleteComment(Long commentId);
|
||||
List<Comment> findTop5ByOrderByIdDesc();
|
||||
Optional<Comment> findById(Long parentId);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
38
src/main/java/myblog/blog/imgupload/domain/ImageFile.java
Normal file
38
src/main/java/myblog/blog/imgupload/domain/ImageFile.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<String> storeFile(List<MultipartFile> 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("이미지가 존재하지 않습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package myblog.blog.imgupload.service.port.outgoing;
|
||||
|
||||
import myblog.blog.imgupload.domain.ImageFile;
|
||||
|
||||
/**
|
||||
* 파일 업로드 전략패턴 추상화 인터페이스
|
||||
*/
|
||||
public interface ImgUploadStrategyPort {
|
||||
String uploadFile(ImageFile imageFile);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package myblog.blog.shared.exception;
|
||||
/*
|
||||
- REST 컨트롤러 상태 메세지 전송용 커스텀 에러
|
||||
*/
|
||||
public class CustomFormException extends RuntimeException {
|
||||
public CustomFormException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user