diff --git a/src/main/java/com/api/trip/common/exception/CustomException.java b/src/main/java/com/api/trip/common/exception/CustomException.java index 9887735..ab34ae6 100644 --- a/src/main/java/com/api/trip/common/exception/CustomException.java +++ b/src/main/java/com/api/trip/common/exception/CustomException.java @@ -3,12 +3,12 @@ import lombok.Getter; @Getter -public abstract class CustomException extends RuntimeException { +public class CustomException extends RuntimeException { - protected CustomException(ErrorCode errorCode){ + private final ErrorCode errorCode; + + public CustomException(ErrorCode errorCode) { + super(errorCode.getMessage()); this.errorCode = errorCode; } - private ErrorCode errorCode; - - } diff --git a/src/main/java/com/api/trip/common/exception/ErrorCode.java b/src/main/java/com/api/trip/common/exception/ErrorCode.java index f51e671..30d5034 100644 --- a/src/main/java/com/api/trip/common/exception/ErrorCode.java +++ b/src/main/java/com/api/trip/common/exception/ErrorCode.java @@ -35,8 +35,17 @@ public enum ErrorCode { NOT_FOUND_EMAIL_TOKEN("이메일 인증 토큰이 존재하지 않습니다.", HttpStatus.NOT_FOUND), ALREADY_JOINED("이미 존재하는 회원입니다.", HttpStatus.CONFLICT), - ; + // 게시판 관련 + BAD_REQUEST("잘못된 요청입니다.", HttpStatus.BAD_REQUEST), + UNAUTHORIZED("로그인해 주세요.", HttpStatus.UNAUTHORIZED), + FORBIDDEN("접근 권한이 없습니다.", HttpStatus.FORBIDDEN), + ARTICLE_NOT_FOUND("존재하지 않는 게시글입니다.", HttpStatus.NOT_FOUND), + COMMENT_NOT_FOUND("존재하지 않는 댓글입니다.", HttpStatus.NOT_FOUND), + INTEREST_ARTICLE_ALREADY_EXISTS("이미 좋아한 게시글입니다.", HttpStatus.BAD_REQUEST), + INTEREST_ARTICLE_NOT_FOUND("좋아한 게시글이 아닙니다.", HttpStatus.NOT_FOUND), + UPLOAD_FAILED("파일 업로드에 실패하였습니다.", HttpStatus.INTERNAL_SERVER_ERROR), + ; private final String message; private final HttpStatus status; @@ -45,6 +54,4 @@ public enum ErrorCode { this.message = message; this.status = status; } - - } diff --git a/src/main/java/com/api/trip/domain/article/controller/dto/CreateArticleRequest.java b/src/main/java/com/api/trip/domain/article/controller/dto/CreateArticleRequest.java index f68a70e..91c7daa 100644 --- a/src/main/java/com/api/trip/domain/article/controller/dto/CreateArticleRequest.java +++ b/src/main/java/com/api/trip/domain/article/controller/dto/CreateArticleRequest.java @@ -1,7 +1,5 @@ package com.api.trip.domain.article.controller.dto; -import com.api.trip.domain.article.model.Article; -import com.api.trip.domain.member.model.Member; import lombok.Getter; import java.util.List; @@ -12,12 +10,4 @@ public class CreateArticleRequest { private String title; private List tags; private String content; - - public Article toEntity(Member writer) { - return Article.builder() - .writer(writer) - .title(title) - .content(content) - .build(); - } } diff --git a/src/main/java/com/api/trip/domain/article/service/ArticleService.java b/src/main/java/com/api/trip/domain/article/service/ArticleService.java index a85bd20..e86a629 100644 --- a/src/main/java/com/api/trip/domain/article/service/ArticleService.java +++ b/src/main/java/com/api/trip/domain/article/service/ArticleService.java @@ -1,5 +1,7 @@ package com.api.trip.domain.article.service; +import com.api.trip.common.exception.CustomException; +import com.api.trip.common.exception.ErrorCode; import com.api.trip.domain.article.controller.dto.*; import com.api.trip.domain.article.model.Article; import com.api.trip.domain.article.repository.ArticleRepository; @@ -19,24 +21,28 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Objects; @Service @Transactional @RequiredArgsConstructor public class ArticleService { - private final ArticleRepository articleRepository; private final MemberRepository memberRepository; + private final ArticleRepository articleRepository; private final ArticleTagRepository articleTagRepository; private final TagRepository tagRepository; - private final InterestArticleRepository interestArticleRepository; private final ArticleFileRepository articleFileRepository; + private final InterestArticleRepository interestArticleRepository; public Long createArticle(CreateArticleRequest request, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); - final Article article = request.toEntity(member); + final Article article = Article.builder() + .writer(member) + .title(request.getTitle()) + .content(request.getContent()) + .build(); articleRepository.save(article); @@ -58,11 +64,14 @@ public Long createArticle(CreateArticleRequest request, String email) { } public void updateArticle(Long articleId, UpdateArticleRequest request, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + Article article = articleRepository.findById(articleId) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); - Article article = articleRepository.findById(articleId).orElseThrow(); if (article.getWriter() != member) { - throw new RuntimeException("수정 권한이 없습니다."); + throw new CustomException(ErrorCode.FORBIDDEN); } articleTagRepository.deleteAllByArticle(article); @@ -85,11 +94,14 @@ public void updateArticle(Long articleId, UpdateArticleRequest request, String e } public void deleteArticle(Long articleId, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + Article article = articleRepository.findById(articleId) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); - Article article = articleRepository.findById(articleId).orElseThrow(); if (article.getWriter() != member) { - throw new RuntimeException("삭제 권한이 없습니다."); + throw new CustomException(ErrorCode.FORBIDDEN); } articleTagRepository.deleteAllByArticle(article); @@ -100,14 +112,15 @@ public void deleteArticle(Long articleId, String email) { } public ReadArticleResponse readArticle(Long articleId, String email) { - Article article = articleRepository.findArticle(articleId).orElseThrow(); + Article article = articleRepository.findArticle(articleId) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); List articleTags = articleTagRepository.findArticleTags(article); InterestArticle interestArticle = null; - if (!Objects.equals(email, "anonymousUser")) { - Member member = memberRepository.findByEmail(email).orElseThrow(); - interestArticle = interestArticleRepository.findByMemberAndArticle(member, article); + Member member = memberRepository.findByEmail(email).orElse(null); + if (member != null) { + interestArticle = interestArticleRepository.findByMemberAndArticle(member, article).orElse(null); } articleRepository.increaseViewCount(article); @@ -132,7 +145,8 @@ public GetArticlesResponse getArticles(Pageable pageable, int sortCode, String c @Transactional(readOnly = true) public GetMyArticlesResponse getMyArticles(String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); List
articles = articleRepository.findAllByWriterOrderByIdDesc(member); diff --git a/src/main/java/com/api/trip/domain/articlefile/service/ArticleFileService.java b/src/main/java/com/api/trip/domain/articlefile/service/ArticleFileService.java index ed89abf..acf1d50 100644 --- a/src/main/java/com/api/trip/domain/articlefile/service/ArticleFileService.java +++ b/src/main/java/com/api/trip/domain/articlefile/service/ArticleFileService.java @@ -1,16 +1,19 @@ package com.api.trip.domain.articlefile.service; +import com.api.trip.common.exception.CustomException; +import com.api.trip.common.exception.ErrorCode; import com.api.trip.domain.articlefile.model.ArticleFile; import com.api.trip.domain.articlefile.repository.ArticleFileRepository; import com.api.trip.domain.articlefile.uploader.ArticleFileUploader; +import com.api.trip.domain.member.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.time.LocalDateTime; import java.util.List; -import java.util.Objects; import java.util.UUID; @Service @@ -18,26 +21,34 @@ @RequiredArgsConstructor public class ArticleFileService { + private final MemberRepository memberRepository; private final ArticleFileRepository articleFileRepository; private final ArticleFileUploader articleFileUploader; public String upload(MultipartFile multipartFile, String email) { - if (Objects.equals(email, "anonymousUser")) { - throw new RuntimeException("접근 권한이 없습니다."); + memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + String url = null; + try { + url = articleFileUploader.upload(multipartFile, UUID.randomUUID().toString()); + } catch (IOException e) { + throw new CustomException(ErrorCode.UPLOAD_FAILED); } - String url = articleFileUploader.upload(multipartFile, UUID.randomUUID().toString()); - - ArticleFile articleFile = ArticleFile.builder() - .url(url) - .build(); - - return articleFileRepository.save(articleFile).getUrl(); + return articleFileRepository.save( + ArticleFile.builder() + .url(url) + .build() + ) + .getUrl(); } public void deleteTemporaryArticleFilesBefore(LocalDateTime localDateTime) { List articleFiles = articleFileRepository.findAllByArticleNullAndCreatedAtBefore(localDateTime); + articleFileRepository.deleteAllInBatch(articleFiles); + articleFiles.forEach(articleFile -> articleFileUploader.delete(articleFile.getUrl())); } } diff --git a/src/main/java/com/api/trip/domain/articlefile/uploader/ArticleFileUploader.java b/src/main/java/com/api/trip/domain/articlefile/uploader/ArticleFileUploader.java index 4deaa37..45cd5f6 100644 --- a/src/main/java/com/api/trip/domain/articlefile/uploader/ArticleFileUploader.java +++ b/src/main/java/com/api/trip/domain/articlefile/uploader/ArticleFileUploader.java @@ -20,13 +20,8 @@ public class ArticleFileUploader { @Value("${cloud.aws.s3.bucket}") private String bucket; - public String upload(MultipartFile multipartFile, String fileName) { - InputStream inputStream; - try { - inputStream = multipartFile.getInputStream(); - } catch (IOException e) { - throw new RuntimeException(e); - } + public String upload(MultipartFile multipartFile, String fileName) throws IOException { + InputStream inputStream = multipartFile.getInputStream(); ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType(multipartFile.getContentType()); diff --git a/src/main/java/com/api/trip/domain/comment/controller/dto/CreateCommentRequest.java b/src/main/java/com/api/trip/domain/comment/controller/dto/CreateCommentRequest.java index 55408d3..c1ecaa7 100644 --- a/src/main/java/com/api/trip/domain/comment/controller/dto/CreateCommentRequest.java +++ b/src/main/java/com/api/trip/domain/comment/controller/dto/CreateCommentRequest.java @@ -1,8 +1,5 @@ package com.api.trip.domain.comment.controller.dto; -import com.api.trip.domain.article.model.Article; -import com.api.trip.domain.comment.model.Comment; -import com.api.trip.domain.member.model.Member; import lombok.Getter; @Getter @@ -11,13 +8,4 @@ public class CreateCommentRequest { private Long articleId; private Long parentId; private String content; - - public Comment toEntity(Member writer, Article article, Comment parent) { - return Comment.builder() - .writer(writer) - .article(article) - .content(content) - .parent(parent) - .build(); - } } diff --git a/src/main/java/com/api/trip/domain/comment/service/CommentService.java b/src/main/java/com/api/trip/domain/comment/service/CommentService.java index 239ae54..7fbd9f3 100644 --- a/src/main/java/com/api/trip/domain/comment/service/CommentService.java +++ b/src/main/java/com/api/trip/domain/comment/service/CommentService.java @@ -1,5 +1,7 @@ package com.api.trip.domain.comment.service; +import com.api.trip.common.exception.CustomException; +import com.api.trip.common.exception.ErrorCode; import com.api.trip.domain.article.model.Article; import com.api.trip.domain.article.repository.ArticleRepository; import com.api.trip.domain.comment.controller.dto.CreateCommentRequest; @@ -21,45 +23,61 @@ @RequiredArgsConstructor public class CommentService { + private final MemberRepository memberRepository; private final CommentRepository commentRepository; private final ArticleRepository articleRepository; - private final MemberRepository memberRepository; public Long createComment(CreateCommentRequest request, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); - Article article = articleRepository.findById(request.getArticleId()).orElseThrow(); + Article article = articleRepository.findById(request.getArticleId()) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); Comment parent = null; if (request.getParentId() != null) { - parent = commentRepository.findById(request.getParentId()).orElseThrow(); + parent = commentRepository.findById(request.getParentId()) + .orElseThrow(() -> new CustomException(ErrorCode.COMMENT_NOT_FOUND)); + if (parent.getParent() != null || parent.getArticle() != article) { - throw new RuntimeException("잘못된 요청입니다."); + throw new CustomException(ErrorCode.BAD_REQUEST); } } - Comment comment = request.toEntity(member, article, parent); - - return commentRepository.save(comment).getId(); + return commentRepository.save( + Comment.builder() + .writer(member) + .article(article) + .content(request.getContent()) + .parent(parent) + .build() + ) + .getId(); } public void updateComment(Long commentId, UpdateCommentRequest request, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new CustomException(ErrorCode.COMMENT_NOT_FOUND)); - Comment comment = commentRepository.findById(commentId).orElseThrow(); if (comment.getWriter() != member) { - throw new RuntimeException("수정 권한이 없습니다."); + throw new CustomException(ErrorCode.FORBIDDEN); } comment.modify(request.getContent()); } public void deleteComment(Long commentId, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new CustomException(ErrorCode.COMMENT_NOT_FOUND)); - Comment comment = commentRepository.findById(commentId).orElseThrow(); if (comment.getWriter() != member) { - throw new RuntimeException("삭제 권한이 없습니다."); + throw new CustomException(ErrorCode.FORBIDDEN); } commentRepository.delete(comment); @@ -67,7 +85,8 @@ public void deleteComment(Long commentId, String email) { @Transactional(readOnly = true) public GetCommentsResponse getComments(Long articleId) { - Article article = articleRepository.findById(articleId).orElseThrow(); + Article article = articleRepository.findById(articleId) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); List comments = commentRepository.findComments(article); @@ -76,7 +95,8 @@ public GetCommentsResponse getComments(Long articleId) { @Transactional(readOnly = true) public GetMyCommentsResponse getMyComments(String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); List comments = commentRepository.findAllByWriterOrderByIdDesc(member); diff --git a/src/main/java/com/api/trip/domain/interestarticle/controller/dto/CreateInterestArticleRequest.java b/src/main/java/com/api/trip/domain/interestarticle/controller/dto/CreateInterestArticleRequest.java index ed21e3d..9890e2e 100644 --- a/src/main/java/com/api/trip/domain/interestarticle/controller/dto/CreateInterestArticleRequest.java +++ b/src/main/java/com/api/trip/domain/interestarticle/controller/dto/CreateInterestArticleRequest.java @@ -1,19 +1,9 @@ package com.api.trip.domain.interestarticle.controller.dto; -import com.api.trip.domain.article.model.Article; -import com.api.trip.domain.interestarticle.model.InterestArticle; -import com.api.trip.domain.member.model.Member; import lombok.Getter; @Getter public class CreateInterestArticleRequest { private Long articleId; - - public InterestArticle toEntity(Member member, Article article) { - return InterestArticle.builder() - .member(member) - .article(article) - .build(); - } } diff --git a/src/main/java/com/api/trip/domain/interestarticle/repository/InterestArticleRepository.java b/src/main/java/com/api/trip/domain/interestarticle/repository/InterestArticleRepository.java index 04bb2ed..c9dfe7c 100644 --- a/src/main/java/com/api/trip/domain/interestarticle/repository/InterestArticleRepository.java +++ b/src/main/java/com/api/trip/domain/interestarticle/repository/InterestArticleRepository.java @@ -5,7 +5,9 @@ import com.api.trip.domain.member.model.Member; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface InterestArticleRepository extends JpaRepository { - InterestArticle findByMemberAndArticle(Member member, Article article); + Optional findByMemberAndArticle(Member member, Article article); } diff --git a/src/main/java/com/api/trip/domain/interestarticle/service/InterestArticleService.java b/src/main/java/com/api/trip/domain/interestarticle/service/InterestArticleService.java index 93265c1..01acf51 100644 --- a/src/main/java/com/api/trip/domain/interestarticle/service/InterestArticleService.java +++ b/src/main/java/com/api/trip/domain/interestarticle/service/InterestArticleService.java @@ -1,5 +1,7 @@ package com.api.trip.domain.interestarticle.service; +import com.api.trip.common.exception.CustomException; +import com.api.trip.common.exception.ErrorCode; import com.api.trip.domain.article.model.Article; import com.api.trip.domain.article.repository.ArticleRepository; import com.api.trip.domain.interestarticle.controller.dto.CreateInterestArticleRequest; @@ -16,33 +18,42 @@ @RequiredArgsConstructor public class InterestArticleService { + private final MemberRepository memberRepository; private final InterestArticleRepository interestArticleRepository; private final ArticleRepository articleRepository; - private final MemberRepository memberRepository; public Long createInterestArticle(CreateInterestArticleRequest request, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); - - Article article = articleRepository.findById(request.getArticleId()).orElseThrow(); - - InterestArticle interestArticle = interestArticleRepository.findByMemberAndArticle(member, article); - if (interestArticle != null) { - throw new RuntimeException("잘못된 요청입니다."); - } - - interestArticle = request.toEntity(member, article); - - articleRepository.increaseLikeCount(interestArticle.getArticle()); - - return interestArticleRepository.save(interestArticle).getId(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + Article article = articleRepository.findById(request.getArticleId()) + .orElseThrow(() -> new CustomException(ErrorCode.ARTICLE_NOT_FOUND)); + + interestArticleRepository.findByMemberAndArticle(member, article) + .ifPresent(interestArticle -> { + throw new CustomException(ErrorCode.INTEREST_ARTICLE_ALREADY_EXISTS); + }); + + articleRepository.increaseLikeCount(article); + + return interestArticleRepository.save( + InterestArticle.builder() + .member(member) + .article(article) + .build() + ) + .getId(); } public void deleteInterestArticle(Long interestArticleId, String email) { - Member member = memberRepository.findByEmail(email).orElseThrow(); + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new CustomException(ErrorCode.UNAUTHORIZED)); + + InterestArticle interestArticle = interestArticleRepository.findById(interestArticleId) + .orElseThrow(() -> new CustomException(ErrorCode.INTEREST_ARTICLE_NOT_FOUND)); - InterestArticle interestArticle = interestArticleRepository.findById(interestArticleId).orElseThrow(); if (interestArticle.getMember() != member) { - throw new RuntimeException("삭제 권한이 없습니다."); + throw new CustomException(ErrorCode.FORBIDDEN); } articleRepository.decreaseLikeCount(interestArticle.getArticle());