4차 프로젝트에서 추천 편지나 타겟 편지 등 다양한 알림을 보내야 하는 상황이 있었습니다. 이때 저희는 단순히 알림 페이지 내에서 관리하는 것뿐만 아니라, 사용자에게 푸시 알림을 보내는 방법에 대해 고민하였습니다. 앱이 아닌 웹 환경이므로 어떻게 할지 고민하다가 FCM을 이용하기로 하였습니다.
📌 FCM이란?
FCM은 Firebase Cloud Messaging으로, 무료로 메시지를 보낼 수 있는 크로스 플랫폼 메시징 솔루션입니다. FCM은 Google의 클라우드 메시징 서비스이고, 토큰을 이용해 사용자를 식별하고 푸시 메시지를 보낼 수 있습니다.
📌 어떻게 사용자는 푸시 알림을 받게되는걸까?
사용자는 알림을 허용하면 FCM의 고유한 토큰을 발급받습니다. 이때 이 토큰을 이용하여 푸시 알림이 이루어지게 됩니다.

저희는 알림 허용 시, 사용자의 토큰을 DB에 저장하였습니다. 이후 알림을 전송해야 할 상황이 되면, DB에 저장된 사용자의 토큰을 통해 FCM에 메시지 전송을 요청합니다. 그러면 FCM은 Service Worker를 통해 푸시 알림을 받게 됩니다.
이때 Service Worker가 백그라운드로 켜져 있어야 사용자는 실시간으로 알림을 받을 수 있습니다.
📌 백엔드의 FCM 구현
이때 저희는 사용자 토큰을 DB에 저장하고, 해당 알림을 FCM을 통해 메시지를 보내야 했습니다. 구현은 비교적 간단했습니다.
스프링 FCM 설정
우선 build.gradle 에 FCM 의존성을 추가합니다.
// Firebase Admin SDK
implementation 'com.google.firebase:firebase-admin:9.2.0'
그 후, FCM Config를 작성해야 합니다.
FcmConfig.java
@Configuration
public class FcmConfig {
@Value("${fcm.private-key}")
private String privateKey;
@PostConstruct
public void init() {
try {
byte[] decodedBytes = Base64.getDecoder().decode(privateKey);
InputStream serviceAccount = new ByteArrayInputStream(decodedBytes);
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();
if (FirebaseApp.getApps().isEmpty()) {
FirebaseApp.initializeApp(options);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
이때 InputStream은 사실 간단하게 다음과 같이 작성할 수도 있습니다.
new ClassPathResource("service-account.json").getInputStream();
처음에 저희는 위와 같이 작성하였지만, 서버 내에 Key 파일을 두고 싶지 않았습니다. 그래서 해당 json 파일을 Base64로 인코딩하여 secrets에 등록하여 해당 String을 받아왔습니다. 그 후, 다시 디코딩하여 ByteArrayInputStream을 통해 InputStream을 생성하였습니다.
Base64 인코딩은 다음 명령어를 사용하여 인코딩하였습니다.
base64 service-account.json
메시지 전송
저희는 서비스 계층에서 PushNotificationProvider 인터페이스를 생성하고, 인프라 계층에서 FCM 구현체를 작성하였습니다.
public interface PushNotificationProvider {
void pushAll(PushMessages pushMessages);
}
@Slf4j
@Component
@RequiredArgsConstructor
public class FirebasePushProvider implements PushNotificationProvider {
private final FirebaseMessageMapper messageMapper;
@Override
public void pushAll(PushMessages pushMessages) {
List<Message> firebaseMessages = messageMapper.mapToFirebaseMessages(pushMessages);
try {
FirebaseMessaging.getInstance().sendEach(firebaseMessages);
} catch (FirebaseMessagingException e) {
log.error(e.getMessage());
}
}
}
FCM을 통해 푸시 알림을 전송하는 것은 비교적 간단했습니다. 우선 firebase의 Message 객체를 생성합니다. 그 후, FirebaseMessaging 인스턴스를 불러와 생성한 Message 객체를 전송하면 됩니다.
위 코드에서 PushMessages는 도메인 객체로, 도메인 및 서비스 계층에서 사용하는 자바로만 작성된 객체입니다.
위처럼 비교적 간단하게 백엔드에서 FCM 알림을 전송할 수 있었습니다. 제가 이용한 방법처럼 json을 적용하지 않고 API 통신을 이용한 방법도 있는 것으로 알고 있지만, 저희는 Firebase Admin SDK를 이용하였습니다. 공식 문서에도 비교적 자세한 설명이 나와있으므로, 혹시 이용하신다면 참고하셔도 좋을 것 같습니다.
'데브코스' 카테고리의 다른 글
인덱스를 통한 받은 편지 조회 개선하기 (0) | 2025.03.21 |
---|---|
알림 기능의 필수 여부 확인하기 (0) | 2025.02.08 |
모니터링 서버 구축하기 (0) | 2025.01.27 |
이벤트스토밍 적용기 (0) | 2024.11.24 |