-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[OING-177] feat: 매일 사용자 휴대폰 FCM 노티 발송 기능 추가 (#145)
* feat: add fcm services * feat: add notification feature * feat: only not quit members * feat: add slack alert feature
- Loading branch information
Showing
18 changed files
with
336 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
common/src/main/java/com/oing/service/FCMNotificationService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.oing.service; | ||
|
||
import com.google.firebase.messaging.Message; | ||
import com.google.firebase.messaging.MulticastMessage; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 4:09 AM | ||
*/ | ||
public interface FCMNotificationService { | ||
void sendMessage(Message message); | ||
void sendMulticastMessage(MulticastMessage message); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
gateway/src/main/java/com/oing/component/FCMNotificationServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.oing.component; | ||
|
||
import com.google.firebase.messaging.FirebaseMessaging; | ||
import com.google.firebase.messaging.Message; | ||
import com.google.firebase.messaging.MulticastMessage; | ||
import com.oing.service.FCMNotificationService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; | ||
import org.springframework.stereotype.Component; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 4:10 AM | ||
*/ | ||
|
||
@RequiredArgsConstructor | ||
@Component | ||
@ConditionalOnBean(FirebaseMessaging.class) | ||
public class FCMNotificationServiceImpl implements FCMNotificationService { | ||
private final FirebaseMessaging firebaseMessaging; | ||
|
||
@Override | ||
public void sendMessage(Message message) { | ||
firebaseMessaging.sendAsync(message); | ||
} | ||
|
||
@Override | ||
public void sendMulticastMessage(MulticastMessage message) { | ||
firebaseMessaging.sendEachForMulticastAsync(message); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
gateway/src/main/java/com/oing/component/MockFCMNotificationServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.oing.component; | ||
|
||
import com.google.firebase.messaging.FirebaseMessaging; | ||
import com.google.firebase.messaging.Message; | ||
import com.google.firebase.messaging.MulticastMessage; | ||
import com.oing.service.FCMNotificationService; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
import org.springframework.stereotype.Component; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 4:10 AM | ||
*/ | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Component | ||
@ConditionalOnMissingBean(FirebaseMessaging.class) | ||
public class MockFCMNotificationServiceImpl implements FCMNotificationService { | ||
|
||
@Override | ||
public void sendMessage(Message message) { | ||
log.info("MockFCMNotificationServiceImpl.sendMessage: {}", message); | ||
} | ||
|
||
@Override | ||
public void sendMulticastMessage(MulticastMessage message) { | ||
log.info("MockFCMNotificationServiceImpl.sendMulticastMessage: {}", message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.oing.config; | ||
|
||
import com.google.auth.oauth2.GoogleCredentials; | ||
import com.google.firebase.FirebaseApp; | ||
import com.google.firebase.FirebaseOptions; | ||
import com.google.firebase.messaging.FirebaseMessaging; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Profile; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.util.Base64; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 3:59 AM | ||
*/ | ||
@Profile({"prod", "dev"}) | ||
@Configuration | ||
public class FirebaseConfig { | ||
@Value("${cloud.firebase}") | ||
private String firebaseSecret; | ||
|
||
@Bean | ||
public FirebaseMessaging firebaseMessaging() throws IOException { | ||
ByteArrayInputStream credentials = new ByteArrayInputStream(Base64.getDecoder().decode(firebaseSecret)); | ||
FirebaseOptions options = FirebaseOptions.builder() | ||
.setCredentials(GoogleCredentials.fromStream(credentials)).build(); | ||
FirebaseApp firebaseApp = FirebaseApp.initializeApp(options); | ||
return FirebaseMessaging.getInstance(firebaseApp); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
gateway/src/main/java/com/oing/domain/BulkNotificationCompletedEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.oing.domain; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 4:49 AM | ||
*/ | ||
public record BulkNotificationCompletedEvent( | ||
String reason, | ||
int totalTargets, | ||
int totalMembers, | ||
long elapsedMillis | ||
) { | ||
} |
122 changes: 122 additions & 0 deletions
122
gateway/src/main/java/com/oing/job/DailyNotificationJob.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package com.oing.job; | ||
|
||
import com.google.common.collect.Lists; | ||
import com.google.firebase.messaging.ApnsConfig; | ||
import com.google.firebase.messaging.Aps; | ||
import com.google.firebase.messaging.MulticastMessage; | ||
import com.google.firebase.messaging.Notification; | ||
import com.oing.domain.BulkNotificationCompletedEvent; | ||
import com.oing.domain.Member; | ||
import com.oing.service.FCMNotificationService; | ||
import com.oing.service.MemberDeviceService; | ||
import com.oing.service.MemberPostService; | ||
import com.oing.service.MemberService; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.time.LocalDate; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
|
||
/** | ||
* no5ing-server | ||
* User: CChuYong | ||
* Date: 2/2/24 | ||
* Time: 4:16 AM | ||
*/ | ||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Component | ||
public class DailyNotificationJob { | ||
private final ApplicationEventPublisher eventPublisher; | ||
private final FCMNotificationService fcmNotificationService; | ||
|
||
private final MemberService memberService; | ||
private final MemberDeviceService memberDeviceService; | ||
private final MemberPostService memberPostService; | ||
|
||
@Scheduled(cron = "0 0 12 * * *", zone = "Asia/Seoul") // 12:00 PM | ||
public void sendDailyUploadNotification() { | ||
long start = System.currentTimeMillis(); | ||
log.info("[DailyNotificationJob] 오늘 업로드 알림 전송 시작"); | ||
HashSet<String> targetFcmTokens = new HashSet<>(); | ||
List<Member> members = memberService.findAllMember(); | ||
for (Member member : members) { | ||
targetFcmTokens.addAll(memberDeviceService.getFcmTokensByMemberId(member.getId())); | ||
} | ||
|
||
Lists.partition(targetFcmTokens.stream().toList(), 500).forEach(partitionedList -> { | ||
MulticastMessage multicastMessage = MulticastMessage.builder() | ||
.setNotification( | ||
buildNotification("삐삐", "지금 바로 가족에게 일상 공유를 해볼까요?") | ||
) | ||
.addAllTokens(partitionedList) | ||
.setApnsConfig(buildApnsConfig()) | ||
.build(); | ||
fcmNotificationService.sendMulticastMessage(multicastMessage); | ||
}); | ||
log.info("[DailyNotificationJob] 오늘 업로드 알림 전송 완료. (총 {}명, {}토큰) 소요시간 : {}ms", | ||
members.size(), | ||
targetFcmTokens.size(), | ||
System.currentTimeMillis() - start); | ||
|
||
eventPublisher.publishEvent( | ||
new BulkNotificationCompletedEvent( | ||
"오늘 업로드 알림 전송 완료", targetFcmTokens.size(), members.size(), | ||
System.currentTimeMillis() - start | ||
) | ||
); | ||
} | ||
|
||
@Scheduled(cron = "0 30 23 * * *", zone = "Asia/Seoul") // 11:30 PM | ||
public void sendDailyRemainingNotification() { | ||
long start = System.currentTimeMillis(); | ||
log.info("[DailyNotificationJob] 오늘 미 업로드 사용자 대상 알림 전송 시작"); | ||
LocalDate today = LocalDate.now(); | ||
List<Member> allMembers = memberService.findAllMember(); | ||
HashSet<String> targetFcmTokens = new HashSet<>(); | ||
HashSet<String> postedMemberIds = new HashSet<>(memberPostService.getMemberIdsPostedToday(today)); | ||
allMembers.stream() | ||
.filter(member -> !postedMemberIds.contains(member.getId())) //오늘 업로드한 사람이 아닌 사람들은 | ||
.forEach(member -> targetFcmTokens.addAll(memberDeviceService.getFcmTokensByMemberId(member.getId()))); | ||
|
||
Lists.partition(targetFcmTokens.stream().toList(), 500).forEach(partitionedList -> { | ||
MulticastMessage multicastMessage = MulticastMessage.builder() | ||
.setNotification( | ||
buildNotification("삐삐", "사진을 공유할 수 있는 시간이 얼마 남지 않았어요.") | ||
) | ||
.addAllTokens(partitionedList) | ||
.setApnsConfig(buildApnsConfig()) | ||
.build(); | ||
fcmNotificationService.sendMulticastMessage(multicastMessage); | ||
}); | ||
log.info("[DailyNotificationJob] 오늘 미 업로드 사용자 대상 알림 전송 완료. (총 {}명, {}토큰) 소요시간 : {}ms", | ||
allMembers.size() - postedMemberIds.size(), | ||
targetFcmTokens.size(), | ||
System.currentTimeMillis() - start); | ||
|
||
eventPublisher.publishEvent( | ||
new BulkNotificationCompletedEvent( | ||
"오늘 미업로드자 업로드 알림 전송 완료", targetFcmTokens.size(), | ||
allMembers.size() - postedMemberIds.size(), | ||
System.currentTimeMillis() - start | ||
) | ||
); | ||
} | ||
|
||
private Notification buildNotification(String title, String body){ | ||
return Notification.builder() | ||
.setTitle(title) | ||
.setBody(body) | ||
.build(); | ||
} | ||
|
||
private ApnsConfig buildApnsConfig(){ | ||
return ApnsConfig.builder() | ||
.setAps(Aps.builder().setSound("default").build()) | ||
.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,4 +46,4 @@ management: | |
endpoints: | ||
web: | ||
exposure: | ||
include: health,info,prometheus | ||
include: health,info,prometheus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.