Skip to content

Commit

Permalink
Merge pull request #41 from ssu-student-union/feat/40-post
Browse files Browse the repository at this point in the history
[feat] #40 게시판별 좋아요 많은 게시물 api 구현 및 쿼리dsl, common(페이지네이션, p6spy)
  • Loading branch information
chahyunsoo authored Aug 1, 2024
2 parents 0c5a5ac + 5141fac commit 9ffc3c6
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 13 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'

// P6spy
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'

// querydsl
implementation "com.querydsl:querydsl-jpa:5.0.0:jakarta"
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" // querydsl JPAAnnotationProcessor 사용 지정
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ public class QPostEntity extends EntityPathBase<PostEntity> {
//inherited
public final DateTimePath<java.time.LocalDateTime> createdAt = _super.createdAt;

public final DateTimePath<java.time.LocalDateTime> deletedAt = createDateTime("deletedAt", java.time.LocalDateTime.class);

public final NumberPath<Long> id = createNumber("id", Long.class);

public final DateTimePath<java.time.LocalDateTime> lastEditedAt = createDateTime("lastEditedAt", java.time.LocalDateTime.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import ussum.homepage.application.post.service.PostService;
import ussum.homepage.application.post.service.dto.request.PostCreateRequest;
import ussum.homepage.application.post.service.dto.request.PostUpdateRequest;
import ussum.homepage.application.post.service.dto.response.PostListResponse;
import ussum.homepage.application.post.service.dto.response.PostResponse;
import ussum.homepage.application.post.service.dto.response.TopLikedPostListResponse;
import ussum.homepage.global.ApiResponse;
import ussum.homepage.global.config.auth.UserId;

Expand All @@ -26,6 +28,14 @@ public ApiResponse<PostListResponse> getBoardPostsList(@RequestParam(value = "pa
return ApiResponse.onSuccess(postList);
}

@GetMapping("/{boardCode}/posts/top-liked")
public ResponseEntity<ApiResponse<?>> getTopLikedBoardPostList(@RequestParam(value = "page", defaultValue = "0") int page, @RequestParam(value = "take") int take,
@PathVariable(name = "boardCode") String boardCode) {

TopLikedPostListResponse postList = postService.getTopLikedPostList(page, take, boardCode);
return ApiResponse.success(postList);
}

@GetMapping("/{boardCode}/posts/{postId}")
public ApiResponse<PostResponse> getBoardPost(@PathVariable(name = "boardCode") String boardCode,
@PathVariable(name = "postId") Long postId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ussum.homepage.application.post.service.dto.BoardResponse;
import ussum.homepage.application.post.service.dto.request.BoardUpdateRequest;

import ussum.homepage.application.post.service.dto.request.PostCreateRequest;
import ussum.homepage.application.post.service.dto.request.PostSearchRequest;
import ussum.homepage.application.post.service.dto.request.PostUpdateRequest;
import ussum.homepage.application.post.service.dto.response.PostListResponse;
import ussum.homepage.application.post.service.dto.response.PostResponse;
import ussum.homepage.application.post.service.dto.response.*;
import ussum.homepage.domain.post.Board;
import ussum.homepage.domain.post.Category;
import ussum.homepage.domain.post.Post;
import ussum.homepage.domain.post.service.*;
import ussum.homepage.domain.user.User;
import ussum.homepage.domain.user.service.UserReader;
import ussum.homepage.infra.jpa.user.entity.MajorCode;
import ussum.homepage.global.common.PageInfo;
import ussum.homepage.infra.jpa.post.PostMapper;
import ussum.homepage.infra.jpa.post.dto.SimplePostDto;

import java.util.List;

Expand All @@ -35,6 +34,7 @@ public class PostService {
private final PostFormatter postFormatter;
private final PostAppender postAppender;
private final PostModifier postModifier;
private final PostMapper postMapper;


public PostListResponse getPostList(Pageable pageable, String boardCode) {
Expand All @@ -43,6 +43,14 @@ public PostListResponse getPostList(Pageable pageable, String boardCode) {
return PostListResponse.of(postList.getContent(), (int) postList.getTotalElements(), postFormatter::format);
}

public TopLikedPostListResponse getTopLikedPostList(int page, int take, String boardCode){
Pageable pageable = PageInfo.of(page,take);
Page<SimplePostResponse> simplePostDtoList = postReader.findSimplePostDtoListByBoardCode(boardCode, pageable);
PageInfo pageInfo = PageInfo.of(simplePostDtoList);

return TopLikedPostListResponse.of(simplePostDtoList.getContent(), pageInfo);
}

public PostResponse getPost(String boardCode, Long postId) {
return postFormatter.format(
postReader.getPostWithBoardCode(boardCode, postId).getId()
Expand Down Expand Up @@ -73,5 +81,9 @@ public PostListResponse searchPost(Pageable pageable, String boardCode, String q
return PostListResponse.of(searchPost.getContent(), (int) searchPost.getTotalElements(),
postFormatter::format);
}

private List<SimplePostResponse> createSimplePostResponse(List<SimplePostResponse> simplePostDtoList){
return simplePostDtoList.stream().toList();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ussum.homepage.application.post.service.dto.response;

import lombok.AccessLevel;
import lombok.Builder;
import ussum.homepage.domain.post.Post;

@Builder(access = AccessLevel.PRIVATE)
public record SimplePostResponse(
Long postId,
String title,
String content,
String date,
Integer like
) {
public static SimplePostResponse of(Post post,
Integer like){
return SimplePostResponse.builder()
.postId(post.getId())
.title(post.getTitle())
.content(post.getContent())
.date(post.getCreatedAt())
.like(like)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ussum.homepage.application.post.service.dto.response;

import lombok.AccessLevel;
import lombok.Builder;
import ussum.homepage.global.common.PageInfo;

import java.util.List;
@Builder(access = AccessLevel.PRIVATE)
public record TopLikedPostListResponse(
List<SimplePostResponse> posts,
PageInfo pageInfo
) {
public static TopLikedPostListResponse of(List<SimplePostResponse> posts, PageInfo pageInfo){
return TopLikedPostListResponse.builder()
.posts(posts)
.pageInfo(pageInfo)
.build();
}
}
4 changes: 4 additions & 0 deletions src/main/java/ussum/homepage/domain/post/PostRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import ussum.homepage.application.post.service.dto.response.SimplePostResponse;
import ussum.homepage.infra.jpa.post.dto.SimplePostDto;


import java.util.List;
import java.util.Optional;
Expand All @@ -15,4 +18,5 @@ public interface PostRepository {
Post save(Post post);
void delete(Post post);
Page<Post> findBySearchCriteria(Pageable pageable,String boardCode, String q, String categoryCode);
Page<SimplePostResponse> findPostDtoListByBoardCode(String boardCode, Pageable pageable);
}
10 changes: 7 additions & 3 deletions src/main/java/ussum/homepage/domain/post/service/PostReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import ussum.homepage.application.post.service.dto.request.PostSearchRequest;

import ussum.homepage.application.post.service.dto.response.SimplePostResponse;
import ussum.homepage.infra.jpa.post.dto.SimplePostDto;
import ussum.homepage.domain.post.Board;
import ussum.homepage.domain.post.BoardRepository;
import ussum.homepage.domain.post.Post;
import ussum.homepage.domain.post.PostRepository;
import ussum.homepage.global.error.exception.GeneralException;

import java.util.List;

import static ussum.homepage.global.error.status.ErrorStatus.BOARD_NOT_FOUND;
import static ussum.homepage.global.error.status.ErrorStatus.POST_NOT_FOUND;

Expand All @@ -25,6 +25,10 @@ public Page<Post> getPostList(Pageable pageable, String boardCode) {
return postRepository.findAllWithBoard(pageable, boardCode);
}

public Page<SimplePostResponse> findSimplePostDtoListByBoardCode(String boardCode, Pageable pageable){
return postRepository.findPostDtoListByBoardCode(boardCode, pageable);
}

public Post getPostWithId(Long postId) {
return postRepository.findById(postId).orElseThrow(()-> new GeneralException(POST_NOT_FOUND));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ussum.homepage.global.common;

import com.p6spy.engine.logging.Category;
import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

@Component
public class CustomP6spySqlFormatter implements MessageFormattingStrategy {
@Override
public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
sql = formatSql(category, sql);
return String.format("[SQL] %s | %s | %d ms | %s ", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()), category, elapsed, formatSql(category, sql));
}

private String formatSql(String category, String sql) {
if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) {
String trimmedSql = sql.trim().toLowerCase(Locale.ROOT);
if (trimmedSql.startsWith("create") || trimmedSql.startsWith("alter") || trimmedSql.startsWith("comment")) {
sql = FormatStyle.DDL.getFormatter().format(sql);
}
sql = FormatStyle.BASIC.getFormatter().format(sql);
return sql;
}
return sql;
}
}
27 changes: 27 additions & 0 deletions src/main/java/ussum/homepage/global/common/PageInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package ussum.homepage.global.common;

import lombok.AccessLevel;
import lombok.Builder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

@Builder(access = AccessLevel.PRIVATE)
public record PageInfo(
int pageNum,
int pageSize,
long totalElements,
long totalPages
) {
public static PageInfo of(Page<?> page) {
return PageInfo.builder()
.pageNum(page.getNumber())
.pageSize(page.getSize())
.totalElements(page.getTotalElements())
.totalPages(page.getTotalPages())
.build();
}
public static Pageable of(int page, int take){
return PageRequest.of(page, take);
}
}
8 changes: 8 additions & 0 deletions src/main/java/ussum/homepage/infra/jpa/post/PostMapper.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package ussum.homepage.infra.jpa.post;

import org.springframework.stereotype.Component;
import ussum.homepage.application.post.service.dto.response.SimplePostResponse;
import ussum.homepage.application.post.service.dto.response.TopLikedPostListResponse;
import ussum.homepage.domain.post.Board;
import ussum.homepage.domain.post.Category;
import ussum.homepage.domain.post.Post;
import ussum.homepage.domain.user.User;
import ussum.homepage.global.common.PageInfo;
import ussum.homepage.infra.jpa.post.entity.BoardCode;
import ussum.homepage.infra.jpa.post.entity.BoardEntity;
import ussum.homepage.infra.jpa.post.entity.CategoryEntity;
import ussum.homepage.infra.jpa.post.entity.PostEntity;
import ussum.homepage.infra.jpa.user.entity.UserEntity;

import java.time.LocalDateTime;
import java.util.List;

@Component
public class PostMapper {
Expand Down Expand Up @@ -55,4 +59,8 @@ public PostEntity toEntity(Post post, UserEntity user, BoardEntity board, Catego
);
}

public TopLikedPostListResponse toTopLikedPostListResponse(List<SimplePostResponse> postResponseList, PageInfo pageInfo){
return TopLikedPostListResponse.of(postResponseList, pageInfo);
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package ussum.homepage.infra.jpa.post;

import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;
import ussum.homepage.domain.post.Board;

import ussum.homepage.application.post.service.dto.response.SimplePostResponse;
import ussum.homepage.infra.jpa.post.dto.SimplePostDto;
import ussum.homepage.domain.post.Post;
import ussum.homepage.domain.post.PostRepository;
import ussum.homepage.global.error.exception.GeneralException;
Expand All @@ -19,14 +26,19 @@
import ussum.homepage.infra.jpa.user.entity.UserEntity;
import ussum.homepage.infra.jpa.user.repository.UserJpaRepository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static ussum.homepage.global.error.status.ErrorStatus.*;
import static ussum.homepage.infra.jpa.post.entity.PostEntity.increaseViewCount;

import static ussum.homepage.infra.jpa.post.entity.QPostEntity.postEntity;
import static ussum.homepage.infra.jpa.postlike.entity.QPostReactionEntity.postReactionEntity;
import static ussum.homepage.infra.jpa.post.entity.QBoardEntity.boardEntity;

import static ussum.homepage.infra.jpa.post.entity.PostEntity.updateLastEditedAt;


@Repository
@RequiredArgsConstructor
public class PostRepositoryImpl implements PostRepository {
Expand All @@ -35,6 +47,7 @@ public class PostRepositoryImpl implements PostRepository {
private final CategoryJpaRepository categoryJpaRepository;
private final UserJpaRepository userJpaRepository;
private final PostMapper postMapper;
private final JPAQueryFactory queryFactory;

@Override
public Optional<Post> findById(Long postId) {
Expand Down Expand Up @@ -111,4 +124,39 @@ public Page<Post> findBySearchCriteria(Pageable pageable,String boardCode, Strin
q.isEmpty() ? null : q,
categoryCode.isEmpty() ? null : MajorCode.getEnumMajorCodeFromStringMajorCode(categoryCode)).map(postMapper::toDomain);
}

@Override
public Page<SimplePostResponse> findPostDtoListByBoardCode(String boardCode, Pageable pageable) {

List<SimplePostResponse> contents = queryFactory
.select(Projections.constructor(SimplePostDto.class,
postEntity,
postReactionEntity.countDistinct().castToNum(Long.class)
))
.from(postEntity)
.leftJoin(postReactionEntity).on(postReactionEntity.postEntity.eq(postEntity))
.leftJoin(postEntity.boardEntity, boardEntity)
.where(eqBoardCode(boardCode))
.groupBy(postEntity)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch()
.stream()
.map(simplePostDto -> SimplePostResponse.of(
postMapper.toDomain(simplePostDto.postEntity()),
Math.toIntExact(simplePostDto.likeCount())))
.toList();

JPAQuery<Long> countQuery = queryFactory
.select(boardEntity.boardCode.countDistinct())
.from(postEntity)
.leftJoin(postReactionEntity).on(postReactionEntity.postEntity.eq(postEntity))
.leftJoin(postEntity.boardEntity, boardEntity)
.where(eqBoardCode(boardCode))
.groupBy(postEntity);
return PageableExecutionUtils.getPage(contents, pageable, countQuery::fetchCount);
}
private BooleanExpression eqBoardCode(String boardCode) {
return boardCode != null ? boardEntity.boardCode.eq(BoardCode.getEnumBoardCodeFromStringBoardCode(boardCode)) : null;
}
}
11 changes: 11 additions & 0 deletions src/main/java/ussum/homepage/infra/jpa/post/dto/SimplePostDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ussum.homepage.infra.jpa.post.dto;

import ussum.homepage.infra.jpa.post.entity.PostEntity;


public record SimplePostDto(PostEntity postEntity, Long likeCount) {

public static SimplePostDto of(PostEntity post, Long likeCount) {
return new SimplePostDto(post, likeCount);
}
}

0 comments on commit 9ffc3c6

Please sign in to comment.