Skip to content

Commit

Permalink
[FEAT] 게시글 조회시 사용자가 찜한 게시글인지 확인 가능한 값 추가 (#158)
Browse files Browse the repository at this point in the history
* fix: 메인 페이지 게시글 페이지네이션시 일치 하지 않던 totalElements값 수정

* feat: custom findById 제거, @repository 제거, extends를 통해 PostRepositoryCustom 사용

* refactor: postCustomRepository대신 postRepository 사용

* feat: session이 비어있을 떄 null 반환하는 함수 추가

* feat: isLiked 필드 추가

* feat: memberId를 기준으로 좋아요한 게시글에 대한 isLiked상태 설정하여 반환

* feat: isLiked 기본값 false로 설정

* feat: 마이페이지 내가 작성한 게시글 조회시 isLiked 값 설정

* feat: 마이페이지 찜한 게시글 목록 조회시 isLiked 필드 true로 설정

* feat: 단일 게시글 조회시 isLiked 설정하여 반환

* refactor: Optional클래스 적용

* feat: Early Return 패턴 적용

* feat: SessionError 비즈니스 예외 처리 적용

* rename: Exception 이름 변경

* remove: 사용안하는 SessionErrorCode 제거

* refactor: SessionUtils validate 함수 대신 직접 Long형으로 변환

* refactor: getMemberIdOrNull 대신 getMemberId 사용

* refactor: SessionUtils catch 예외 NullpointerException, NumberFormatException 지정

* refactor: NumberFormatException 제거
  • Loading branch information
injae-348 authored Sep 22, 2024
1 parent 1b71a79 commit 41d56a2
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import econo.buddybridge.chat.chatmessage.dto.ChatMessageReqDto;
import econo.buddybridge.chat.chatmessage.dto.ChatMessageResDto;
import econo.buddybridge.chat.chatmessage.service.ChatMessageService;
import econo.buddybridge.utils.session.SessionUtils;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequiredArgsConstructor
public class ChatMessageController {
Expand All @@ -27,7 +23,7 @@ public ChatMessageResDto sendMessage(
@Header("simpSessionAttributes") Map<String, Object> attributes
) {
Object memberIdObject = attributes.get("memberId");
Long senderId = SessionUtils.validateMemberId(memberIdObject);
Long senderId = Long.parseLong(memberIdObject.toString());
return chatMessageService.save(senderId, chatMessageReqDto, matchingId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ public ApiResponse<ApiResponse.CustomBody<PostCustomPage>> getAllPosts(
@RequestParam(defaultValue = "desc", required = false) String sort,
@RequestParam(value = "post-status", required = false) PostStatus postStatus,
@RequestParam(value = "disability-type", required = false) DisabilityType disabilityType,
@RequestParam(value = "assistance-type", required = false) AssistanceType assistanceType
@RequestParam(value = "assistance-type", required = false) AssistanceType assistanceType,
HttpServletRequest request
) {
PostCustomPage posts = postService.getPosts(page, size, sort, postType, postStatus, disabilityType, assistanceType);
Long memberId = SessionUtils.getMemberId(request);
PostCustomPage posts = postService.getPosts(memberId, page, size, sort, postType, postStatus, disabilityType, assistanceType);
return ApiResponseGenerator.success(posts, HttpStatus.OK);
}

Expand All @@ -75,9 +77,11 @@ public ApiResponse<ApiResponse.CustomBody<Long>> createPost(
@GetMapping("/{post-id}")
@AllowAnonymous
public ApiResponse<ApiResponse.CustomBody<PostResDto>> getPost(
@PathVariable("post-id") Long postId
@PathVariable("post-id") Long postId,
HttpServletRequest request
) {
PostResDto postResDto = postService.findPost(postId);
Long memberId = SessionUtils.getMemberId(request);
PostResDto postResDto = postService.findPost(memberId, postId);
return ApiResponseGenerator.success(postResDto, HttpStatus.OK);
}

Expand Down
37 changes: 28 additions & 9 deletions src/main/java/econo/buddybridge/post/dto/PostResDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@

import econo.buddybridge.member.dto.MemberResDto;
import econo.buddybridge.member.entity.DisabilityType;
import econo.buddybridge.post.entity.AssistanceType;
import econo.buddybridge.post.entity.District;
import econo.buddybridge.post.entity.Post;
import econo.buddybridge.post.entity.PostStatus;
import econo.buddybridge.post.entity.PostType;
import econo.buddybridge.post.entity.ScheduleType;
import java.time.LocalDateTime;
import econo.buddybridge.post.entity.*;
import lombok.Builder;

import java.time.LocalDateTime;

@Builder
public record PostResDto(
Long id,
Expand All @@ -27,7 +23,8 @@ public record PostResDto(
LocalDateTime createdAt,
LocalDateTime modifiedAt,
PostStatus postStatus,
DisabilityType disabilityType
DisabilityType disabilityType,
Boolean isLiked
) {

public PostResDto(Post post) {
Expand All @@ -46,7 +43,29 @@ public PostResDto(Post post) {
post.getCreatedAt(),
post.getModifiedAt(),
post.getPostStatus(),
post.getDisabilityType()
post.getDisabilityType(),
post.getIsLiked()
);
}

public PostResDto(Post post, Boolean isLiked) {
this(
post.getId(),
new MemberResDto(post.getAuthor()),
post.getTitle(),
post.getAssistanceType(),
post.getSchedule().getStartTime(),
post.getSchedule().getEndTime(),
post.getSchedule().getScheduleType(),
post.getSchedule().getScheduleDetails(),
post.getDistrict(),
post.getContent(),
post.getPostType(),
post.getCreatedAt(),
post.getModifiedAt(),
post.getPostStatus(),
post.getDisabilityType(),
isLiked
);
}
}
2 changes: 2 additions & 0 deletions src/main/java/econo/buddybridge/post/entity/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public class Post extends BaseEntity {
@OneToMany(mappedBy = "post", orphanRemoval = true, cascade = CascadeType.ALL)
private final List<Comment> comments = new ArrayList<>();

private Boolean isLiked = false;

public void changeStatus(PostStatus status){ // 상태 변경
this.postStatus = status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public Optional<PostLike> findByPostIdAndMemberId(Long postId, Long memberId) {
@Override
public PostCustomPage findPostsByLikes(Long memberId, Integer page, Integer size, String sort, PostType postType) {

// Todo: 쿼리 최적화 고려
List<PostResDto> content = queryFactory
.select(postLike.post)
.from(postLike)
Expand All @@ -42,7 +41,7 @@ public PostCustomPage findPostsByLikes(Long memberId, Integer page, Integer size
.orderBy(buildOrderSpecifier(sort))
.fetch()
.stream()
.map(PostResDto::new)
.map(post -> new PostResDto(post,true))
.toList();

Long totalElements = queryFactory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
package econo.buddybridge.post.repository;

import econo.buddybridge.post.entity.Post;
import lombok.NonNull;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface PostRepository extends JpaRepository<Post, Long> {

@NonNull
@EntityGraph(attributePaths = {"author"})
Optional<Post> findById(Long postId);
public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryCustom {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

import econo.buddybridge.member.entity.DisabilityType;
import econo.buddybridge.post.dto.PostCustomPage;
import econo.buddybridge.post.dto.PostResDto;
import econo.buddybridge.post.entity.AssistanceType;
import econo.buddybridge.post.entity.PostStatus;
import econo.buddybridge.post.entity.PostType;
import org.springframework.stereotype.Repository;

@Repository
public interface PostRepositoryCustom {

PostCustomPage findPosts(Integer page, Integer size, String sort, PostType postType,
PostResDto findByMemberIdAndPostId(Long memberId, Long postId);

PostCustomPage findPosts(Long memberId, Integer page, Integer size, String sort, PostType postType,
PostStatus postStatus, DisabilityType disabilityType, AssistanceType assistanceType);

PostCustomPage findPostsMyPage(Long memberId, Integer page, Integer size, String sort, PostType postType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,82 @@
import econo.buddybridge.member.entity.DisabilityType;
import econo.buddybridge.post.dto.PostCustomPage;
import econo.buddybridge.post.dto.PostResDto;
import econo.buddybridge.post.entity.AssistanceType;
import econo.buddybridge.post.entity.District;
import econo.buddybridge.post.entity.PostStatus;
import econo.buddybridge.post.entity.PostType;
import econo.buddybridge.post.entity.*;
import econo.buddybridge.post.exception.PostInvalidSortValueException;
import econo.buddybridge.post.exception.PostNotFoundException;
import lombok.RequiredArgsConstructor;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static econo.buddybridge.post.entity.QPost.post;
import static econo.buddybridge.post.entity.QPostLike.postLike;

@RequiredArgsConstructor
public class PostRepositoryImpl implements PostRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Override
public PostCustomPage findPosts(Integer page, Integer size, String sort, PostType postType,
public PostResDto findByMemberIdAndPostId(Long memberId, Long postId) {
Post content = queryFactory
.selectFrom(post)
.where(post.id.eq(postId))
.fetchOne();

if (content == null) {
throw PostNotFoundException.EXCEPTION;
}

Boolean isLiked = memberId != null && queryFactory
.select(postLike.post.id)
.from(postLike)
.where(postLike.member.id.eq(memberId), postLike.post.id.eq(postId))
.fetchOne() != null;

return new PostResDto(content, isLiked);
}

@Override
public PostCustomPage findPosts(Long memberId, Integer page, Integer size, String sort, PostType postType,
PostStatus postStatus, DisabilityType disabilityType, AssistanceType assistanceType) {
List<PostResDto> postResDtos = queryFactory

List<Post> posts = queryFactory
.selectFrom(post)
.where(buildPostStatusExpression(postStatus), buildPostTypeExpression(postType),
buildPostDisabilityTypeExpression(disabilityType), buildPostAssistanceTypeExpression(assistanceType))
.offset((long) page * size)
.limit(size)
.orderBy(buildOrderSpecifier(sort))
.fetch()
.stream()
.map(PostResDto::new)
.toList();
.fetch();

List<PostResDto> content = getPostResDtos(memberId, posts);

Long totalElements = queryFactory
.select(post.count())
.from(post)
.where(buildPostStatusExpression(postStatus), buildPostTypeExpression(postType))
.where(buildPostStatusExpression(postStatus), buildPostTypeExpression(postType),
buildPostDisabilityTypeExpression(disabilityType), buildPostAssistanceTypeExpression(assistanceType))
.fetchOne();

// content, totalElements, last
return new PostCustomPage(postResDtos, totalElements, postResDtos.size() < size);
return new PostCustomPage(content, totalElements, content.size() < size);
}

@Override
public PostCustomPage findPostsMyPage(Long memberId, Integer page, Integer size, String sort, PostType postType) {

List<PostResDto> content = queryFactory
List<Post> posts = queryFactory
.selectFrom(post)
.where(buildMemberIdExpression(memberId), buildPostTypeExpression(postType))
.offset((long) page * size)
.limit(size)
.orderBy(buildOrderSpecifier(sort))
.fetch()
.stream()
.map(PostResDto::new)
.toList();
.fetch();

List<PostResDto> content = getPostResDtos(memberId, posts);

Long totalElements = queryFactory
.select(post.count())
Expand All @@ -70,6 +92,28 @@ public PostCustomPage findPostsMyPage(Long memberId, Integer page, Integer size,
return new PostCustomPage(content, totalElements, content.size() < size);
}

private List<PostResDto> getPostResDtos(Long memberId, List<Post> posts) {
if (memberId != null) {
List<Long> postIds = posts.stream().map(Post::getId).collect(Collectors.toList());
Set<Long> postLikedIds = new HashSet<>(
queryFactory
.select(postLike.post.id)
.from(postLike)
.where(postLike.member.id.eq(memberId), postLike.post.id.in(postIds))
.fetch()
);

return posts.stream()
.map(post -> new PostResDto(post, postLikedIds.contains(post.getId())))
.toList();
}

return posts.stream()
.map(PostResDto::new)
.toList();

}

private BooleanExpression buildMemberIdExpression(Long memberId) {
return memberId == null ? null : post.author.id.eq(memberId);
}
Expand Down
15 changes: 6 additions & 9 deletions src/main/java/econo/buddybridge/post/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import econo.buddybridge.post.exception.PostNotFoundException;
import econo.buddybridge.post.exception.PostUpdateNotAllowedException;
import econo.buddybridge.post.repository.PostRepository;
import econo.buddybridge.post.repository.PostRepositoryCustom;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -25,7 +24,6 @@
public class PostService {

private final PostRepository postRepository;
private final PostRepositoryCustom postRepositoryCustom;
private final MemberService memberService;

// 존재하는 포스트인지 확인
Expand All @@ -36,20 +34,19 @@ public Post findPostByIdOrThrow(Long postId) {
}

@Transactional(readOnly = true) // 단일 게시글 조회
public PostResDto findPost(Long postId) {
Post post = findPostByIdOrThrow(postId);
return new PostResDto(post);
public PostResDto findPost(Long memberId, Long postId) {
return postRepository.findByMemberIdAndPostId(memberId, postId);
}

@Transactional(readOnly = true) // 내가 작성한 게시글 조회
public PostCustomPage getPostsMyPage(Long memberId, Integer page, Integer size, String sort, PostType postType) {
return postRepositoryCustom.findPostsMyPage(memberId, page - 1, size, sort, postType);
return postRepository.findPostsMyPage(memberId, page - 1, size, sort, postType);
}

@Transactional(readOnly = true)
public PostCustomPage getPosts(Integer page, Integer size, String sort, PostType postType, PostStatus postStatus,
@Transactional(readOnly = true) // 전체 게시글 조회
public PostCustomPage getPosts(Long memberId, Integer page, Integer size, String sort, PostType postType, PostStatus postStatus,
DisabilityType disabilityType, AssistanceType assistanceType) {
return postRepositoryCustom.findPosts(page - 1, size, sort, postType, postStatus, disabilityType, assistanceType);
return postRepository.findPosts(memberId, page - 1, size, sort, postType, postStatus, disabilityType, assistanceType);
}

// 검증 과정 필요성 고려
Expand Down
17 changes: 7 additions & 10 deletions src/main/java/econo/buddybridge/utils/session/SessionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@

import jakarta.servlet.http.HttpServletRequest;

import java.util.Optional;

public class SessionUtils {

public static Long getMemberId(HttpServletRequest request) {
return Long.parseLong(request.getSession().getAttribute("memberId").toString());
}

public static Long validateMemberId(Object memberId) {
if(memberId instanceof Integer) {
return ((Integer) memberId).longValue();
} else if(memberId instanceof Long) {
return (Long) memberId;
} else {
throw new IllegalArgumentException("적절하지 않은 memberId 입니다.");
try {
return Optional.of(Long.parseLong(request.getSession().getAttribute("memberId").toString())).orElse(null);
} catch (NullPointerException e) {
return null;
}
}

}

0 comments on commit 41d56a2

Please sign in to comment.