우리는 스터디 게시글을 조회할때 페이지네이션을 사용하여 10개씩 조회한다
해당 화면을 보는 유저(인가된 유저)가 이 화면을 보는지 안보는지 확인하려고 기존에는 isBookmarked라는 api를 따로 사용했다


@Override
public UserId resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
try {
String jwtToken = webRequest.getHeader(JwtProperties.ACCESS_HEADER_STRING);
if (jwtToken == null) {
return new UserId(null);
}
jwtToken = jwtToken.replace(JwtProperties.TOKEN_PREFIX, "");
Long id = (JWT.require(Algorithm.HMAC512(SECRET)).build().verify(jwtToken).getClaim("id")).asLong();
return new UserId(id);
} catch (Exception e) {
return null;
}
}
우리는 리졸버에서 인가를 처리한다 그래서 비회원을 위해서 jwt가 없더라도 null을 보내는 쪽으로 하였다
@Getter
public class PostDataByInquiry {
private Long postId;
private MajorType major;
private String title;
private LocalDate studyStartDate;
private LocalDate studyEndDate;
private LocalDateTime createdDate;
private Integer studyPerson;
private GenderType filteredGender;
private Integer penalty;
private String penaltyWay;
private Integer remainingSeat;
private boolean close;
private boolean isBookmarked; //추가
private UserData userData;
@Builder
public PostDataByInquiry(Long postId, MajorType major, String title, LocalDate studyStartDate, LocalDate studyEndDate, LocalDateTime createdDate, Integer studyPerson, GenderType filteredGender, Integer penalty, String penaltyWay, Integer remainingSeat, boolean close, boolean isBookmarked, UserData userData) {
this.postId = postId;
this.major = major;
this.title = title;
this.studyStartDate = studyStartDate;
this.studyEndDate = studyEndDate;
this.createdDate = createdDate;
this.studyPerson = studyPerson;
this.filteredGender = filteredGender;
this.penalty = penalty;
this.penaltyWay = penaltyWay;
this.remainingSeat = remainingSeat;
this.close = close;
this.isBookmarked = isBookmarked;
this.userData = userData;
}
}
이렇게 isBookmarked를 dto에 추가 하였다
@Override
public List<PostDataByInquiry> findByInquiry(final InquiryRequest inquiryRequest, final Pageable pageable, Long userId) {
JPAQuery<PostDataByInquiry> data = jpaQueryFactory
.select(Projections.constructor(PostDataByInquiry.class,
studyPostEntity.id.as("postId"), studyPostEntity.major, studyPostEntity.title, studyPostEntity.studyStartDate, studyPostEntity.studyEndDate,
studyPostEntity.createdDate, studyPostEntity.studyPerson, studyPostEntity.filteredGender,
studyPostEntity.penalty, studyPostEntity.penaltyWay, studyPostEntity.remainingSeat, studyPostEntity.close,
bookmarkPredicate(userId), //여기서 isBookmarked 값 지정해준다
Projections.constructor(
UserData.class,
userEntity.id, userEntity.major, userEntity.nickname, userEntity.imageUrl
)
))
.from(studyPostEntity)
.leftJoin(userEntity).on(studyPostEntity.postedUserId.eq(userEntity.id))
.where(textEq(inquiryRequest.getInquiryText()).or(majorEq(inquiryRequest.getInquiryText(), inquiryRequest.isTitleAndMajor())))
.orderBy(hotPredicate(inquiryRequest), studyPostEntity.createdDate.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1);
if (userId != null) {
data.leftJoin(bookmarkEntity).on(studyPostEntity.id.eq(bookmarkEntity.postId).and(bookmarkEntity.userId.eq(userId)));
} //유저 아이디가 있으면 그떄서야 bookmark와 join함
return data.fetch();
}
private BooleanExpression bookmarkPredicate(Long userId) {
if (userId != null) {
return Expressions.booleanTemplate("{0} = {1}", bookmarkEntity.userId, userId);
}
return Expressions.asBoolean(Expressions.constant(false));
}
유저 아이디가 있으면 그떄서야 bookmark와 join한다
bookmarkPredicate 메서드는 userId를 인자로 받아서 BooleanExpression을 반환한다 QueryDSL에서 조건문을 동적으로 생성했다
QueryDSL에서는 BooleanExpression이라는 타입을 통해 where 절의 조건을 표현하는데 이 메서드는 특정 게시물이 사용자에 의해 북마크되었는지 여부를 판단하는 조건을 생성하는 역할을 한다
코드를 보면 현재 조회하고 있는 북마크의 userId가 인자로 받은 userId와 같은지를 판단하는 조건을 생성한다
만약 비회원이 조회한다면(userId가 null인 경우) Expressions.asBoolean(Expressions.constant(false))를 통해 항상 false를 반환하는 BooleanExpression을 반환, 로그인하지 않은 상태에서는 모든 게시물이 북마크되지 않았다고 판단하므로 항상 false를 반환함
브라우저 캐싱, 네트워크 상태 등으로 매번 다른 결과가 나와서 정확하게 측정할 수 없지만 수정전 평균적으로 
530ms 정도 나오던게

평균적으로 400ms 정도로 나온다