알람 기능을 추가해 보았다.
- 로그인 한 유저에게 달린 모든 댓글과 좋아요를 page형태로 return
- 자신이 자신의 글에 댓글과 좋아요를 달 시 알람 x
- 좋아요 취소후 재등록시 알람 x
1. Domain
Alarm (Entity)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Table(name = "alarm")
@Entity
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Alarm extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;
//알람 타입 (like or comment)
@Enumerated(EnumType.STRING)
private AlarmType alarmType;
//댓글이나 좋아요를 달은 userId
private int fromUserId;
//알람 발생한 postId
private int targetId;
private String text;
public AlarmDto toResponse() {
return AlarmDto.builder()
.id(this.getId())
.alarmType(this.getAlarmType())
.fromUserId(this.getFromUserId())
.targetId(this.getTargetId())
.text(this.getAlarmType().getText())
.createdAt(this.getCreatedAt())
.build();
}
public static Alarm toEntity(Post post, User user, AlarmType alarmType) {
return Alarm.builder()
.user(post.getUser())
.alarmType(alarmType)
.fromUserId(user.getId())
.targetId(post.getId())
.build();
}
}
Alarm Entity이다. 다른 Entity와 마찬가지로 BaseEntity를 extends해주었다.
AlarmType (Enum)
@AllArgsConstructor
@Getter
public enum AlarmType {
NEW_COMMENT_ON_POST("new comment!"),
NEW_LIKE_ON_POST("new like!");
private String text;
}
Alarm Entity에서 사용하는 AlarmType이다.
Enum으로 구현하였다.
AlarmDto (DTO)
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class AlarmDto {
private int id;
private AlarmType alarmType;
private int fromUserId;
private int targetId;
private String text;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
}
AlarmService -> AlarmController로 return하기 위한 Dto이다.
2. Repository
AlarmRepository
public interface AlarmRepository extends JpaRepository<Alarm, Integer> {
Page<Alarm> findAllByUser(User user, Pageable pageable);
}
해당 유저의 알람을 Page로 모두 불러오기 위한 findAllByUser method를 추가하였다.
3. Service
AlarmService
@Service
@RequiredArgsConstructor
@Slf4j
public class AlarmService {
private final AlarmRepository alarmRepository;
private final UserRepository userRepository;
@Transactional
public Page<AlarmDto> getAlarm(Pageable pageable, String userName) {
User user = userRepository.findByUserName(userName)
.orElseThrow(() -> new AppException(ErrorCode.NOT_FOUNDED_USER_NAME, ""));
Page<Alarm> alarms = alarmRepository.findAllByUser(user, pageable);
return alarms.map(Alarm::toResponse);
}
}
알람목록을 불러오기 위한 비즈니스 로직이 담겨있다.
PostService
@Service
@RequiredArgsConstructor
@Slf4j
public class PostService {
private final PostRepository postRepository;
private final UserRepository userRepository;
private final CommentRepository commentRepository;
private final LikeRepository likeRepository;
private final AlarmRepository alarmRepository;
...
//댓글 기능
@Transactional
public CommentDto createComment(Integer postId, String userName, String comment) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new AppException(ErrorCode.POST_NOT_FOUND, ""));
User user = userRepository.findByUserName(userName)
.orElseThrow(() -> new AppException(ErrorCode.NOT_FOUNDED_USER_NAME, ""));
Comment commentEntity = Comment.builder()
.comment(comment)
.user(user)
.post(post)
.build();
commentRepository.save(commentEntity);
//자신의 글에 다른 사람이 comment 등록 시 alarm 생성 (자기 자신 x)
if (post.getUser().getId() != user.getId()) {
Alarm alarm = Alarm.toEntity(post, user, AlarmType.NEW_COMMENT_ON_POST);
alarmRepository.save(alarm);
}
return commentEntity.toResponse();
}
...
@Transactional
public String doLike(Integer postId, String userName) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new AppException(ErrorCode.POST_NOT_FOUND, ""));
User user = userRepository.findByUserName(userName)
.orElseThrow(() -> new AppException(ErrorCode.NOT_FOUNDED_USER_NAME, ""));
Optional<Like> like = likeRepository.findByUserAndPost(user, post);
//좋아요가 이미 존재하고, deletedAt이 null일때 (삭제되지 않은 상태)
if (like.isPresent() && like.get().getDeletedAt() == null) {
likeRepository.delete(like.get());
return "좋아요를 취소했습니다.";
}
//좋아요가 있지만, deletedAt이 null이 아닐 때 (삭제된 상태. 즉 취소된 상태)
if (like.isPresent() && like.get().getDeletedAt() != null) {
like.get().recoverLike(like.get()); //좋아요 복구 method
likeRepository.saveAndFlush(like.get());
return "좋아요를 눌렀습니다.";
}
//좋아요가 아예 없을 때 새로 생성
likeRepository.save(Like.toEntity(user, post));
//첫 좋아요 발생시에만 alarm 생성 + 다른 사람이 좋아요 처음 눌렀을 시 (자기 자신 x)
if (post.getUser().getId() != user.getId()) {
Alarm alarm = Alarm.toEntity(post, user, AlarmType.NEW_LIKE_ON_POST);
alarmRepository.save(alarm);
}
return "좋아요를 눌렀습니다.";
}
...
}
새로운 댓글과 좋아요를 작성할 때 알람에 추가하는 로직을 추가하였다.
자신의 글에 다른사람이 댓글/좋아요를 누를 시에만 알람을 추가하도록 조건문을 추가하였고,
좋아요의 경우에는, 취소 후 재등록에는 알람이 생성되지 않도록 하였다.
4. Controller
AlarmController
@RestController
@RequestMapping("/api/v1/alarms")
@RequiredArgsConstructor
public class AlarmController {
private final AlarmService alarmService;
@GetMapping
@ApiOperation(value = "유저 알람 목록 조회")
public Response<Page<AlarmDto>> getAlarm(@PageableDefault(size=20, sort="createdAt", direction = Sort.Direction.DESC) Pageable pageable,
@ApiIgnore Authentication authentication) {
Page<AlarmDto> alarmDtos = alarmService.getAlarm(pageable, authentication.getName());
return Response.success(alarmDtos);
}
}
알람 목록을 조회하기 위한 Controller를 추가하였다.
'프로젝트 > 멋사 개인 프로젝트 (mutsa-SNS)' 카테고리의 다른 글
[25] mutsa-SNS-2 6일차 - (2) Swagger api 정보 추가 (0) | 2023.01.10 |
---|---|
[24] mutsa-SNS-2 6일차 - (1) 알람 기능 test code (0) | 2023.01.10 |
[22] mutsa-SNS-2 4일차 - 마이 피드 기능 test code (0) | 2023.01.09 |
[21] mutsa-SNS-2 3일차 - (2) 마이 피드 기능 구현 (0) | 2023.01.05 |
[20] mutsa-SNS-2 3일차 - (1) soft delete 관련 리펙토링 (@Transactional 이슈) (0) | 2023.01.05 |