Skip to content

Commit

Permalink
feat: 사용자 알림 목록 조회 오프셋 기반 페이지네이션 추가
Browse files Browse the repository at this point in the history
* refactor: Cursor 네이밍 추가

* refactor: 조회하는 쿼리와 Read를 True로 변경하는 쿼리 분리

* feat: 오프셋기반 조회 dto 추가

* feat: 오프셋 기반 사용자 알림 목록 조회 구현

* test: 오프셋 기반 사용자 알림 조회 컨트롤러 테스트 구현

* fix: createAt -> createdAt

* fix: replay -> reply

* docs: API 문서 최신화
  • Loading branch information
jjuny0310 authored Jan 9, 2024
1 parent baf7600 commit 046272b
Show file tree
Hide file tree
Showing 16 changed files with 405 additions and 110 deletions.
5 changes: 4 additions & 1 deletion src/docs/asciidoc/notification.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
== 알림

=== 알림 목록 조회
=== 사용자 알림 목록 조회(Offset)
operation::notification/get-notifications-by-offset[snippets='http-request,http-response,cookie,response-fields']

=== 사용자 알림 목록 조회(Cursor)
operation::notification/get-notifications-by-cursor[snippets='http-request,http-response,cookie,response-fields']

=== 새로운 알림 확인
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ private void publishNotificationEventFromPostReply(Post post) {
.message(String.format(NotificationMessage.POST_REPLY_MESSAGE.getMessage(), post.getTitle()))
.contentId(post.getId())
.serviceType(ServiceType.POST)
.notificationType(NotificationType.POST_REPLAY)
.notificationType(NotificationType.POST_REPLY)
.build();
applicationEventPublisher.publishEvent(notificationEvent);
}
Expand All @@ -237,7 +237,7 @@ private void publishNotificationEventFromCommentReply(Post post, Comment comment
.message(String.format(NotificationMessage.COMMENT_REPLY_MESSAGE.getMessage(), post.getTitle()))
.contentId(post.getId())
.serviceType(ServiceType.POST)
.notificationType(NotificationType.COMMENT_REPLAY)
.notificationType(NotificationType.COMMENT_REPLY)
.build();
applicationEventPublisher.publishEvent(notificationEvent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.ssafy.ssafsound.domain.auth.dto.AuthenticatedMember;
import com.ssafy.ssafsound.domain.auth.validator.Authentication;
import com.ssafy.ssafsound.domain.notification.dto.GetCheckNotificationResDto;
import com.ssafy.ssafsound.domain.notification.dto.GetNotificationReqDto;
import com.ssafy.ssafsound.domain.notification.dto.GetNotificationResDto;
import com.ssafy.ssafsound.domain.notification.dto.*;
import com.ssafy.ssafsound.domain.notification.service.NotificationService;
import com.ssafy.ssafsound.global.common.response.EnvelopeResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,11 +21,20 @@
public class NotificationController {
private final NotificationService notificationService;

@GetMapping()
public EnvelopeResponse<GetNotificationResDto> getNotificationsByCursor(@Authentication AuthenticatedMember authenticatedMember,
@Valid @ModelAttribute GetNotificationReqDto getNotificationReqDto) {
return EnvelopeResponse.<GetNotificationResDto>builder()
.data(notificationService.getNotifications(authenticatedMember, getNotificationReqDto))
@GetMapping("/cursor")
public EnvelopeResponse<GetNotificationCursorResDto> getNotificationsByCursor(@Authentication AuthenticatedMember authenticatedMember,
@Valid @ModelAttribute GetNotificationCursorReqDto getNotificationCursorReqDto) {
return EnvelopeResponse.<GetNotificationCursorResDto>builder()
.data(notificationService.getNotificationsByCursor(authenticatedMember, getNotificationCursorReqDto))
.build();
}

@GetMapping("/offset")
public EnvelopeResponse<GetNotificationOffsetResDto> getNotificationsByOffset(@Authentication AuthenticatedMember authenticatedMember,
@Valid @ModelAttribute GetNotificationOffsetReqDto getNotificationOffsetReqDto) {

return EnvelopeResponse.<GetNotificationOffsetResDto>builder()
.data(notificationService.getNotificationsByOffset(authenticatedMember, getNotificationOffsetReqDto))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
@Getter
public enum NotificationType {
SYSTEM(1, "SYSTEM"),
POST_REPLAY(2, "POST_REPLAY"),
COMMENT_REPLAY(3, "COMMENT_REPLAY"),
POST_REPLY(2, "POST_REPLY"),
COMMENT_REPLY(3, "COMMENT_REPLY"),
RECRUIT(4, "RECRUIT");

private final Integer id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GetNotificationReqDto {
public class GetNotificationCursorReqDto {
@Builder.Default
private Long cursor = -1L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

@Getter
@Builder
public class GetNotificationResDto {
public class GetNotificationCursorResDto {
private List<GetNotificationElement> notifications;
private Long cursor;

public static GetNotificationResDto of(List<Notification> notifications, Integer pageSize) {
public static GetNotificationCursorResDto of(List<Notification> notifications, Integer pageSize) {
int size = notifications.size();
boolean hasNext = size == pageSize + 1;

return GetNotificationResDto.builder()
return GetNotificationCursorResDto.builder()
.notifications((hasNext ? notifications.subList(0, size - 1) : notifications)
.stream()
.map(GetNotificationElement::from)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class GetNotificationElement {
private Boolean read;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createAt;
private LocalDateTime createdAt;

public static GetNotificationElement from(Notification notification) {
return GetNotificationElement.builder()
Expand All @@ -30,7 +30,7 @@ public static GetNotificationElement from(Notification notification) {
.serviceType(notification.getServiceType())
.notificationType(notification.getNotificationType())
.read(notification.getRead())
.createAt(notification.getCreatedAt())
.createdAt(notification.getCreatedAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ssafy.ssafsound.domain.notification.dto;

import lombok.*;
import lombok.experimental.SuperBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import javax.validation.constraints.Min;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GetNotificationOffsetReqDto {
@Builder.Default
private Integer page = 1;

@Min(value = 10, message = "Size가 너무 작습니다.")
@Builder.Default
private Integer size = 10;

public void setPage(Integer page) {
if (page <= 0) {
this.page = 1;
return;
}
this.page = page;
}

public PageRequest toPageRequest() {
return PageRequest.of(this.page - 1, this.size, Sort.Direction.DESC, "id");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.ssafy.ssafsound.domain.notification.dto;

import com.ssafy.ssafsound.domain.notification.domain.Notification;
import lombok.Builder;
import lombok.Getter;
import org.springframework.data.domain.Page;

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

@Getter
@Builder
public class GetNotificationOffsetResDto {
private List<GetNotificationElement> notifications;
private Integer currentPage;
private Integer totalPageCount;

public static GetNotificationOffsetResDto of(Page<Notification> notifications) {
return GetNotificationOffsetResDto.builder()
.notifications(notifications.getContent().stream()
.map(GetNotificationElement::from)
.collect(Collectors.toList()))
.currentPage(notifications.getNumber() + 1)
.totalPageCount(notifications.getTotalPages())
.build();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

public interface NotificationCustomRepository {

List<Notification> findAllByOwnerAndReadTrue(Long ownerId, Long cursor, Integer size);
List<Notification> findAllByOwnerId(Long ownerId, Long cursor, Integer size);
void updateReadTrueByOwnerId(Long ownerId);

Boolean existsNewNotification(Long ownerId);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.ssafy.ssafsound.domain.notification.repository;

import com.ssafy.ssafsound.domain.notification.domain.Notification;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface NotificationRepository extends MongoRepository<Notification, String>, NotificationCustomRepository {
Page<Notification> findAllByOwnerId(Long ownerId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class NotificationRepositoryImpl implements NotificationCustomRepository
private final MongoOperations mongoOperations;

@Override
public List<Notification> findAllByOwnerAndReadTrue(Long ownerId, Long cursor, Integer size) {
public List<Notification> findAllByOwnerId(Long ownerId, Long cursor, Integer size) {
Criteria criteria = Criteria.where("ownerId").is(ownerId);
if (cursor != -1) {
criteria.and("_id").lt(cursor);
Expand All @@ -28,15 +28,16 @@ public List<Notification> findAllByOwnerAndReadTrue(Long ownerId, Long cursor, I
.limit(size + 1)
.with(Sort.by(Sort.Order.desc("_id")));

List<Notification> notifications = mongoOperations.find(query, Notification.class);
return mongoOperations.find(query, Notification.class);
}

@Override
public void updateReadTrueByOwnerId(Long ownerId) {
mongoOperations.updateMulti(
new Query(Criteria.where("ownerId").is(ownerId)),
new Update().set("read", true),
Notification.class
);

return notifications;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
import com.ssafy.ssafsound.domain.member.exception.MemberException;
import com.ssafy.ssafsound.domain.member.repository.MemberRepository;
import com.ssafy.ssafsound.domain.notification.domain.Notification;
import com.ssafy.ssafsound.domain.notification.dto.GetCheckNotificationResDto;
import com.ssafy.ssafsound.domain.notification.dto.GetNotificationReqDto;
import com.ssafy.ssafsound.domain.notification.dto.GetNotificationResDto;
import com.ssafy.ssafsound.domain.notification.dto.*;
import com.ssafy.ssafsound.domain.notification.event.NotificationEvent;
import com.ssafy.ssafsound.domain.notification.repository.NotificationRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -25,16 +25,31 @@ public class NotificationService {
private final MemberRepository memberRepository;

@Transactional
public GetNotificationResDto getNotifications(AuthenticatedMember authenticatedMember, GetNotificationReqDto getNotificationReqDto) {
public GetNotificationCursorResDto getNotificationsByCursor(AuthenticatedMember authenticatedMember, GetNotificationCursorReqDto getNotificationCursorReqDto) {
if (!memberRepository.existsById(authenticatedMember.getMemberId())) {
throw new MemberException(MemberErrorInfo.MEMBER_NOT_FOUND_BY_ID);
}

Long ownerId = authenticatedMember.getMemberId();
Long cursor = getNotificationReqDto.getCursor();
int size = getNotificationReqDto.getSize();
List<Notification> notifications = notificationRepository.findAllByOwnerAndReadTrue(ownerId, cursor, size);
return GetNotificationResDto.of(notifications, size);
Long cursor = getNotificationCursorReqDto.getCursor();
int size = getNotificationCursorReqDto.getSize();
List<Notification> notifications = notificationRepository.findAllByOwnerId(ownerId, cursor, size);
notificationRepository.updateReadTrueByOwnerId(ownerId);

return GetNotificationCursorResDto.of(notifications, size);
}

@Transactional
public GetNotificationOffsetResDto getNotificationsByOffset(AuthenticatedMember authenticatedMember, GetNotificationOffsetReqDto getNotificationOffsetReqDto) {
if (!memberRepository.existsById(authenticatedMember.getMemberId())) {
throw new MemberException(MemberErrorInfo.MEMBER_NOT_FOUND_BY_ID);
}

Long ownerId = authenticatedMember.getMemberId();
PageRequest pageRequest = getNotificationOffsetReqDto.toPageRequest();
Page<Notification> notifications = notificationRepository.findAllByOwnerId(ownerId, pageRequest);
notificationRepository.updateReadTrueByOwnerId(ownerId);
return GetNotificationOffsetResDto.of(notifications);
}

@Transactional
Expand Down
Loading

0 comments on commit 046272b

Please sign in to comment.