본문 바로가기

Web Sever 개발과 CS 기초/스프링

스프링 알림 기능 - Spring Data JPA DB 구현

개요 목적

스프링으로 구현한 서비스에서 알림 기능을 추가하기 위한 데이터 베이스(Spring Data Jpa) 설정 방법에 대해 알아본다.

알림 서비스에서 사용할 예시는, 황대영이라는 유저가 관리하는 유저 문장 그룹이 있고, 해당 문장 그룹을 구독하는 김민우 유저가 존재한다. 문장 그룹을 구독하거나, 구독한 문장 그룹이 입데이트(문장 추가,삭제)되면 각 관련 유저에게 알림이 가는 시스템이다.

실제 사용 동작 예시 확인

1. 구독자 추가 알림 - 문장 그룹 주인 황대영에게 구독자가 늘었다고 알림이 간다.

2. 문장 추가 알림 - 황대영 문장 그룹에 문장이 추가되면 구독한 김민우 유저에게 문장 그룹이 업데이트 되었다고 알림이 간다.

3. 문장 삭제 알림 - 문장 그룹에 문장이 삭제되면 구독한 김민우에게 문장 삭제 알림이 간다.

4. 문장 확인 알림 - 알림 목록에 있는 각 알림에 x버튼을 클릭하면 해당 알림이 삭제된다.

엔티티 데이터 베이스 테이블 생성

각 알림 기능들을 구현 코드를 살펴보기 전에 엔티티 구성 방법에 대해서 알아보자.

알림 기능에 사용되는 엔티티는 총 5가지 이다.

  1. users : 황대영 김민우 같은 유저 정보를 저장한다.
  2. sentence-group : 황대영 문장 그룹1 같은 문장들을 소유하고 있는 문장 그룹 정보를 저장한다. users의 ID를 FK로 가져서 해당 문장 그룹의 누구의 것인지 나타낸다.
  3. user-sentence : 문장 그룹내에 실제 영어,번역 문장들을 저장한다.
  4. sentence-subscribe: 어떤 유저가 어떤 문장 그룹을 구독하고 있는 데이터를 저장한다.
  5. alarm: 구독과 문장 업데이트 알림 데이터를 저장한다.

1. 구독자 추가 알림 구현

@Service
@RequiredArgsConstructor
public class UserSentenceService {

    private final SentenceGroupRepository sentenceGroupRepository;
    private final UserRepository userRepository;
    private final SentenceSubscribeRepository sentenceSubscribeRepository;
    private final UserSentenceRepository userSentenceRepository;
    private final AlarmRepository alarmRepository;

    @Transactional
    public void subscribeSentence(UserSentenceRequest request) {
        //구독한 유저 아이디로 구독 유저를 찾고
        Users findUser = userRepository.findById(request.getSubscriberId()).orElseThrow();
        //구독할 문장 그룹 아이디로 문장 그룹을 찾는다.
        SentenceGroup findSentenceGroup = sentenceGroupRepository.findById(
            request.getSubscribedSentenceId()).orElseThrow();
        //sentenceSubscribe 테이블에 해당 데이터를 등록한다.
        SentenceSubscribe sentenceSubscribe = SentenceSubscribe.builder().subscribedUser(findUser)
            .sentenceGroup(findSentenceGroup).build();
        sentenceSubscribeRepository.save(sentenceSubscribe);

        //알림 보내기 - 알림 데이터 테이블에 저장하기
        //유저 이름과 문장 목록을 가지고 구독했다는 알림 메세지 작성
        String alarmMessage =
            findUser.getName() + "님이 " + findSentenceGroup.getSentenceName() + " 목록을 구독했습니다.";
        //문장 그룹과 구독한 유저 구독이라는 알림 타입, 메세지 정보를 테이블에 저장한다.
        Alarm alarm = Alarm.builder().sentenceGroup(findSentenceGroup).subscribedUser(findUser)
        .alarmType(AlarmType.SUBSCRIBE).alarmMessage(alarmMessage).build();
        alarmRepository.save(alarm);
    }

2. 문장 추가 알림 구현

@Service
@RequiredArgsConstructor
public class UserSentenceService {

    @Transactional
    public void addSentence(UserSentenceRequest request) {
       //request 정보로 날라온 문장 id 영어 번역 정보로 userSentence에 데이터 저장한다
       SentenceGroup findSentenceGroup = sentenceGroupRepository.findById(
           request.getUpdateSentenceGroupId()).orElseThrow();
       UserSentence userSentence = UserSentence.builder()
           .sentenceGroup(findSentenceGroup).korean(request.getKorean())
           .english(request.getEnglish()).build();
       userSentenceRepository.save(userSentence);

       //알림 보내기 - 해당 문장 그룹을 구독한 유저 전부에게
       //SetnteceSubscribe 테이블에서 해당 문장 그룹을 구독한 모든 사용자 정보가 있는 데이터를 찾는다.
       List<SentenceSubscribe> findSubuscribeList = sentenceSubscribeRepository
           .findListBySentenceGroup(findSentenceGroup);
       //알림 메세지를 등록하고
       String alarmMessage =
           findSentenceGroup.getSentenceName() + " 목록에 문장이 추가되었습니다.";
       //구독한 모든 유저 대상으로 알림 테이블에 데이터를 추가한다
       for (SentenceSubscribe sentenceSubscribe : findSubuscribeList) {
          Alarm alarm = Alarm.builder().sentenceGroup(findSentenceGroup)
              .subscribedUser(sentenceSubscribe.getSubscribedUser())
              .alarmType(AlarmType.UPDATE).alarmMessage(alarmMessage).build();
        alarmRepository.save(alarm);}
    }
}

3. 문장 삭제 알림 구현

@Service
@RequiredArgsConstructor
public class UserSentenceService {

    @Transactional
    public void deleteSentence(UserSentenceRequest request) {
        UserSentence findUserSentence = userSentenceRepository.findById(
                request.getDeleteSentenceId()).orElseThrow();
        //문장 추가와 같은 원리로 알림을 보낸다.
        //다른점은 request로 들어온 문장 ID로 해당 데이터를 삭제한다.
        userSentenceRepository.deleteById(request.getDeleteSentenceId());

        SentenceGroup findSentenceGroup = sentenceGroupRepository.findById(
            findUserSentence.getSentenceGroup().getId()).orElseThrow();
        List<SentenceSubscribe> findSubuscribeList = sentenceSubscribeRepository
            .findListBySentenceGroup(findSentenceGroup);
        String alarmMessage =
            findSentenceGroup.getSentenceName() + " 목록에 문장이 삭제 되었습니다.";
        for (SentenceSubscribe sentenceSubscribe : findSubuscribeList) {
            Alarm alarm = Alarm.builder().sentenceGroup(findSentenceGroup)
                .subscribedUser(sentenceSubscribe.getSubscribedUser())
                .alarmType(
                    AlarmType.UPDATE).alarmMessage(alarmMessage).build();
            alarmRepository.save(alarm);
        }
    }

4. 문장 알림 확인 구현

@Service
@RequiredArgsConstructor
public class UserSentenceService {

    @Transactional
    public void deleteAlarm(UserSentenceRequest request) {
        //x button을 클릭하면 request로 해당 알림 ID롤 전송
        //알림 테이블에서 해당 데이터를 삭제한다
        alarmRepository.deleteById(request.getAlarmId());
    }
}