스터디를 만들때가 아니라 공개할 때 알림
- 알림 받을 사람: 스터디 주제와 지역에 매칭이 되는 Account
- 알림 제목: 스터디 이름
- 알림 메시지: 스터디 짧은 소개
QueryDSL설정
- http://www.querydsl.com/
- 타입 세이프하게 JPA 쿼리를 작성할 수 있다.
QueryDSL 설치
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>
</plugin>
- 이후에 반드시 메이븐 컴파일 빌드 (mvc compile)를 해야 Q클래스 생성해준다.
- 애노테이션 프로세서
스프링 데이터 JPA와 QueryDSL 연동
- QuerydslPredicateExecutor 인터페이스 추가
- Predicate 사용하기
public interface AccountRepository extends JpaRepository<Account, Long>, QuerydslPredicateExecutor<Account> {
}
public class AccountPredicates {
public static Predicate findByTagsAndZones(Set<Tag> tags, Set<Zone> zones){
return QAccount.account.zones.any().in(zones).and(QAccount.account.tags.any().in(tags));
}
}
스터디를 생성할때 스터디 생성알림을 보내지 않고 스터디 생성후 모집중일때 알림을 보내려면
package me.weekbelt.studyolle.modules.study;
@RequiredArgsConstructor
@Transactional
@Service
public class StudyService {
// .......
private final ApplicationEventPublisher eventPublisher;
public Study createNewStudy(Study study, Account account) {
Study newStudy = studyRepository.save(study);
newStudy.addManager(account);
// eventPublisher.publishEvent(new StudyCreatedEvent(newStudy)); 삭제
return newStudy;
}
}
createNewStudy메소드에서 이벤트를 발생시키면 안되고
package me.weekbelt.studyolle.modules.study;
@RequiredArgsConstructor
@Transactional
@Service
public class StudyService {
// .........
public void publish(Study study) {
study.publish();
this.eventPublisher.publishEvent(new StudyCreatedEvent(study));
}
// ..........
}
스터디가 공개되는 publish메소드가 실행될때 이벤트를 발생 시켜야 한다.
스터디와 관련된 Tag와 Zone 정보를 가져오기위한 로직을 추가한다.
package me.weekbelt.studyolle.modules.study.event;
@RequiredArgsConstructor
@Slf4j
@Async
@Transactional
@Component
public class StudyEventListener {
private final StudyRepository studyRepository;
@EventListener
public void handleStudyCreatedEvent(StudyCreatedEvent studyCreatedEvent) {
Study study = studyRepository.findStudyWithTagsAndZonesById(studyCreatedEvent.getStudy().getId());
}
}
StudyRepository에 Tag와Zone을 함께 조회하는 메소드 작성
package me.weekbelt.studyolle.modules.study;
@Transactional(readOnly = true)
public interface StudyRepository extends JpaRepository<Study, Long> {
// ........
@EntityGraph(value = "Study.withTagsAndZones", type = EntityGraph.EntityGraphType.FETCH)
Study findStudyWithTagsAndZonesById(Long id);
}
StudyEntity에 엔티티 그래프 추가
package me.weekbelt.studyolle.modules.study;
@NamedEntityGraph(name = "Study.withTagsAndZones", attributeNodes = {
@NamedAttributeNode("tags"),
@NamedAttributeNode("zones")
})
// ........
public class Study {
// ............
}
스터디의 Tag, Zone과 스터디 참여 계정의 Tag, Zone과 관련된 사람들에게 알림을 보내기위한 로직 생성
AccountRepository에 QuerydslPredicateExecutor를 상속
package me.weekbelt.studyolle.modules.account;
@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long>,
QuerydslPredicateExecutor<Account> { // 추가
// ..........
}
Predicate를 AccountRepository에 제공하기위한 클래스 추가
스터디의 zone과 tag중에 account의 zone과 tag가 하나라도 겹치면 알림이 갈 수 있도록 하기위한 로직
package me.weekbelt.studyolle.modules.account;
public class AccountPredicates {
public static Predicate findByTagsAndZones(Set<Tag> tags, Set<Zone> zones) {
return account.zones.any().in(zones)
.and(account.tags.any().in(tags));
}
}
다시 StudyEventListener로 돌아와서 누구에게 알림을 발송해야하는지 조건과 그 조건 충족시 처리를 하는 로직을 작성한다.
package me.weekbelt.studyolle.modules.study.event;
@RequiredArgsConstructor
@Slf4j
@Async
@Transactional
@Component
public class StudyEventListener {
private final StudyRepository studyRepository;
private final AccountRepository accountRepository;
private final EmailService emailService;
private final TemplateEngine templateEngine;
private final AppProperties appProperties;
private final NotificationRepository notificationRepository;
@EventListener
public void handleStudyCreatedEvent(StudyCreatedEvent studyCreatedEvent) {
// Tags와 Zones를 참조할수 있는 Study를 가져왔다.
Study study = studyRepository.findStudyWithTagsAndZonesById(studyCreatedEvent.getStudy().getId());
Iterable<Account> accounts = accountRepository.findAll(AccountPredicates.findByTagsAndZones(study.getTags(), study.getZones()));
accounts.forEach(account -> {
if (account.isStudyCreatedByEmail()){
sendStudyCreatedEmail(study, account);
}
if (account.isStudyCreatedByWeb()) {
saveStudyCreatedNotification(study, account);
}
});
}
private void sendStudyCreatedEmail(Study study, Account account) {
Context context = new Context();
context.setVariable("nickname", account.getNickname());
context.setVariable("link", "/study/" + study.getEncodedPath());
context.setVariable("linkname", study.getTitle());
context.setVariable("message", "새로운 스터디가 생겼습니다.");
context.setVariable("host", appProperties.getHost());
String message = templateEngine.process("mail/simple-link", context);
EmailMessage emailMessage = EmailMessage.builder()
.subject("스터디올래, '" + study.getTitle() + "' 스터디가 생겼습니다.")
.to(account.getEmail())
.message(message)
.build();
emailService.sendEmail(emailMessage);
}
private void saveStudyCreatedNotification(Study study, Account account) {
Notification notification = new Notification();
notification.setTitle(study.getTitle());
notification.setLink("/study/" + study.getEncodedPath());
notification.setChecked(false);
notification.setCreatedLocalDateTime(LocalDateTime.now());
notification.setMessage(study.getShortDescription());
notification.setAccount(account);
notification.setNotificationType(NotificationType.STUDY_CREATED);
notificationRepository.save(notification);
}
}
참고: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-%EC%9B%B9%EC%95%B1#
'스프링과 JPA 기반 웹 어플리케이션 개발 > 7부 알림' 카테고리의 다른 글
76. 관심있는 스터디 변경 알림 (0) | 2020.05.12 |
---|---|
75. 알림 목록 조회 및 삭게 (0) | 2020.05.12 |
74. 스터디 알림 아이콘 변경 (0) | 2020.05.12 |
72. 알림 처리 설계 (0) | 2020.05.11 |
71. 알림 도메인 (0) | 2020.05.10 |