티스토리 뷰

게시글 북마크 기능은 다 만들었고, 이제 유저(멤버)의 북마크 페이지나 마이 페이지에서 북마크한 목록을 조회하는 기능을 구현할 것이다.

 


Dto

MyBookamrkDto

package com.example.MyFreshmanCommunity.dto;

import com.example.MyFreshmanCommunity.entity.Article;
import com.example.MyFreshmanCommunity.entity.Major;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MyBookmarkDto {
    private Long id;
    private String title;
    private String content;
    private LocalDateTime createDate;
    private LoginResponseDto member;
    private Major major;

    public static MyBookmarkDto createMyBookmarkDto(Article article){
        return new MyBookmarkDto(
                article.getId(),
                article.getTitle(),
                article.getContent(),
                article.getCreateDate(),
                LoginResponseDto.createLoginDto(article.getMember()),
                article.getMajor()
        );
    }
}

 

사실 ArticleResponseDto랑 다른 게 없지만 구분하는 게 더 이해하기 편할 것 같아 구분하여 클래스를 만들어주었다.

유저가 북마크한 게시글의 목록들이 createBookmarkDto메서드를 통해 MyBookmarkDto에 담겨 반환될 것이다.

 


BookmarkRepository

List<Bookmark> findAllByMember(Member member);

 


Service

MemberService

❗️❗️❗️틀린코드❗️❗️❗️

    public List<MyBookmarkDto> myBookmark(HttpSession session) {
        Member member = (Member) session.getAttribute("member");
        List<Article> bookmarks = articleRepository.findAllByIdIn(bookmarkRepository.findAllArticleIdByMember(member));
        List<MyBookmarkDto> dtos = new ArrayList<MyBookmarkDto>();
        for(Article a: bookmarks) {
            MyBookmarkDto dto = MyBookmarkDto.createBookmarkDto(a);
            dtos.add(dto);
        }
        return dtos;
    }

 

처음에는 되게 복잡하게 생각했다.

findAllArticleIdByMember 메서드를 호출하여 회원의 북마크된 게시물의 ID 목록을 가져온 다음, 이 ID 목록을 사용하여 findAllByIdIn 메서드를 호출하여 해당 ID를 가진 게시물을 가져왔다. 그런 다음 가져온 각 게시물을 MyBookmarkDto로 변환하여 리스트에 추가해주었다. 그러나 이렇게 하면 두 번의 데이터베이스 쿼리를 실행하므로 데이터베이스 부하가 발생할 뿐만 아니라, postman으로 돌려보았을 때 "Specified result type [java.lang.Long] did not match Query selection type [com.example.MyFreshmanCommunity.entity.Bookmark] - multiple selections: use Tuple or array" 라는 오류 메시지가 나타났다. 찾아보니 이 오류는 여러 선택 항목이 있는 쿼리에서 단일 타입을 반환하려고 할 때 발생하는데, 따라서 여러 개의 엔티티나 다른 객체를 선택한 경우에는 해당 결과를 Tuple이나 배열로 반환해야 한다.

 

❗️❗️❗️두번째 틀린코드❗️❗️❗️

public List<MyBookmarkDto> myBookmark(HttpSession session) {
    Member member = (Member) session.getAttribute("member");
    
    // Member로부터 Article ID 목록 가져오기
    List<Tuple> articleTuples = bookmarkRepository.findAllArticleIdByMember(member);
    List<Long> articleIds = new ArrayList<>();
    for (Tuple tuple : articleTuples) {
        // Tuple에서 Article ID를 가져와서 List<Long>에 추가
        Long articleId = (Long) tuple.get(0);
        articleIds.add(articleId);
    }
    
    // Article ID 목록을 사용하여 Article 목록 조회
    List<Article> bookmarks = articleRepository.findAllByIdIn(articleIds);
    
    // Article 목록을 MyBookmarkDto로 변환
    List<MyBookmarkDto> dtos = new ArrayList<>();
    for (Article a: bookmarks) {
        MyBookmarkDto dto = MyBookmarkDto.createBookmarkDto(a);
        dtos.add(dto);
    }
    
    return dtos;
}

 

따라서 투플을 이용한 코드로 바꿔보았지만,,, 이번엔 Invoked method is not a property accessor라는 오류가 떴다. 이 오류는 스프링 데이터 프로젝션에서 사용되는 메서드가 올바른 방식으로 호출되지 않았을 때 발생한다.

 

이를통해 내가 생각했던 방식은 아예 잘못되었음을 깨닫고, 다시 처음부터 생각해보았다. ㅎㅎ

 

🌟🌟최종코드🌟🌟

    public List<MyBookmarkDto> myBookmark(HttpSession session) {
        Member member = (Member) session.getAttribute("member");
        return bookmarkRepository.findAllByMember(member).stream()
                .map(bookmark -> MyBookmarkDto.createMyBookmarkDto(bookmark.getArticle()))
                .collect(Collectors.toList());
    }

 

두 번의 데이터베이스 쿼리를 호출할 필요 없이, findAllByMember 메서드를 사용하여 회원의 북마크된 항목을 한 번에 가져오고, 그런 다음 각 북마크 항목을 MyBookmarkDto로 매핑하여 최종 결과를 얻으면 된다. 

이 방법은 스트림 및 람다 표현식을 사용하여 코드를 간결하게 유지할 수 있을 뿐만 아니라, 하나의 쿼리만 사용하므로 데이터베이스 부하가 줄어들게 된다.

 


Controller

MemberApiController

    //나의 북마크
    @GetMapping("/user/bookmark")
    public ResponseEntity<List<MyBookmarkDto>> myBookmark(HttpServletRequest request) {
        HttpSession session = request.getSession();
        List<MyBookmarkDto> bookmarks = memberService.myBookmark(session);
        return ResponseEntity.status(HttpStatus.OK).body(bookmarks);
    }

 

유저가 여러개의 게시글을 북마크할 수 있으므로 반환타입을 <List<MyBookmarkDto>>로 해주었다. 또한 유저마다의 북마크 목록을 가져오기 위해 현재 로그인되어있는 멤버의 세션을 가져와주었다.


postman을 통한 데이터 확인 

북마크 목록 조회

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함