Skip to content

Commit

Permalink
fix: search condition & paging count 추가 및 최적화 적용 (#5)
Browse files Browse the repository at this point in the history
포함하지 않았던 count query를 repository에서 계산 후 서비스가 사용
  • Loading branch information
toychip committed Dec 14, 2023
1 parent 713597d commit 4c61ff8
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.api.TaveShot.domain.Post.controller;

import com.api.TaveShot.domain.Post.dto.PostCreateRequest;
import com.api.TaveShot.domain.Post.dto.PostDto;
import com.api.TaveShot.domain.Post.dto.PostListResponse;
import com.api.TaveShot.domain.Post.dto.PostResponse;
import com.api.TaveShot.domain.Post.dto.PostSearchCondition;
import com.api.TaveShot.domain.Post.service.PostService;
import com.api.TaveShot.global.success.SuccessResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -34,29 +34,30 @@ public SuccessResponse<PostResponse> save(@RequestBody PostCreateRequest request

/* READ */
@GetMapping("/post/{postId}")
public SuccessResponse<PostResponse> read(@PathVariable Long postId) {
public SuccessResponse<PostResponse> getSinglePost(@PathVariable Long postId) {
PostResponse postResponse = postService.findById(postId);
return new SuccessResponse<>(postResponse);
}

/* UPDATE */
@PutMapping("/post/{id}")
public ResponseEntity<Long> update(@PathVariable Long id, @RequestBody PostDto.Request dto) {
postService.update(id, dto);
return ResponseEntity.ok(id);
@GetMapping("/post")
public SuccessResponse<PostListResponse> getPagePost(@RequestBody PostSearchCondition condition, Pageable pageable) {
PostListResponse postListResponse = postService.searchPostPaging(condition, pageable);
return new SuccessResponse<>(postListResponse);
}

// /* UPDATE */
// @PutMapping("/post/{id}")
// public ResponseEntity<Long> update(@PathVariable Long id, @RequestBody PostDto.Request dto) {
// postService.update(id, dto);
// return ResponseEntity.ok(id);
// }

/* DELETE */
@DeleteMapping("/post/{postId}")
public ResponseEntity<Long> delete(@PathVariable Long postId) {
postService.delete(postId);
return ResponseEntity.ok(postId);
}

@GetMapping("/postlistWithCommentCount")
public List<PostDto.Response> postlistWithCommentCount() {
return postService.findAllWithCommentCount();
}


}
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
package com.api.TaveShot.domain.Post.controller;

import com.api.TaveShot.domain.Post.dto.PostDto;
import com.api.TaveShot.domain.Post.service.PostService;
import com.api.TaveShot.global.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class PostIndexController {

private final PostService postService;

@GetMapping("/postlist")
public ResponseEntity<Page<PostDto.Response>> index(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
Page<PostDto.Response> list = postService.pageList(pageable);
return ResponseEntity.ok(list);
}

@GetMapping("/post/read/{id}")
public ResponseEntity<PostDto.Response> read(@PathVariable Long id) {
PostDto.Response dto = postService.findById(id);
return ResponseEntity.ok(dto);
}

@GetMapping("/post/write")
public ResponseEntity<String> write() {
// 현재 로그인한 사용자의 gitLoginId 가져오기
String currentUserId = SecurityUtil.getCurrentMember().getGitLoginId();
return ResponseEntity.ok(currentUserId);
}

@GetMapping("/post/update/{id}")
public ResponseEntity<PostDto.Response> update(@PathVariable Long id) {
PostDto.Response dto = postService.findById(id);

// 현재 로그인한 사용자의 gitLoginId 가져오기
String currentUserId = SecurityUtil.getCurrentMember().getGitLoginId();

// 게시글 작성자의 아이디
String writerId = dto.getWriterId().toString();

// 현재 로그인한 사용자와 게시글 작성자를 비교하여 권한 확인
if (currentUserId.equals(writerId)) {
return ResponseEntity.ok(dto);
} else {
return ResponseEntity.status(403).build();
}
}

@GetMapping("/post/search")
public ResponseEntity<Page<PostDto.Response>> search(@RequestParam String keyword, @PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
Page<PostDto.Response> searchList = postService.search(keyword, pageable);
return ResponseEntity.ok(searchList);
}
}
//package com.api.TaveShot.domain.Post.controller;
//
//import com.api.TaveShot.domain.Post.dto.PostDto;
//import com.api.TaveShot.domain.Post.service.PostService;
//import com.api.TaveShot.global.util.SecurityUtil;
//import lombok.RequiredArgsConstructor;
//import org.springframework.data.domain.Page;
//import org.springframework.data.domain.Pageable;
//import org.springframework.data.domain.Sort;
//import org.springframework.data.web.PageableDefault;
//import org.springframework.http.ResponseEntity;
//import org.springframework.web.bind.annotation.*;
//
//
//@RestController
//@RequestMapping("/api/v1")
//@RequiredArgsConstructor
//public class PostIndexController {
//
// private final PostService postService;
//
// @GetMapping("/postlist")
// public ResponseEntity<Page<PostDto.Response>> index(@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
// Page<PostDto.Response> list = postService.pageList(pageable);
// return ResponseEntity.ok(list);
// }
//
// @GetMapping("/post/read/{id}")
// public ResponseEntity<PostDto.Response> read(@PathVariable Long id) {
// PostDto.Response dto = postService.findById(id);
// return ResponseEntity.ok(dto);
// }
//
// @GetMapping("/post/write")
// public ResponseEntity<String> write() {
// // 현재 로그인한 사용자의 gitLoginId 가져오기
// String currentUserId = SecurityUtil.getCurrentMember().getGitLoginId();
// return ResponseEntity.ok(currentUserId);
// }
//
// @GetMapping("/post/update/{id}")
// public ResponseEntity<PostDto.Response> update(@PathVariable Long id) {
// PostDto.Response dto = postService.findById(id);
//
// // 현재 로그인한 사용자의 gitLoginId 가져오기
// String currentUserId = SecurityUtil.getCurrentMember().getGitLoginId();
//
// // 게시글 작성자의 아이디
// String writerId = dto.getWriterId().toString();
//
// // 현재 로그인한 사용자와 게시글 작성자를 비교하여 권한 확인
// if (currentUserId.equals(writerId)) {
// return ResponseEntity.ok(dto);
// } else {
// return ResponseEntity.status(403).build();
// }
// }
//
// @GetMapping("/post/search")
// public ResponseEntity<Page<PostDto.Response>> search(@RequestParam String keyword, @PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
// Page<PostDto.Response> searchList = postService.search(keyword, pageable);
// return ResponseEntity.ok(searchList);
// }
//}
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package com.api.TaveShot.domain.Post.domain;
package com.api.TaveShot.domain.Post.repository;

import com.api.TaveShot.domain.Post.dto.PostDto;
import com.api.TaveShot.domain.Post.domain.Post;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface PostRepository extends JpaRepository<Post,Long> {
public interface PostRepository extends JpaRepository<Post,Long>, PostRepositoryCustom {
@Modifying
@Query("update Post p set p.view = p.view + 1 where p.id = :id")
int updateView(Long id);

@Query("SELECT new com.api.TaveShot.domain.Post.dto.PostDto.Response(p) FROM Post p LEFT JOIN p.comments c GROUP BY p.id")
List<PostDto.Response> findAllWithCommentCount();
// @Query("SELECT new com.api.TaveShot.domain.Post.dto.PostDto.Response(p) FROM Post p LEFT JOIN p.comments c GROUP BY p.id")
// List<PostDto.Response> findAllWithCommentCount();



Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package com.api.TaveShot.domain.Post.repository;

import com.api.TaveShot.domain.Post.dto.PostListResponse;
import com.api.TaveShot.domain.Post.dto.PostResponse;
import com.api.TaveShot.domain.Post.dto.PostSearchCondition;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface PostRepositoryCustom {
List<PostResponse> searchPagePost(PostSearchCondition condition, Pageable pageable);
// List<PostResponse> searchPagePost(PostSearchCondition condition, Pageable pageable);

// Long searchCountPost(PostSearchCondition condition, Pageable pageable);

Page<PostResponse> searchPagePost(PostSearchCondition condition, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@
import com.api.TaveShot.domain.Post.dto.PostResponse;
import com.api.TaveShot.domain.Post.dto.PostSearchCondition;
import com.api.TaveShot.domain.Post.dto.QPostResponse;
import com.api.TaveShot.global.config.DataBaseConfig;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Wildcard;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.util.StringUtils;

@RequiredArgsConstructor
public class PostRepositoryImpl implements PostRepositoryCustom {

private final DataBaseConfig dataBaseConfig;
private final JPAQueryFactory jpaQueryFactory;

@Override
public List<PostResponse> searchPagePost(PostSearchCondition condition, Pageable pageable) {
public Page<PostResponse> searchPagePost(PostSearchCondition condition, Pageable pageable) {

return dataBaseConfig.jpaQueryFactory()
List<PostResponse> postResponses = getSearchPageContent(condition, pageable);
JPAQuery<Long> searchPageCount = getSearchPageCount(condition);

return PageableExecutionUtils.getPage(postResponses, pageable, searchPageCount::fetchOne);
}

private List<PostResponse> getSearchPageContent(PostSearchCondition condition, Pageable pageable) {
return jpaQueryFactory
.select(
new QPostResponse(post.id, post.title, post.content,
post.writer, post.viewCount, post.member.id))
Expand All @@ -36,6 +47,17 @@ public List<PostResponse> searchPagePost(PostSearchCondition condition, Pageable
.fetch();
}

private JPAQuery<Long> getSearchPageCount(PostSearchCondition condition) {
return jpaQueryFactory
.select(Wildcard.count)
.from(post)
.where(
containTitle(condition.getTitle()),
containContent(condition.getContent()),
containWriter(condition.getWriter())
);
}

private BooleanExpression containTitle(String title) {
if (StringUtils.hasText(title)) {
return post.title.contains(title);
Expand Down
60 changes: 23 additions & 37 deletions src/main/java/com/api/TaveShot/domain/Post/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import com.api.TaveShot.domain.Member.domain.Member;
import com.api.TaveShot.domain.Post.converter.PostConverter;
import com.api.TaveShot.domain.Post.domain.Post;
import com.api.TaveShot.domain.Post.domain.PostRepository;
import com.api.TaveShot.domain.Post.dto.PostCreateRequest;
import com.api.TaveShot.domain.Post.dto.PostDto;
import com.api.TaveShot.domain.Post.dto.PostListResponse;
import com.api.TaveShot.domain.Post.dto.PostResponse;
import com.api.TaveShot.domain.Post.dto.PostSearchCondition;
import com.api.TaveShot.domain.Post.repository.PostRepository;
import com.api.TaveShot.global.exception.ApiException;
import com.api.TaveShot.global.exception.ErrorType;
import com.api.TaveShot.global.util.SecurityUtil;
Expand Down Expand Up @@ -40,11 +41,7 @@ public PostResponse save(PostCreateRequest request) {
return PostConverter.entityToResponse(post);
}




/* READ */

/* READ Single */
public PostResponse findById(Long postId) {
Post post = postRepository.findById(postId).orElseThrow(
() -> new ApiException(ErrorType._POST_NOT_FOUND));
Expand All @@ -54,14 +51,26 @@ public PostResponse findById(Long postId) {
return PostConverter.entityToResponse(post);
}

/* UPDATE */
@Transactional
public void update(Long id, PostDto.Request dto) {
Post post = postRepository.findById(id).orElseThrow(() ->
new IllegalArgumentException("해당 게시글이 존재하지 않습니다. id=" + id));

post.update(dto.getTitle(), dto.getContent(),dto.getAttachmentFile());
/* READ Paging */

public PostListResponse searchPostPaging(PostSearchCondition condition, Pageable pageable) {
Page<PostResponse> postResponses = postRepository.searchPagePost(condition, pageable);
return PostListResponse.builder()
.postResponses(postResponses.getContent())
.totalPage(postResponses.getTotalPages())
.totalElements(postResponses.getTotalElements())
.isFirst(postResponses.isFirst())
.isLast(postResponses.isLast())
.build();
}
// /* UPDATE */
// @Transactional
// public void update(Long id, PostDto.Request dto) {
// Post post = postRepository.findById(id).orElseThrow(() ->
// new IllegalArgumentException("해당 게시글이 존재하지 않습니다. id=" + id));
//
// post.update(dto.getTitle(), dto.getContent(),dto.getAttachmentFile());
// }

/* DELETE (영구 삭제 안되도록 어쩌구는 추후에 다시..) */
@Transactional
Expand All @@ -72,27 +81,4 @@ public void delete(Long postId) {
postRepository.delete(post);
}

/* Views Counting */
@Transactional
public int updateView(Long id) {
return postRepository.updateView(id);
}

/* Paging and Sort */
public Page<PostDto.Response> pageList(Pageable pageable) {
Page<Post> postPage = postRepository.findAll(pageable);
return postPage.map(PostDto.Response::new);
}

/* search */
public Page<PostDto.Response> search(String keyword, Pageable pageable) {
Page<Post> searchResult = postRepository.findByTitleContaining(keyword, pageable);
return searchResult.map(PostDto.Response::new);
}

public List<PostDto.Response> findAllWithCommentCount() {
return postRepository.findAllWithCommentCount();
}


}

0 comments on commit 4c61ff8

Please sign in to comment.