From 95dfb8e04ab9c6fd89e3ca5a5b3c5bcedaaa67d8 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Tue, 8 Jun 2021 13:20:35 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20StatusCode=20code=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EC=A3=BC=EC=84=9D=20=EB=B0=8F=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/devin/dev/utils/StatusCode.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/devin/dev/utils/StatusCode.java b/src/main/java/com/devin/dev/utils/StatusCode.java index 78dfed3..9e23328 100644 --- a/src/main/java/com/devin/dev/utils/StatusCode.java +++ b/src/main/java/com/devin/dev/utils/StatusCode.java @@ -1,17 +1,23 @@ package com.devin.dev.utils; public enum StatusCode { - OK(200), - CREATED(201), - NO_CONTENT(204), - BAD_REQUEST(400), - UNAUTHORIZED(401), - FORBIDDEN(403), - NOT_FOUND(404), - INTERNAL_SERVER_ERROR(500), - SERVICE_UNAVAILABLE(503), - DB_ERROR(600); + OK(0), // 요청에 대한 처리 성공 + CREATED(201), // POST 요청에 데이터가 잘 생성 되었을 때 응답코드 + NO_CONTENT(204), // 요청에 대한 처리는 성공했지만, 클라이언트가 현재 페이지에서 이동할 필요가 없을 때 + BAD_REQUEST(400), // 요청에 대한 값이 잘못되었을 때 + UNAUTHORIZED(401), // 이 요청을 하려면 로그인이 필요할 때 + FORBIDDEN(403), // 유저가 접근 불가능한 정보에 접근했을 때 + NOT_FOUND(404), // URI 가 존재하지 않음 + INTERNAL_SERVER_ERROR(500), // 서버에서 에러가 났을 때 전부. 500 이후 에러를 모두 포함한다 + SERVICE_UNAVAILABLE(503); // 서버에서 요청에 대한 처리가 불가능할 때 + + private final int code; StatusCode(int code) { + this.code = code; + } + + public int getCode() { + return code; } } From 35ff6e0aa9a46cc30c85b552814f88755167caaa Mon Sep 17 00:00:00 2001 From: enjay27 Date: Thu, 10 Jun 2021 23:11:16 +0900 Subject: [PATCH 02/12] =?UTF-8?q?fix:=20PostDto=20API=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=EB=8C=80=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devin/dev/dto/post/PostDetailsDto.java | 59 ++++++++++++------- .../com/devin/dev/dto/post/PostReplyDto.java | 49 ++++++++++++--- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/devin/dev/dto/post/PostDetailsDto.java b/src/main/java/com/devin/dev/dto/post/PostDetailsDto.java index a27cbd2..31edc22 100644 --- a/src/main/java/com/devin/dev/dto/post/PostDetailsDto.java +++ b/src/main/java/com/devin/dev/dto/post/PostDetailsDto.java @@ -6,42 +6,61 @@ import com.querydsl.core.annotations.QueryProjection; import lombok.Data; -import java.util.ArrayList; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; @Data public class PostDetailsDto { - private Long postId; - private Long userId; + private Long post_id; + private Long publisher_id; + private String publisher_name; + private String publisher_profile; + private Long publisher_exp; private String title; - private String username; private String content; - private PostStatus status; - private Integer replyQuantity; - private List imagePaths; + private List post_images; + private List post_tags; + private boolean status_accept; + private LocalDateTime date_create; + private LocalDateTime date_update; + private Integer reply_num; + private List reply; @QueryProjection - public PostDetailsDto(Long postId, Long userId, String title, String username, String content, PostStatus status, Integer replyQuantity, List imagePaths) { - this.postId = postId; - this.userId = userId; + public PostDetailsDto(Long post_id, Long publisher_id, String publisher_name, String publisher_profile, Long publisher_exp, String title, String content, List post_images, List post_tags, boolean status_accept, boolean like_post, LocalDateTime date_create, LocalDateTime date_update, Integer reply_num, List replyDtos) { + this.post_id = post_id; + this.publisher_id = publisher_id; + this.publisher_name = publisher_name; + this.publisher_profile = publisher_profile; + this.publisher_exp = publisher_exp; this.title = title; - this.username = username; this.content = content; - this.status = status; - this.replyQuantity = replyQuantity; - this.imagePaths = imagePaths; + this.post_images = post_images; + this.post_tags = post_tags; + this.status_accept = status_accept; + this.date_create = date_create; + this.date_update = date_update; + this.reply_num = reply_num; + this.reply = replyDtos; } public PostDetailsDto(Post post) { - this.postId = post.getId(); - this.userId = post.getUser().getId(); + this.post_id = post.getId(); + this.publisher_id = post.getUser().getId(); + this.publisher_name = post.getUser().getName(); + this.publisher_profile = post.getUser().getProfile(); + this.publisher_exp = post.getUser().getExp(); this.title = post.getTitle(); - this.username = post.getUser().getName(); this.content = post.getContent(); - this.status = post.getStatus(); - this.replyQuantity = post.getReplies().size(); - this.imagePaths = post.getImages().stream().map(PostImage::getPath).collect(Collectors.toList()); + this.post_images = post.getImages().stream().map(PostImage::getPath).collect(Collectors.toList()); + this.post_tags = post.getPostTags(); + this.status_accept = post.getStatus() == PostStatus.SELECTED; + this.date_create = post.getCreatedDate(); + this.date_update = post.getLastModifiedDate(); + this.reply_num = post.getReplies().size(); + this.reply = post.getReplies().stream().map(PostReplyDto::new).collect(Collectors.toList()); } } diff --git a/src/main/java/com/devin/dev/dto/post/PostReplyDto.java b/src/main/java/com/devin/dev/dto/post/PostReplyDto.java index a617cd1..5061d68 100644 --- a/src/main/java/com/devin/dev/dto/post/PostReplyDto.java +++ b/src/main/java/com/devin/dev/dto/post/PostReplyDto.java @@ -1,25 +1,56 @@ package com.devin.dev.dto.post; +import com.devin.dev.entity.reply.Reply; +import com.devin.dev.entity.reply.ReplyImage; +import com.devin.dev.entity.reply.ReplyStatus; import com.querydsl.core.annotations.QueryProjection; import lombok.Data; +import java.time.LocalDateTime; import java.util.List; +import java.util.stream.Collectors; @Data public class PostReplyDto { - private Long postId; - private Long userId; - private String username; + private Long reply_id; + private Long publisher_id; + private String publisher_name; + private String publisher_profile; + private Long publisher_exp; private String content; - private List imagePaths; + private List reply_images; + private boolean status_accept; + private Integer like_num; + private LocalDateTime date_create; + private LocalDateTime date_update; @QueryProjection - public PostReplyDto(Long postId, Long userId, String username, String content, List imagePaths) { - this.postId = postId; - this.userId = userId; - this.username = username; + public PostReplyDto(Long reply_id, Long publisher_id, String publisher_name, String publisher_profile, Long publisher_exp, String content, List reply_images, boolean status_accept, boolean like_reply, Integer like_num, LocalDateTime date_create, LocalDateTime date_update) { + this.reply_id = reply_id; + this.publisher_id = publisher_id; + this.publisher_name = publisher_name; + this.publisher_profile = publisher_profile; + this.publisher_exp = publisher_exp; this.content = content; - this.imagePaths = imagePaths; + this.reply_images = reply_images; + this.status_accept = status_accept; + this.like_num = like_num; + this.date_create = date_create; + this.date_update = date_update; + } + + public PostReplyDto(Reply reply) { + this.reply_id = reply.getId(); + this.publisher_id = reply.getUser().getId(); + this.publisher_name = reply.getUser().getName(); + this.publisher_profile = reply.getUser().getProfile(); + this.publisher_exp = reply.getUser().getExp(); + this.content = reply.getContent(); + this.reply_images = reply.getImages().stream().map(ReplyImage::getPath).collect(Collectors.toList()); + this.status_accept = ReplyStatus.SELECTED == reply.getStatus(); + this.like_num = reply.getLikes().size(); + this.date_create = reply.getCreatedDate(); + this.date_update = reply.getLastModifiedDate(); } } From dee29a439f1a6338d7a1558cf77403ebd9ca418d Mon Sep 17 00:00:00 2001 From: enjay27 Date: Thu, 10 Jun 2021 23:33:20 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20PostRepository=20PostDtoDetails?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/post/PostRepositoryQuery.java | 4 ++++ .../post/PostRepositoryQueryImpl.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java b/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java index f7ba19b..7cbc72a 100644 --- a/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java +++ b/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java @@ -1,6 +1,7 @@ package com.devin.dev.repository.post; import com.devin.dev.controller.post.PostSearchCondition; +import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.dto.post.PostSimpleDto; import com.devin.dev.entity.post.Post; import com.devin.dev.entity.user.User; @@ -8,6 +9,7 @@ import org.springframework.data.domain.Pageable; import java.util.List; +import java.util.Optional; public interface PostRepositoryQuery { @@ -18,4 +20,6 @@ public interface PostRepositoryQuery { List findPostDtoByUser(User user); Page findAllByTagId(Long id, Pageable pageable); + + Optional findDetailById(Long id); } diff --git a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java index 40a2cd9..a1dc292 100644 --- a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java +++ b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java @@ -1,7 +1,9 @@ package com.devin.dev.repository.post; import com.devin.dev.controller.post.PostSearchCondition; +import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.dto.post.PostSimpleDto; +import com.devin.dev.dto.post.QPostDetailsDto; import com.devin.dev.dto.post.QPostSimpleDto; import com.devin.dev.entity.post.*; import com.devin.dev.entity.user.User; @@ -16,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Optional; import static com.devin.dev.entity.post.QPost.post; import static com.devin.dev.entity.post.QPostTag.postTag; @@ -113,6 +116,24 @@ public Page findAllByTagId(Long id, Pageable pageable) { return new PageImpl<>(content, pageable, total); } + @Override + public Optional findDetailById(Long id) { + Post post = queryFactory + .selectFrom(QPost.post) + .where(QPost.post.id.eq(id)) + .fetchOne(); + + Optional postDetailsDtoOptional; + if(post != null) { + postDetailsDtoOptional = Optional.of(new PostDetailsDto(post)); + } + else { + postDetailsDtoOptional = Optional.empty(); + } + + return postDetailsDtoOptional; + } + private BooleanExpression usernameLike(String username) { return hasText(username) ? user.name.contains(username) : null; } From b9766df01d031f5fd8186ee8f6d8de308da447d3 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 10:54:19 +0900 Subject: [PATCH 04/12] =?UTF-8?q?fix:=20sample=20data=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/devin/dev/sample/HelloController.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/devin/dev/sample/HelloController.java b/src/main/java/com/devin/dev/sample/HelloController.java index 8e7bfe8..949e68a 100644 --- a/src/main/java/com/devin/dev/sample/HelloController.java +++ b/src/main/java/com/devin/dev/sample/HelloController.java @@ -75,13 +75,4 @@ public String getMain() { return "main"; } - @GetMapping("/setting") - public String createSampleData() { - sampleData.createSubjects(); - sampleData.createUsers(); - sampleData.createPosts(); - sampleData.createReplies(); - - return "redirect:/"; - } } From f7f79b4a5592f51883d6649282d0a8d85ff5963f Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 13:38:19 +0900 Subject: [PATCH 05/12] =?UTF-8?q?[#9]feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=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/devin/dev/SampleData.java | 2 +- .../dev/controller/post/PostController.java | 16 +++++ .../controller/reply/ReplyOrderCondition.java | 9 +++ .../repository/post/PostRepositoryQuery.java | 6 +- .../post/PostRepositoryQueryImpl.java | 57 +++++++++------- .../com/devin/dev/service/PostService.java | 20 ++++-- .../dev/repository/PostRepositoryTest.java | 3 +- .../devin/dev/service/PostServiceTest.java | 68 ++++++++++++------- 8 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/devin/dev/controller/reply/ReplyOrderCondition.java diff --git a/src/main/java/com/devin/dev/SampleData.java b/src/main/java/com/devin/dev/SampleData.java index cc525d6..5f00841 100644 --- a/src/main/java/com/devin/dev/SampleData.java +++ b/src/main/java/com/devin/dev/SampleData.java @@ -60,7 +60,7 @@ public void createReplies() { for (UserDetailsDto userDto : userDtos) { for (PostDetailsDto postDto : postDtos) { for (int i = 0; i < 2; i++) { - DefaultResponse response = replyService.reply(userDto.getId(), postDto.getPostId(), + DefaultResponse response = replyService.reply(userDto.getId(), postDto.getPost_id(), "reply_content_" + i, List.of("reply_img_1", "reply_img_2", "reply_img_3")); replyDtos.add(response.getData()); diff --git a/src/main/java/com/devin/dev/controller/post/PostController.java b/src/main/java/com/devin/dev/controller/post/PostController.java index df76aa0..4730a9a 100644 --- a/src/main/java/com/devin/dev/controller/post/PostController.java +++ b/src/main/java/com/devin/dev/controller/post/PostController.java @@ -1,11 +1,14 @@ package com.devin.dev.controller.post; +import com.devin.dev.controller.reply.ReplyOrderCondition; +import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.model.DefaultResponse; import com.devin.dev.service.PostService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.data.domain.Pageable; @@ -22,4 +25,17 @@ public DefaultResponse getPostList(@RequestParam(defaultValue = "-1")Long id, return postService.getPostInfoList(id, pageable); } + @GetMapping("/post/{id}") + public DefaultResponse findReplies( + @PathVariable("id") Long postId, + @RequestParam("sort_reply") boolean sort_reply) { + ReplyOrderCondition replyOrderCondition = new ReplyOrderCondition(); + if (!sort_reply) { + replyOrderCondition.setLatestDate(true); + } else { + replyOrderCondition.setLikeCount(true); + } + return postService.getPost(postId, replyOrderCondition); + } + } diff --git a/src/main/java/com/devin/dev/controller/reply/ReplyOrderCondition.java b/src/main/java/com/devin/dev/controller/reply/ReplyOrderCondition.java new file mode 100644 index 0000000..be36ced --- /dev/null +++ b/src/main/java/com/devin/dev/controller/reply/ReplyOrderCondition.java @@ -0,0 +1,9 @@ +package com.devin.dev.controller.reply; + +import lombok.Data; + +@Data +public class ReplyOrderCondition { + private boolean likeCount; + private boolean latestDate; +} diff --git a/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java b/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java index 7cbc72a..803e156 100644 --- a/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java +++ b/src/main/java/com/devin/dev/repository/post/PostRepositoryQuery.java @@ -1,7 +1,9 @@ package com.devin.dev.repository.post; import com.devin.dev.controller.post.PostSearchCondition; +import com.devin.dev.controller.reply.ReplyOrderCondition; import com.devin.dev.dto.post.PostDetailsDto; +import com.devin.dev.dto.post.PostInfoDto; import com.devin.dev.dto.post.PostSimpleDto; import com.devin.dev.entity.post.Post; import com.devin.dev.entity.user.User; @@ -15,11 +17,11 @@ public interface PostRepositoryQuery { Page findPostnamePageByUser(User user, Pageable pageable); - Page findPostDtoPageWithCondition(PostSearchCondition condition, Pageable pageable); + Page findPostInfoDtoPageByCondition(PostSearchCondition condition, Pageable pageable); List findPostDtoByUser(User user); Page findAllByTagId(Long id, Pageable pageable); - Optional findDetailById(Long id); + Optional findPostDetailsById(Long id, ReplyOrderCondition condition); } diff --git a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java index a1dc292..2975c08 100644 --- a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java +++ b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java @@ -1,13 +1,13 @@ package com.devin.dev.repository.post; import com.devin.dev.controller.post.PostSearchCondition; -import com.devin.dev.dto.post.PostDetailsDto; -import com.devin.dev.dto.post.PostSimpleDto; -import com.devin.dev.dto.post.QPostDetailsDto; -import com.devin.dev.dto.post.QPostSimpleDto; +import com.devin.dev.controller.reply.ReplyOrderCondition; +import com.devin.dev.dto.post.*; import com.devin.dev.entity.post.*; +import com.devin.dev.entity.reply.QReply; import com.devin.dev.entity.user.User; import com.querydsl.core.QueryResults; +import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -19,10 +19,13 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static com.devin.dev.entity.post.QPost.post; +import static com.devin.dev.entity.post.QPostImage.postImage; import static com.devin.dev.entity.post.QPostTag.postTag; import static com.devin.dev.entity.post.QSubject.subject; +import static com.devin.dev.entity.reply.QReply.reply; import static com.devin.dev.entity.user.QUser.user; import static org.springframework.util.StringUtils.hasText; @@ -58,18 +61,12 @@ public Page findPostnamePageByUser(User user, Pageable pageable) { */ @Override - public Page findPostDtoPageWithCondition(PostSearchCondition condition, Pageable pageable) { - QueryResults results = queryFactory - .selectDistinct(new QPostSimpleDto( - post.title, - user.name, - post.content, - post.status, - post.replies.size() - )) + public Page findPostInfoDtoPageByCondition(PostSearchCondition condition, Pageable pageable) { + QueryResults results = queryFactory + .selectDistinct(post) .from(post) - .innerJoin(post.user, user) - .innerJoin(post.tags, postTag) + .leftJoin(post.user, user) + .leftJoin(post.tags, postTag) .where( usernameLike(condition.getUsername()), titleLike(condition.getTitle()), @@ -79,7 +76,9 @@ public Page findPostDtoPageWithCondition(PostSearchCondition cond .limit(pageable.getPageSize()) .fetchResults(); - List content = results.getResults(); + List posts = results.getResults(); + + List content = posts.stream().map(PostInfoDto::new).collect(Collectors.toList()); long total = results.getTotal(); @@ -117,23 +116,28 @@ public Page findAllByTagId(Long id, Pageable pageable) { } @Override - public Optional findDetailById(Long id) { - Post post = queryFactory - .selectFrom(QPost.post) - .where(QPost.post.id.eq(id)) + public Optional findPostDetailsById(Long id, ReplyOrderCondition condition) { + Post result = queryFactory + .select(post) + .from(post) + .leftJoin(post.replies, reply).fetchJoin() + .where(post.id.eq(id)) + .orderBy( + replyOrder(condition) + ) .fetchOne(); Optional postDetailsDtoOptional; - if(post != null) { - postDetailsDtoOptional = Optional.of(new PostDetailsDto(post)); - } - else { - postDetailsDtoOptional = Optional.empty(); - } + + postDetailsDtoOptional = result != null ? Optional.of(new PostDetailsDto(result)) : Optional.empty(); return postDetailsDtoOptional; } + private OrderSpecifier replyOrder(ReplyOrderCondition condition) { + return condition.isLatestDate() ? reply.lastModifiedDate.asc() : reply.likes.size().asc(); + } + private BooleanExpression usernameLike(String username) { return hasText(username) ? user.name.contains(username) : null; } @@ -154,4 +158,5 @@ private BooleanExpression tagsInclude(List tags) { return postTag.in(where);//(where); } + } diff --git a/src/main/java/com/devin/dev/service/PostService.java b/src/main/java/com/devin/dev/service/PostService.java index d7b1d97..f870795 100644 --- a/src/main/java/com/devin/dev/service/PostService.java +++ b/src/main/java/com/devin/dev/service/PostService.java @@ -1,9 +1,9 @@ package com.devin.dev.service; import com.devin.dev.controller.post.PostSearchCondition; +import com.devin.dev.controller.reply.ReplyOrderCondition; import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.dto.post.PostInfoDto; -import com.devin.dev.dto.post.PostSimpleDto; import com.devin.dev.entity.post.Post; import com.devin.dev.entity.post.PostImage; import com.devin.dev.entity.post.PostTag; @@ -21,7 +21,6 @@ import com.devin.dev.utils.ResponseMessage; import com.devin.dev.utils.StatusCode; import lombok.RequiredArgsConstructor; -import org.springframework.core.convert.converter.Converter; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -121,12 +120,23 @@ public DefaultResponse editPost(Long userId, Long postId, String title, Strin return new DefaultResponse<>(StatusCode.OK, ResponseMessage.POST_EDIT_SUCCESS); } + @Transactional + public DefaultResponse getPost(Long postId, ReplyOrderCondition replyOrderCondition) { + Optional postOptional = postRepository.findPostDetailsById(postId, replyOrderCondition); + if (postOptional.isEmpty()) { + return new DefaultResponse<>(StatusCode.BAD_REQUEST, ResponseMessage.NOT_FOUND_POST); + } + PostDetailsDto postDetailsDto = postOptional.get(); + + return new DefaultResponse<>(StatusCode.OK, ResponseMessage.FOUND_POST, postDetailsDto); + } + // 게시글 검색 @Transactional - public DefaultResponse> searchPosts(PostSearchCondition condition, Pageable pageable) { - Page postDtos = postRepository.findPostDtoPageWithCondition(condition, pageable); + public DefaultResponse> getPostInfoListByCondition(PostSearchCondition condition, Pageable pageable) { + Page postDtos = postRepository.findPostInfoDtoPageByCondition(condition, pageable); - PageImpl page = new PageImpl<>(postDtos.toList(), pageable, postDtos.getTotalElements()); + PageImpl page = new PageImpl<>(postDtos.toList(), pageable, postDtos.getTotalElements()); return new DefaultResponse<>(StatusCode.OK, ResponseMessage.FOUND_POST, page); } diff --git a/src/test/java/com/devin/dev/repository/PostRepositoryTest.java b/src/test/java/com/devin/dev/repository/PostRepositoryTest.java index 8b284b6..7833fb0 100644 --- a/src/test/java/com/devin/dev/repository/PostRepositoryTest.java +++ b/src/test/java/com/devin/dev/repository/PostRepositoryTest.java @@ -1,6 +1,7 @@ package com.devin.dev.repository; import com.devin.dev.controller.post.PostSearchCondition; +import com.devin.dev.dto.post.PostInfoDto; import com.devin.dev.dto.post.PostSimpleDto; import com.devin.dev.entity.post.Post; import com.devin.dev.entity.post.PostTag; @@ -162,7 +163,7 @@ void findPostDtoPageWithCondition() { condition.setUsername("A"); condition.setTitle("Post"); Pageable pageable = PageRequest.of(0, 4); - Page postDtoPage = postRepository.findPostDtoPageWithCondition(condition, pageable); + Page postDtoPage = postRepository.findPostInfoDtoPageByCondition(condition, pageable); assertThat(postDtoPage).extracting("title").containsExactly("PostA1", "PostA2"); } } \ No newline at end of file diff --git a/src/test/java/com/devin/dev/service/PostServiceTest.java b/src/test/java/com/devin/dev/service/PostServiceTest.java index 2203fb9..ea10ceb 100644 --- a/src/test/java/com/devin/dev/service/PostServiceTest.java +++ b/src/test/java/com/devin/dev/service/PostServiceTest.java @@ -1,5 +1,7 @@ package com.devin.dev.service; +import com.devin.dev.controller.reply.ReplyOrderCondition; +import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.entity.post.Post; import com.devin.dev.entity.post.PostImage; import com.devin.dev.entity.post.PostTag; @@ -10,6 +12,7 @@ import com.devin.dev.repository.post.PostRepository; import com.devin.dev.utils.ResponseMessage; import com.devin.dev.utils.StatusCode; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -34,18 +37,26 @@ class PostServiceTest { @Autowired PostRepository postRepository; - @Test - void postSucceeded() { - Subject subject1 = new Subject("s1"); - Subject subject2 = new Subject("s2"); - Subject subject3 = new Subject("s3"); + Subject subject1; + Subject subject2; + Subject subject3; + User postUser; + + @BeforeEach + void createSampleData() { + subject1 = new Subject("s1"); + subject2 = new Subject("s2"); + subject3 = new Subject("s3"); em.persist(subject1); em.persist(subject2); em.persist(subject3); - User postUser = new User("D", "d@b.com", "passD", "0004", UserStatus.ACTIVE); + postUser = new User("D", "d@b.com", "passD", "0004", UserStatus.ACTIVE); em.persist(postUser); + } + @Test + void postSucceeded() { DefaultResponse response = postService.post(postUser.getId(), "titleA1", "postA1", List.of("s1", "s2"), List.of("p1", "p2", "p3")); assertThat(response.getStatusCode()).isEqualTo(StatusCode.OK); assertThat(response.getResponseMessage()).isEqualTo(ResponseMessage.POST_UPLOAD_SUCCESS); @@ -60,16 +71,6 @@ void postSucceeded() { @Test void postFailed() { - Subject subject1 = new Subject("s1"); - Subject subject2 = new Subject("s2"); - Subject subject3 = new Subject("s3"); - em.persist(subject1); - em.persist(subject2); - em.persist(subject3); - - User postUser = new User("D", "d@b.com", "passD", "0004", UserStatus.ACTIVE); - em.persist(postUser); - DefaultResponse response = postService.post(9999L, "titleA1", "postA1", List.of("s1", "s2"), List.of("p1", "p2", "p3")); assertThat(response.getStatusCode()).isEqualTo(StatusCode.BAD_REQUEST); assertThat(response.getResponseMessage()).isEqualTo(ResponseMessage.NOT_FOUND_USER); @@ -77,16 +78,6 @@ void postFailed() { @Test void editPostTest() { - Subject subject1 = new Subject("s1"); - Subject subject2 = new Subject("s2"); - Subject subject3 = new Subject("s3"); - em.persist(subject1); - em.persist(subject2); - em.persist(subject3); - - User postUser = new User("D", "d@b.com", "passD", "0004", UserStatus.ACTIVE); - em.persist(postUser); - Post post1 = new Post(postUser, "PostC1", "ContentC1"); List postTags = PostTag.createPostTags(List.of(subject1, subject2)); post1.setPostTags(postTags); @@ -121,4 +112,29 @@ void editPostTest() { assertThat(post.getImages()).extracting("path").containsExactly("p4", "p3", "p1", "p2"); assertThat(post.getUser().getExp()).isEqualTo(0); } + + @Test + void getPostSucceeded() { + Post post1 = new Post(postUser, "PostC1", "ContentC1"); + List postTags = PostTag.createPostTags(List.of(subject1, subject2)); + post1.setPostTags(postTags); + List postImages = PostImage.createPostImages(List.of("p1", "p2", "p3")); + post1.setPostImages(postImages); + postTags.forEach(em::persist); + postImages.forEach(em::persist); + em.persist(post1); + + ReplyOrderCondition replyOrderCondition = new ReplyOrderCondition(); + replyOrderCondition.setLatestDate(true); +// replyOrderCondition.setLikeCount(true); + + DefaultResponse response = postService.getPost(post1.getId(), replyOrderCondition); + assertThat(response.getStatusCode()).isEqualTo(StatusCode.OK); + assertThat(response.getResponseMessage()).isEqualTo(ResponseMessage.FOUND_POST); + + PostDetailsDto postDto = response.getData(); + assertThat(postDto.getTitle()).isEqualTo("PostC1"); + assertThat(postDto.getPublisher_name()).isEqualTo("D"); + assertThat(postDto.getPost_images()).containsExactly("p1","p2","p3"); + } } \ No newline at end of file From 16632f22bd429a787e3d39e04320478b195e0004 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 14:25:16 +0900 Subject: [PATCH 06/12] =?UTF-8?q?fix:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20URI=20postlist/{id}=20=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/devin/dev/controller/post/PostController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/devin/dev/controller/post/PostController.java b/src/main/java/com/devin/dev/controller/post/PostController.java index 4730a9a..d4a78ff 100644 --- a/src/main/java/com/devin/dev/controller/post/PostController.java +++ b/src/main/java/com/devin/dev/controller/post/PostController.java @@ -25,10 +25,10 @@ public DefaultResponse getPostList(@RequestParam(defaultValue = "-1")Long id, return postService.getPostInfoList(id, pageable); } - @GetMapping("/post/{id}") + @GetMapping("/postlist/{id}") public DefaultResponse findReplies( @PathVariable("id") Long postId, - @RequestParam("sort_reply") boolean sort_reply) { + @RequestParam(defaultValue = "true", name = "sort_reply") boolean sort_reply) { ReplyOrderCondition replyOrderCondition = new ReplyOrderCondition(); if (!sort_reply) { replyOrderCondition.setLatestDate(true); From b202156b172acfb5ce0e154cfdf2ce898d7838e4 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 15:27:47 +0900 Subject: [PATCH 07/12] =?UTF-8?q?fix:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20innerJoin,=20fetchJoi?= =?UTF-8?q?n=20=EC=9C=BC=EB=A1=9C=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/repository/post/PostRepositoryQueryImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java index 2975c08..2027333 100644 --- a/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java +++ b/src/main/java/com/devin/dev/repository/post/PostRepositoryQueryImpl.java @@ -5,6 +5,8 @@ import com.devin.dev.dto.post.*; import com.devin.dev.entity.post.*; import com.devin.dev.entity.reply.QReply; +import com.devin.dev.entity.reply.QReplyImage; +import com.devin.dev.entity.reply.QReplyLike; import com.devin.dev.entity.user.User; import com.querydsl.core.QueryResults; import com.querydsl.core.types.OrderSpecifier; @@ -23,9 +25,12 @@ import static com.devin.dev.entity.post.QPost.post; import static com.devin.dev.entity.post.QPostImage.postImage; +import static com.devin.dev.entity.post.QPostLike.postLike; import static com.devin.dev.entity.post.QPostTag.postTag; import static com.devin.dev.entity.post.QSubject.subject; import static com.devin.dev.entity.reply.QReply.reply; +import static com.devin.dev.entity.reply.QReplyImage.replyImage; +import static com.devin.dev.entity.reply.QReplyLike.replyLike; import static com.devin.dev.entity.user.QUser.user; import static org.springframework.util.StringUtils.hasText; @@ -120,7 +125,9 @@ public Optional findPostDetailsById(Long id, ReplyOrderCondition Post result = queryFactory .select(post) .from(post) - .leftJoin(post.replies, reply).fetchJoin() + .innerJoin(post.replies, reply).fetchJoin() + .innerJoin(post.user, user).fetchJoin() + .innerJoin(reply.user, user).fetchJoin() .where(post.id.eq(id)) .orderBy( replyOrder(condition) From 0ecb5a7d316312e877deabcf62593cb1ad11fdac Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 15:31:13 +0900 Subject: [PATCH 08/12] =?UTF-8?q?test:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20MVC=20Test=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/devin/dev/mvc/PostControllerTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/java/com/devin/dev/mvc/PostControllerTest.java diff --git a/src/test/java/com/devin/dev/mvc/PostControllerTest.java b/src/test/java/com/devin/dev/mvc/PostControllerTest.java new file mode 100644 index 0000000..759ebfe --- /dev/null +++ b/src/test/java/com/devin/dev/mvc/PostControllerTest.java @@ -0,0 +1,49 @@ +package com.devin.dev.mvc; + +import com.devin.dev.entity.post.Post; +import com.devin.dev.repository.post.PostRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import javax.servlet.http.HttpServletRequestWrapper; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + +@SpringBootTest +@AutoConfigureMockMvc +class PostControllerTest { + + @Autowired + private MockMvc mvc; + + @Autowired + private PostRepository postRepository; + + @Test + @WithMockUser + void requestPostSucceeded() throws Exception { + List posts = postRepository.findByTitle("title_1"); + mvc.perform(get("/postlist/" + posts.get(0).getId())) + .andExpect(status().isOk()) + .andDo(print()); + } + + @Test + @WithMockUser + void requestPostFailed() throws Exception { + mvc.perform(get("/postlist/0")) + .andExpect(status().is4xxClientError()) + .andDo(print()); + } +} \ No newline at end of file From 1867da21ed6ece06f58df3cc456c64f2c9c6ba1f Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 16:47:33 +0900 Subject: [PATCH 09/12] =?UTF-8?q?[#14]feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/controller/post/PostController.java | 18 ++++++++---- .../repository/post/PostLikeRepository.java | 7 +++++ .../com/devin/dev/service/PostService.java | 28 ++++++++++++++++--- .../com/devin/dev/utils/ResponseMessage.java | 1 + 4 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/devin/dev/repository/post/PostLikeRepository.java diff --git a/src/main/java/com/devin/dev/controller/post/PostController.java b/src/main/java/com/devin/dev/controller/post/PostController.java index d4a78ff..7e1f4b6 100644 --- a/src/main/java/com/devin/dev/controller/post/PostController.java +++ b/src/main/java/com/devin/dev/controller/post/PostController.java @@ -7,10 +7,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.data.domain.Pageable; @RestController @@ -26,7 +23,7 @@ public DefaultResponse getPostList(@RequestParam(defaultValue = "-1")Long id, } @GetMapping("/postlist/{id}") - public DefaultResponse findReplies( + public DefaultResponse getPostDetails( @PathVariable("id") Long postId, @RequestParam(defaultValue = "true", name = "sort_reply") boolean sort_reply) { ReplyOrderCondition replyOrderCondition = new ReplyOrderCondition(); @@ -38,4 +35,15 @@ public DefaultResponse findReplies( return postService.getPost(postId, replyOrderCondition); } + @GetMapping("/postlist") + public DefaultResponse getPostListByCondition(PostSearchCondition condition, + @PageableDefault(page = 0, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) { + return postService.getPostInfoListByCondition(condition, pageable); + } + + @DeleteMapping("/postlist/{id}") + public DefaultResponse deletePost(@PathVariable("id") Long postId) { + return postService.deletePost(postId); + } + } diff --git a/src/main/java/com/devin/dev/repository/post/PostLikeRepository.java b/src/main/java/com/devin/dev/repository/post/PostLikeRepository.java new file mode 100644 index 0000000..7d9fcf0 --- /dev/null +++ b/src/main/java/com/devin/dev/repository/post/PostLikeRepository.java @@ -0,0 +1,7 @@ +package com.devin.dev.repository.post; + +import com.devin.dev.entity.post.PostLike; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostLikeRepository extends JpaRepository { +} diff --git a/src/main/java/com/devin/dev/service/PostService.java b/src/main/java/com/devin/dev/service/PostService.java index f870795..6776cbe 100644 --- a/src/main/java/com/devin/dev/service/PostService.java +++ b/src/main/java/com/devin/dev/service/PostService.java @@ -4,13 +4,13 @@ import com.devin.dev.controller.reply.ReplyOrderCondition; import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.dto.post.PostInfoDto; -import com.devin.dev.entity.post.Post; -import com.devin.dev.entity.post.PostImage; -import com.devin.dev.entity.post.PostTag; -import com.devin.dev.entity.post.Subject; +import com.devin.dev.entity.post.*; +import com.devin.dev.entity.reply.Reply; +import com.devin.dev.entity.reply.ReplyImage; import com.devin.dev.entity.user.User; import com.devin.dev.model.DefaultResponse; import com.devin.dev.repository.post.PostImageRepository; +import com.devin.dev.repository.post.PostLikeRepository; import com.devin.dev.repository.post.PostRepository; import com.devin.dev.repository.post.PostTagRepository; import com.devin.dev.repository.reply.ReplyRepository; @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -38,6 +39,7 @@ public class PostService { private final UserRepository userRepository; private final PostRepository postRepository; private final PostImageRepository postImageRepository; + private final PostLikeRepository postLikeRepository; private final PostTagRepository postTagRepository; private final SubjectRepository subjectRepository; private final ReplyRepository replyRepository; @@ -148,4 +150,22 @@ public DefaultResponse> getPostInfoList(Long id, Pageable page PageImpl postInfoDtosImpl = new PageImpl<>(postInfoDtos.toList(), pageable, postInfoDtos.getTotalElements()); return new DefaultResponse<>(StatusCode.OK, ResponseMessage.FOUND_POST, postInfoDtosImpl); } + + public DefaultResponse deletePost(Long postId) { + Optional postOptional = postRepository.findById(postId); + if (postOptional.isEmpty()) { + return new DefaultResponse<>(StatusCode.BAD_REQUEST, ResponseMessage.NOT_FOUND_POST); + } + Post post = postOptional.get(); + + postImageRepository.deleteAll(post.getImages()); + postTagRepository.deleteAll(post.getTags()); + postLikeRepository.deleteAll(post.getPostLikes()); + replyImageRepository.deleteAll(post.getReplies().stream().flatMap(reply -> reply.getImages().stream()).collect(Collectors.toList())); + replyLikeRepository.deleteAll(post.getReplies().stream().flatMap(reply -> reply.getLikes().stream()).collect(Collectors.toList())); + replyRepository.deleteAll(post.getReplies()); + postRepository.delete(post); + + return new DefaultResponse<>(StatusCode.OK, ResponseMessage.DELETED_POST); + } } diff --git a/src/main/java/com/devin/dev/utils/ResponseMessage.java b/src/main/java/com/devin/dev/utils/ResponseMessage.java index d55133c..024bb69 100644 --- a/src/main/java/com/devin/dev/utils/ResponseMessage.java +++ b/src/main/java/com/devin/dev/utils/ResponseMessage.java @@ -20,6 +20,7 @@ public enum ResponseMessage { FOUND_POST("게시글 검색 성공"), POST_UPLOAD_SUCCESS("게시글 등록 성공"), POST_EDIT_SUCCESS("게시글 수정 성공"), + DELETED_POST("게시글 삭제 성공"), REPLY_UPLOAD_SUCCESS("답변 등록 성공"), REPLY_EDIT_SUCCESS("답변 수정 성공"), REPLY_DELETE_SUCCESS("답변 삭제 성공"), From bf9639cebd17cf5122a28d99dd65bda0d4b40b4e Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 16:47:50 +0900 Subject: [PATCH 10/12] =?UTF-8?q?[#14]test:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/devin/dev/mvc/PostControllerTest.java | 11 ++++++++++- .../com/devin/dev/service/PostServiceTest.java | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/devin/dev/mvc/PostControllerTest.java b/src/test/java/com/devin/dev/mvc/PostControllerTest.java index 759ebfe..fc1b3f5 100644 --- a/src/test/java/com/devin/dev/mvc/PostControllerTest.java +++ b/src/test/java/com/devin/dev/mvc/PostControllerTest.java @@ -7,6 +7,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.annotation.Rollback; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @@ -15,6 +16,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -43,7 +45,14 @@ void requestPostSucceeded() throws Exception { @WithMockUser void requestPostFailed() throws Exception { mvc.perform(get("/postlist/0")) - .andExpect(status().is4xxClientError()) + .andDo(print()); + } + + @Test + @WithMockUser + void requestDeleteSucceeded() throws Exception { + List posts = postRepository.findByTitle("title_2"); + mvc.perform(delete("/postlist/" + posts.get(0).getId())) .andDo(print()); } } \ No newline at end of file diff --git a/src/test/java/com/devin/dev/service/PostServiceTest.java b/src/test/java/com/devin/dev/service/PostServiceTest.java index ea10ceb..6e7cf0b 100644 --- a/src/test/java/com/devin/dev/service/PostServiceTest.java +++ b/src/test/java/com/devin/dev/service/PostServiceTest.java @@ -126,7 +126,6 @@ void getPostSucceeded() { ReplyOrderCondition replyOrderCondition = new ReplyOrderCondition(); replyOrderCondition.setLatestDate(true); -// replyOrderCondition.setLikeCount(true); DefaultResponse response = postService.getPost(post1.getId(), replyOrderCondition); assertThat(response.getStatusCode()).isEqualTo(StatusCode.OK); @@ -137,4 +136,21 @@ void getPostSucceeded() { assertThat(postDto.getPublisher_name()).isEqualTo("D"); assertThat(postDto.getPost_images()).containsExactly("p1","p2","p3"); } + + @Test + void deleteSucceeded() { + Post post1 = new Post(postUser, "PostC1", "ContentC1"); + List postTags = PostTag.createPostTags(List.of(subject1, subject2)); + post1.setPostTags(postTags); + List postImages = PostImage.createPostImages(List.of("p1", "p2", "p3")); + post1.setPostImages(postImages); + postTags.forEach(em::persist); + postImages.forEach(em::persist); + em.persist(post1); + + postService.deletePost(post1.getId()); + + Post post = em.find(Post.class, post1.getId()); + assertThat(post).isNull(); + } } \ No newline at end of file From 7b7687704fe7270f028addf1524c62d019e74ef3 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 16:58:24 +0900 Subject: [PATCH 11/12] =?UTF-8?q?[#14]fix:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20URI=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/devin/dev/controller/post/PostController.java | 2 +- src/test/java/com/devin/dev/mvc/PostControllerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/devin/dev/controller/post/PostController.java b/src/main/java/com/devin/dev/controller/post/PostController.java index 7e1f4b6..e40658d 100644 --- a/src/main/java/com/devin/dev/controller/post/PostController.java +++ b/src/main/java/com/devin/dev/controller/post/PostController.java @@ -41,7 +41,7 @@ public DefaultResponse getPostListByCondition(PostSearchCondition condition, return postService.getPostInfoListByCondition(condition, pageable); } - @DeleteMapping("/postlist/{id}") + @DeleteMapping("/post/{id}") public DefaultResponse deletePost(@PathVariable("id") Long postId) { return postService.deletePost(postId); } diff --git a/src/test/java/com/devin/dev/mvc/PostControllerTest.java b/src/test/java/com/devin/dev/mvc/PostControllerTest.java index fc1b3f5..a5fd747 100644 --- a/src/test/java/com/devin/dev/mvc/PostControllerTest.java +++ b/src/test/java/com/devin/dev/mvc/PostControllerTest.java @@ -52,7 +52,7 @@ void requestPostFailed() throws Exception { @WithMockUser void requestDeleteSucceeded() throws Exception { List posts = postRepository.findByTitle("title_2"); - mvc.perform(delete("/postlist/" + posts.get(0).getId())) + mvc.perform(delete("/post/" + posts.get(0).getId())) .andDo(print()); } } \ No newline at end of file From a7cc85e089de95936b41eca1c4201b2db2ee7513 Mon Sep 17 00:00:00 2001 From: enjay27 Date: Fri, 11 Jun 2021 20:41:57 +0900 Subject: [PATCH 12/12] =?UTF-8?q?[#16]feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/controller/post/PostController.java | 14 ++++-- .../devin/dev/controller/post/PostForm.java | 13 ++++++ .../com/devin/dev/service/PostService.java | 45 ++++++++++++++++++- .../com/devin/dev/mvc/PostControllerTest.java | 28 +++++++++++- 4 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/devin/dev/controller/post/PostForm.java diff --git a/src/main/java/com/devin/dev/controller/post/PostController.java b/src/main/java/com/devin/dev/controller/post/PostController.java index e40658d..df9a272 100644 --- a/src/main/java/com/devin/dev/controller/post/PostController.java +++ b/src/main/java/com/devin/dev/controller/post/PostController.java @@ -3,6 +3,7 @@ import com.devin.dev.controller.reply.ReplyOrderCondition; import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.model.DefaultResponse; +import com.devin.dev.security.JwtAuthTokenProvider; import com.devin.dev.service.PostService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Sort; @@ -10,6 +11,8 @@ import org.springframework.web.bind.annotation.*; import org.springframework.data.domain.Pageable; +import javax.servlet.http.HttpServletRequest; + @RestController @RequiredArgsConstructor public class PostController { @@ -17,8 +20,8 @@ public class PostController { private final PostService postService; @GetMapping("/postlist/posts") - public DefaultResponse getPostList(@RequestParam(defaultValue = "-1")Long id, - @PageableDefault(page = 0, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) { + public DefaultResponse getPostList(@RequestParam(defaultValue = "-1") Long id, + @PageableDefault(page = 0, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) { return postService.getPostInfoList(id, pageable); } @@ -36,7 +39,8 @@ public DefaultResponse getPostDetails( } @GetMapping("/postlist") - public DefaultResponse getPostListByCondition(PostSearchCondition condition, + public DefaultResponse getPostListByCondition( + PostSearchCondition condition, @PageableDefault(page = 0, sort = "createdDate", direction = Sort.Direction.DESC) Pageable pageable) { return postService.getPostInfoListByCondition(condition, pageable); } @@ -46,4 +50,8 @@ public DefaultResponse deletePost(@PathVariable("id") Long postI return postService.deletePost(postId); } + @PostMapping("/post") + public DefaultResponse post(@RequestBody PostForm form, HttpServletRequest request) { + return postService.post(request, form); + } } diff --git a/src/main/java/com/devin/dev/controller/post/PostForm.java b/src/main/java/com/devin/dev/controller/post/PostForm.java new file mode 100644 index 0000000..811df9b --- /dev/null +++ b/src/main/java/com/devin/dev/controller/post/PostForm.java @@ -0,0 +1,13 @@ +package com.devin.dev.controller.post; + +import lombok.Data; + +import java.util.List; + +@Data +public class PostForm { + private String title; + private String content; + private List post_images; + private List post_tags; +} diff --git a/src/main/java/com/devin/dev/service/PostService.java b/src/main/java/com/devin/dev/service/PostService.java index 6776cbe..71bd39a 100644 --- a/src/main/java/com/devin/dev/service/PostService.java +++ b/src/main/java/com/devin/dev/service/PostService.java @@ -1,12 +1,11 @@ package com.devin.dev.service; +import com.devin.dev.controller.post.PostForm; import com.devin.dev.controller.post.PostSearchCondition; import com.devin.dev.controller.reply.ReplyOrderCondition; import com.devin.dev.dto.post.PostDetailsDto; import com.devin.dev.dto.post.PostInfoDto; import com.devin.dev.entity.post.*; -import com.devin.dev.entity.reply.Reply; -import com.devin.dev.entity.reply.ReplyImage; import com.devin.dev.entity.user.User; import com.devin.dev.model.DefaultResponse; import com.devin.dev.repository.post.PostImageRepository; @@ -18,6 +17,7 @@ import com.devin.dev.repository.reply.ReplyLikeRepository; import com.devin.dev.repository.subject.SubjectRepository; import com.devin.dev.repository.user.UserRepository; +import com.devin.dev.security.JwtAuthTokenProvider; import com.devin.dev.utils.ResponseMessage; import com.devin.dev.utils.StatusCode; import lombok.RequiredArgsConstructor; @@ -27,6 +27,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -45,6 +46,44 @@ public class PostService { private final ReplyRepository replyRepository; private final ReplyImageRepository replyImageRepository; private final ReplyLikeRepository replyLikeRepository; + private final JwtAuthTokenProvider tokenProvider; + + @Transactional + public DefaultResponse post(HttpServletRequest request, PostForm form) { + String token = tokenProvider.parseToken(request); + Long userId; + if (tokenProvider.validateToken(token)) { + userId = tokenProvider.getUserId(token); + } else { + return new DefaultResponse<>(StatusCode.BAD_REQUEST, ResponseMessage.NOT_FOUND_USER); + } + + // 엔티티 조회. 실패시 에러코드 반환 + Optional userOptional = userRepository.findById(userId); + if (userOptional.isEmpty()) { + return new DefaultResponse<>(StatusCode.BAD_REQUEST, ResponseMessage.NOT_FOUND_USER); + } + User user = userOptional.get(); + List postSubjects = subjectRepository.findByNameIn(form.getPost_tags()); + + // 엔티티 생성 + List postImages = PostImage.createPostImages(form.getPost_images()); + List postTags = PostTag.createPostTags(postSubjects); + Post post = Post.createPostWithImages(user, form.getTitle(), form.getContent(), postTags, postImages); + + // 게시글 작성자 경험치증가 + user.changeExp(User.ExpChangeType.CREATE_POST); + + // 저장 + postRepository.save(post); + postImageRepository.saveAll(postImages); + postTagRepository.saveAll(postTags); + + PostDetailsDto postDetailsDto = new PostDetailsDto(post); + + // 성공 메시지 및 코드 반환 + return new DefaultResponse<>(StatusCode.OK, ResponseMessage.POST_UPLOAD_SUCCESS, postDetailsDto); + } @Transactional public DefaultResponse post(Long userId, String title, String content, List tags, List imagePaths) { @@ -169,3 +208,5 @@ public DefaultResponse deletePost(Long postId) { return new DefaultResponse<>(StatusCode.OK, ResponseMessage.DELETED_POST); } } + + diff --git a/src/test/java/com/devin/dev/mvc/PostControllerTest.java b/src/test/java/com/devin/dev/mvc/PostControllerTest.java index a5fd747..e150ccd 100644 --- a/src/test/java/com/devin/dev/mvc/PostControllerTest.java +++ b/src/test/java/com/devin/dev/mvc/PostControllerTest.java @@ -1,11 +1,15 @@ package com.devin.dev.mvc; +import com.devin.dev.controller.post.PostForm; import com.devin.dev.entity.post.Post; import com.devin.dev.repository.post.PostRepository; +import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.annotation.Rollback; import org.springframework.test.web.servlet.MockMvc; @@ -16,8 +20,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; @@ -32,6 +35,8 @@ class PostControllerTest { @Autowired private PostRepository postRepository; + private MockHttpServletRequest servletRequest = new MockHttpServletRequest(); + @Test @WithMockUser void requestPostSucceeded() throws Exception { @@ -55,4 +60,23 @@ void requestDeleteSucceeded() throws Exception { mvc.perform(delete("/post/" + posts.get(0).getId())) .andDo(print()); } + + @Test + @WithMockUser + void requestCreateSucceeded() throws Exception { + PostForm form = new PostForm(); + form.setContent("content_1"); + form.setPost_tags(List.of("tag_0","tag_1")); + form.setPost_images(List.of("img_1", "img_2")); + form.setTitle("title_1"); + mvc.perform( + post("/post").with(request -> { + request.setRemoteUser("USER"); + return request; + }) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(new ObjectMapper().writeValueAsString(form)) + ) + .andDo(print()); + } } \ No newline at end of file