Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend-board/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'

//Querydsl 추가
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}

tasks.named('test') {
Expand All @@ -62,3 +68,8 @@ test {
jar {
enabled = false
}

clean {
delete file('src/main/generated')
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDateTime;

import com.backendboard.domain.comment.entity.Comment;
import com.querydsl.core.annotations.QueryProjection;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
Expand Down Expand Up @@ -30,9 +31,9 @@ public class CommentReadResponse {
private final LocalDateTime lastModifiedDate;

@Builder
private CommentReadResponse(Long id, Long postId, String author, String content, LocalDateTime createdDate,
LocalDateTime lastModifiedDate
) {
@QueryProjection
public CommentReadResponse(Long id, Long postId, String author, String content, LocalDateTime createdDate,
LocalDateTime lastModifiedDate) {
this.id = id;
this.postId = postId;
this.author = author;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDateTime;

import com.backendboard.domain.comment.entity.Comment;
import com.querydsl.core.annotations.QueryProjection;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
Expand Down Expand Up @@ -30,7 +31,8 @@ public class CommentSliceResponse {
private final LocalDateTime lastModifiedDate;

@Builder
private CommentSliceResponse(Long id, Long postId, String author, String content, LocalDateTime createdDate,
@QueryProjection
public CommentSliceResponse(Long id, Long postId, String author, String content, LocalDateTime createdDate,
LocalDateTime lastModifiedDate) {
this.id = id;
this.postId = postId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -15,6 +17,11 @@
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(
indexes = {
@Index(name = "idx_created_date", columnList = "createdDate")
}
)
public class Comment extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.backendboard.domain.comment.repository;

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;

import com.backendboard.domain.comment.dto.CommentReadResponse;
import com.backendboard.domain.comment.dto.CommentSliceResponse;
import com.backendboard.domain.comment.dto.QCommentReadResponse;
import com.backendboard.domain.comment.dto.QCommentSliceResponse;
import com.backendboard.domain.comment.entity.QComment;
import com.backendboard.domain.user.entity.QUser;
import com.backendboard.global.error.CustomError;
import com.backendboard.global.error.CustomException;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class CommentQueryRepository {
private final JPAQueryFactory queryFactory;

public CommentReadResponse findCommentReadResponse(Long commentId) {
QComment comment = QComment.comment;
QUser user = QUser.user;

CommentReadResponse result = queryFactory
.select(new QCommentReadResponse(
comment.id,
comment.postId,
user.nickname,
comment.content,
comment.createdDate,
comment.lastModifiedDate
))
.from(comment)
.join(user).on(comment.userId.eq(user.id))
.where(comment.id.eq(commentId))
.fetchOne();

if (result == null) {
throw new CustomException(CustomError.COMMENT_NOT_FOUND);
}

return result;
}

public Slice<CommentSliceResponse> findCommentSliceResponse(Long postId, boolean deleted, Pageable pageable) {
QComment comment = QComment.comment;
QUser user = QUser.user;
boolean hasNext = false;
List<OrderSpecifier<?>> orderSpecifiers = getOrderSpecifiers(pageable, comment);

List<CommentSliceResponse> content = queryFactory
.select(new QCommentSliceResponse(
comment.id,
comment.postId,
user.nickname,
comment.content,
comment.createdDate,
comment.lastModifiedDate
))
.from(comment)
.join(user).on(comment.userId.eq(user.id))
.where(
comment.postId.eq(postId),
comment.deleted.eq(deleted)
)
.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]))
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

if (content.size() > pageable.getPageSize()) {
content.remove(pageable.getPageSize());
hasNext = true;
}

return new SliceImpl<>(content, pageable, hasNext);
}

private List<OrderSpecifier<?>> getOrderSpecifiers(Pageable pageable, QComment comment) {
List<OrderSpecifier<?>> orders = new ArrayList<>();

for (Sort.Order order : pageable.getSort()) {
PathBuilder<?> entityPath = new PathBuilder<>(comment.getType(), comment.getMetadata());
orders.add(
new OrderSpecifier(order.isAscending() ? Order.ASC : Order.DESC, entityPath.get(order.getProperty()))
);
}
return orders;
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
package com.backendboard.domain.comment.service;

import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
Expand All @@ -17,6 +12,7 @@
import com.backendboard.domain.comment.dto.CommentUpdateRequest;
import com.backendboard.domain.comment.dto.CommentUpdateResponse;
import com.backendboard.domain.comment.entity.Comment;
import com.backendboard.domain.comment.repository.CommentQueryRepository;
import com.backendboard.domain.comment.repository.CommentRepository;
import com.backendboard.domain.user.entity.User;
import com.backendboard.domain.user.repository.UserRepository;
Expand All @@ -29,6 +25,7 @@
@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {
private final CommentQueryRepository commentQueryRepository;
private final CommentRepository commentRepository;
private final UserRepository userRepository;

Expand Down Expand Up @@ -56,11 +53,7 @@ public CommentUpdateResponse updateComment(CommentUpdateRequest request, Long co

@Override
public CommentReadResponse getComment(Long commentId) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new CustomException(CustomError.COMMENT_NOT_FOUND));
User author = userRepository.findById(comment.getUserId())
.orElseThrow(() -> new CustomException(CustomError.USER_NOT_FOUND));
return CommentReadResponse.toDto(comment, author.getNickname());
return commentQueryRepository.findCommentReadResponse(commentId);
}

@Transactional
Expand All @@ -77,17 +70,7 @@ public void deleteComment(Long commentId, Long authUserId) {

@Override
public Slice<CommentSliceResponse> getCommetsSlice(Long postId, Pageable pageable) {
Slice<Comment> comments = commentRepository.findByPostIdAndDeleted(postId, false, pageable);

Set<Long> userIds = comments.stream().map(Comment::getUserId).collect(Collectors.toSet());

Map<Long, User> userMap = userRepository.findAllById(userIds)
.stream().collect(Collectors.toMap(User::getId, Function.identity()));

return comments.map(comment -> {
User user = userMap.get(comment.getUserId());
return CommentSliceResponse.toDto(comment, user.getNickname());
});
return commentQueryRepository.findCommentSliceResponse(postId, false, pageable);
}

public void validateAuthor(Comment comment, User user) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,14 @@ private PostReadResponse(Long id, String author, String title, String content, L
}

@Builder

public static PostReadResponse toDto(Post post, String author, List<PostImage> images, Long viewCount) {
public static PostReadResponse toDto(Post post, String author, List<PostImage> images) {
return PostReadResponse.builder()
.id(post.getId())
.author(author)
.title(post.getTitle())
.content(post.getContent())
.likeCount(post.getLikeCount())
.viewCount(viewCount)
.viewCount(post.getViewCount())
.images(images.stream().map(PostImageReadResponse::toDto).toList())
.createdDate(post.getCreatedDate())
.lastModifiedDate(post.getLastModifiedDate())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.LocalDateTime;

import com.backendboard.domain.post.entity.Post;
import com.querydsl.core.annotations.QueryProjection;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
Expand Down Expand Up @@ -36,7 +37,8 @@ public class PostSliceResponse {
private final LocalDateTime lastModifiedDate;

@Builder
private PostSliceResponse(Long id, String author, String title, String content, Long likeCount, Long viewCount,
@QueryProjection
public PostSliceResponse(Long id, String author, String title, String content, Long likeCount, Long viewCount,
LocalDateTime createdDate, LocalDateTime lastModifiedDate) {
this.id = id;
this.author = author;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -16,6 +18,13 @@
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(
indexes = {
@Index(name = "idx_like_count", columnList = "likeCount"),
@Index(name = "idx_view_count", columnList = "viewCount"),
@Index(name = "idx_created_date", columnList = "createdDate")
}
)
public class Post extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.backendboard.domain.post.respository;

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;

import com.backendboard.domain.post.dto.PostSliceResponse;
import com.backendboard.domain.post.dto.QPostSliceResponse;
import com.backendboard.domain.post.entity.QPost;
import com.backendboard.domain.user.entity.QUser;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class PostQueryRepository {
private final JPAQueryFactory queryFactory;

public Slice<PostSliceResponse> findPostSliceResponse(boolean deleted, Pageable pageable) {
QPost post = QPost.post;
QUser user = QUser.user;
boolean hasNext = false;
List<OrderSpecifier<?>> orderSpecifiers = getOrderSpecifiers(pageable, post);

List<PostSliceResponse> content = queryFactory
.select(new QPostSliceResponse(
post.id,
user.nickname,
post.title,
post.content,
post.likeCount,
post.viewCount,
post.createdDate,
post.lastModifiedDate
))
.from(post)
.join(user).on(post.userId.eq(user.id))
.where(post.deleted.eq(deleted))
.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]))
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

if (content.size() > pageable.getPageSize()) {
content.remove(pageable.getPageSize());
hasNext = true;
}
return new SliceImpl<>(content, pageable, hasNext);
}

private List<OrderSpecifier<?>> getOrderSpecifiers(Pageable pageable, QPost post) {
List<OrderSpecifier<?>> orders = new ArrayList<>();

for (Sort.Order order : pageable.getSort()) {
PathBuilder<?> entityPath = new PathBuilder<>(post.getType(), post.getMetadata());
orders.add(
new OrderSpecifier(order.isAscending() ? Order.ASC : Order.DESC, entityPath.get(order.getProperty()))
);
}
return orders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ public interface ViewCountRedisRepository {
Map<Object, Object> getEntries();

void incrementCount(String postId);

Long getIncrementCount(String postId);
}
Loading