1. 개요
추천 게시글 기능이다. 우리 팀은 회의 결과 회원가입에서 선호 종목을 받고, 다음 규칙에 따라 게시글을 추천하기로 했다
- 선호 종목이 있는 회원은 선호 종목 내에서 무작위 순서로 게시글 조회
- 선호 종목이 없거나 로그인하지 않은 회원은 모든 게시글에서 무작위 순서로 게시글 조회
- 추천 게시글은 총 8개 조회
위 규칙에 맞춰 구현해보자.
2. ERD
회원에 선호 종목을 일대다 관계로 잇고, 종목을 받았다.
3. 구현
3-1 Service
public <T extends SimplePostDto> List<T> findRecommendPost(CustomUserDetails principal) {
//토큰에서
Member member;
if (principal == null) {
member = null;
} else {
member=memberRepository.findByUsername(principal.getUsername())
.orElseThrow(()->
new NoAuthorizationException("추천 글 조회 실패: 접근 권한이 없습니다.")
);
if (member.getStatus() != MemberStatus.active) {
member = null;
}
}
List<SimplePostQueryDto> recommendPost = postRepository.findRecommendPost(member);
return recommendPost.stream()
.map(p -> convertToTransDto(p))
.map(r -> (T) r)
.collect(Collectors.toList());
}
토큰을 받아 회원의 로그인 여부, 상태 등을 확인하고 repository에서 게시글을 조회하여 반환하는 코드이다. 프론트에서는 게시글 검색, 조회에서 사용했던 것과 같은 컴포넌트를 사용하므로 같은 방식으로 가공하여 반환한다.
3-2 Repository
@Override
public List<SimplePostQueryDto> findRecommendPost(Member member) {
List<FavoriteSport> favoriteSports = member!=null?member.getFavoriteSports(): Collections.emptyList();
List<SimplePostQueryDto> result = queryFactory.select(new QSimplePostQueryDto(
post.id.as("postId"),
meeting.meetingType,
meeting.status,
meeting.gameType,
meeting.location,
post.title,
meeting.meetingDateTime,
meeting.meetingDays,
meeting.meetingMemberNum,
meeting.meetingDeadline,
bookmark.isNotNull().as("isBookmarked")
))
.from(post)
.leftJoin(post.meeting, meeting)
.leftJoin(bookmark).on(bookmark.post.eq(post), hasMember(member))
.where(
post.isDelete.isFalse(), meeting.status.eq("RECRUIT"),
favoriteSportsEq(favoriteSports)
)
.orderBy(Expressions.numberTemplate(Double.class, "function('random')").asc())
.limit(8)
.fetch();
return result;
}
게시글 조회 때와 같은 데이터를 불러오되, 선호 종목을 확인하고, postgresql의 random() 함수를 이용하여 정렬한다. 그 후 8개를 위에서부터 뽑아 반환한다.
private BooleanBuilder favoriteSportsEq(List<FavoriteSport> favoriteSports) {
if (favoriteSports.isEmpty()) {
return null;
}
BooleanBuilder booleanBuilder = new BooleanBuilder();
for (FavoriteSport favoriteSport : favoriteSports) {
booleanBuilder.or(meeting.gameType.eq(favoriteSport.getGameType()));
}
return booleanBuilder;
}
선호 종목이 없을 경우 모든 게시글 중 뽑아야 하므로 null을 반환, 있을 경우 booleanBuilder를 사용하여 조건을 추가한 후 반환한다.
3-3 Controller
@GetMapping("/recommend")
public <T extends SimplePostDto> ApiResponse<List<T>> findRecommendPost(
@AuthenticationPrincipal CustomUserDetails principal) {
return ApiResponse.createSuccess(postService.findRecommendPost(principal));
}
토큰을 받아 이를 서비스에 넘겨 선호 종목을 필터터링하고, 서비스 계층에서 받은 리스트를 그대로 반환하면 된다.
4. 후기
다음 릴리즈 시간이 다가와서 쉬운 것 먼저 처리하고자 이를 먼저 구현했다. 다음은 시간에 따른 모임 정보 처리를 할 생각이다.
'Proj > 구구모' 카테고리의 다른 글
댓글 알림 구현(feat. sse) (0) | 2024.06.25 |
---|---|
EC2 한국 시간으로 변경 (0) | 2024.06.08 |
스프링 스케쥴러를 이용한 게시글 마감 처리 (0) | 2024.06.07 |
댓글 및 대댓글 기능 구현 (0) | 2024.05.29 |
AWS EC2를 이용한 배포 (0) | 2024.05.23 |