Skip to content

Commit

Permalink
[Feat]: FCM 연동 및 로직 구현
Browse files Browse the repository at this point in the history
푸시 알림을 위한 FCM 관련 로직 작성
admin-sdk파일 등록

Related to: #59
  • Loading branch information
dev-Crayon committed Jan 30, 2024
1 parent a238c17 commit ef5fa48
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 1 deletion.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,7 @@ gradle-app.setting
# Environment Variables
application-local.yml
application-dev.yml
application-prod.yml
application-prod.yml

# firebase admin sdk
sobok-76d0a-firebase-adminsdk-qb2ez-50cf49a817.json
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ dependencies {
implementation group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
implementation group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'

// firebase
implementation 'com.google.firebase:firebase-admin:9.2.0'

// Swagger
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.3.0'

Expand Down
47 changes: 47 additions & 0 deletions src/main/java/io/sobok/SobokSobok/config/FCMConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.sobok.SobokSobok.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.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Configuration
public class FCMConfig {

@Value("${firebase.admin-sdk}")
String adminSdkFileName;

@Bean
FirebaseMessaging firebaseMessaging() throws IOException {
ClassPathResource resource = new ClassPathResource("firebase/" + adminSdkFileName);

InputStream refreshToken = resource.getInputStream();

FirebaseApp firebaseApp = null;
List<FirebaseApp> firebaseAppList = FirebaseApp.getApps();

if (firebaseAppList != null && !firebaseAppList.isEmpty()) {
for (FirebaseApp app : firebaseAppList) {
if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) {
firebaseApp = app;
}
}
} else {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(refreshToken))
.build();

firebaseApp = FirebaseApp.initializeApp(options);
}

return FirebaseMessaging.getInstance(firebaseApp);
}
}
1 change: 1 addition & 0 deletions src/main/java/io/sobok/SobokSobok/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public enum ErrorCode {
NOT_LOGGED_IN_USER(HttpStatus.NOT_FOUND, "로그인되지 않은 사용자입니다."),
ALREADY_EXISTS_USER(HttpStatus.CONFLICT, "이미 회원가입이 완료된 사용자입니다."),
ALREADY_USING_USERNAME(HttpStatus.CONFLICT, "이미 사용중인 username입니다."),
EMPTY_DEVICE_TOKEN(HttpStatus.NOT_FOUND, "디바이스 토큰이 존재하지 않습니다."),

// jwt
EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 토큰입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.sobok.SobokSobok.external.firebase;

import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import io.sobok.SobokSobok.auth.application.util.UserServiceUtil;
import io.sobok.SobokSobok.auth.domain.User;
import io.sobok.SobokSobok.auth.infrastructure.UserRepository;
import io.sobok.SobokSobok.exception.ErrorCode;
import io.sobok.SobokSobok.exception.model.NotFoundException;
import io.sobok.SobokSobok.external.firebase.dto.FCMNotificationRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Slf4j
public class FCMNotificationService {

private final FirebaseMessaging firebaseMessaging;
private final UserRepository userRepository;

public void sendNotificationByDeviceToken(FCMNotificationRequest request) {

User user = UserServiceUtil.findUserById(userRepository, request.userId());

if (user.getDeviceToken() == null) {
throw new NotFoundException(ErrorCode.EMPTY_DEVICE_TOKEN);
}

Notification notification = Notification.builder()
.setTitle(request.title())
.setBody(request.body())
.setImage(request.image())
.build();

Message message = Message.builder()
.setToken(user.getDeviceToken())
.setNotification(notification)
.putAllData(request.data())
.build();

try {
firebaseMessaging.send(message);
} catch (FirebaseMessagingException e) {
log.error("푸시알림 전송에 실패했습니다. userId: " + user.getId() + "\n" + e.getMessage());;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.sobok.SobokSobok.external.firebase.dto;

import lombok.Builder;

import java.util.Map;

@Builder
public record FCMNotificationRequest(

Long userId,
String title,
String body,
String image,
Map<String, String> data
) {
}

0 comments on commit ef5fa48

Please sign in to comment.