해당 글에서는 Spring Boot API에서 FCM으로 통신하여 FCM Push Message 전송 API 구축을 하는 방법에 대해 알아봅니다.
💡 [참고] FCM 관련해서 구성 내용에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
분류 | 링크 |
FCM Spirng Boot API 구성 : 단순 전송 기능 | https://adjh54.tistory.com/432 |
FCM React Native 초기 환경 설정 | https://adjh54.tistory.com/431 |
FCM React Native Notifee 메시지 수신 구성 | https://adjh54.tistory.com/433 |
FCM React Natiive Notifee 메시지 전송 및 예약 발송 구성 | https://adjh54.tistory.com/434 |
FCM Spring Boot API 구성: 예약 발송 기능 | https://adjh54.tistory.com/438 |
FCM Github Repository : Spring Boot Firebase Cloud API | https://github.com/adjh54ir/blog-codes/tree/main/spring-boot-fcm |
FCM 스케줄러 Github Repository : Spring Boot Quarts | https://github.com/adjh54ir/blog-codes/tree/main/spring-boot-scheudler |
1) Firebase 환경설정
💡 Firebase 환경설정
- 아래의 공식 사이트에 접근하여 환경설정을 수행합니다.
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com
1. Firebase 사이트 → 프로젝트 개요 → 프로젝트 설정 버튼을 누릅니다.
2. 프로젝트 설정 → 서비스 계정 → 자바 선택 → ‘새 비공개 키 생성’ 버튼을 누릅니다.
3. ‘키 생성’ 버튼을 누릅니다.
4. 생성된 json 파일을 프로젝트 resources/firebase 디렉터리를 생성하고 경로에 옮겨둡니다.
2) Spring Boot 환경설정
1. 전체 데이터 흐름
💡 전체 데이터 흐름
1. Spring Boot FcmController로 API를 호출합니다.
- HTTP Method POST 형태로 구성한 ‘api/v1/fcm/send’로 FCM 토큰(디바이스에서 발급받은 토큰), 푸시 메시지 제목, 내용을 파라미터로 전달합니다.
2. FcmServiceImple
- FCM과 통신하는 URL로 해당 메시지 정보를 전달합니다. 해당 통신 방법은 RestTemplate을 이용하여 동기식 전송을 수행하였습니다.
3. FCM Service
- FCM Service에서는 전달받은 토큰에 따라 디바이스로 푸시 메시지를 전송하고 종료합니다.
2. 의존성 주입
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' // Spring Boot Web
implementation 'com.google.firebase:firebase-admin:9.2.0' // Google Firebase Admin
implementation 'com.fasterxml.jackson.core:jackson-core:2.16.1' // Jackson Data Bind
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
[ 더 알아보기 ]
💡firebase-admin
- Java에서 사용할 수 있는 Firebase Admin SDK를 의미합니다. 이를 이용하면 Firebase Authentication, Cloud Firestore, Cloud Messaging (FCM), Realtime Database 등의 Firebase 서비스를 서버에서 직접 액세스 하고 관리할 수 있습니다.
3. DTO
💡 FcmSendDto
- 모바일에서 전달받은 객체를 매핑하는 DTO입니다
필드 값 | 설명 |
token | - 디바이스 기기에서 발급받은 FCM 토큰 값을 의미합니다. 이는 디바이스로 전송하기 위해서는 전송 주체가 되는 디바이스 기기가 필요하기에 해당 내용이 들어갑니다. |
title | - 디바이스 기기로 전송하려는 푸시메시지의 제목 |
body | - 디바이스 기기로 전송하려는 푸시메시지의 내용 |
/**
* 모바일에서 전달받은 객체
*
* @author : lee
* @fileName : FcmSendDto
* @since : 2/21/24
*/
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FcmSendDto {
private String token;
private String title;
private String body;
@Builder(toBuilder = true)
public FcmSendDto(String token, String title, String body) {
this.token = token;
this.title = title;
this.body = body;
}
}
💡 FcmMessageDto
- FCM에 실제 전송될 데이터의 DTO입니다.
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
/**
* FCM 전송 Format DTO
*
* @author : lee
* @fileName : FcmMessageDto
* @since : 2/21/24
*/
@Getter
@Builder
public class FcmMessageDto {
private boolean validateOnly;
private FcmMessageDto.Message message;
@Builder
@AllArgsConstructor
@Getter
public static class Message {
private FcmMessageDto.Notification notification;
private String token;
}
@Builder
@AllArgsConstructor
@Getter
public static class Notification {
private String title;
private String body;
private String image;
}
}
💡 [참고] 위에 객체는 아래의 형태를 갖추기 위해 구성하였습니다.
- 기본적으로 메시지 단건 전송을 위해서는 아래와 같은 정보를 포함하여서 전송하여야 합니다.
POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1
Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"body":"This is an FCM notification message!",
"title":"FCM Message"
}
}
}
앱 서버 전송 요청 작성 | Firebase 클라우드 메시징
Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 앱 서버 전송 요청 작성 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Fire
firebase.google.com
💡 [참고] 위에 데이터의 경우는 아래의 공식 사이트의 요청 데이터(Request Body) 형태로 구성한 DTO입니다.
- 해당 내용이 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
Method: projects.messages.send | Firebase Cloud Messaging REST API
firebase.google.com
REST Resource: projects.messages | Firebase Cloud Messaging REST API
firebase.google.com
4. FcmController
💡 FcmController
- 모바일로부터 사용자 FCM 토큰, 메시지 제목, 내용을 받아서 서비스를 처리하는 Controller를 구성하였습니다.
/**
* FCM 관리하는 Controller
*
* @author : lee
* @fileName : FcmController
* @since : 2/21/24
*/
@Slf4j
@RestController
@RequestMapping("/api/v1/fcm")
public class FcmController {
private final FcmService fcmService;
public FcmController(FcmService fcmService) {
this.fcmService = fcmService;
}
@PostMapping("/send")
public ResponseEntity<ApiResponseWrapper<Object>> pushMessage(@RequestBody @Validated FcmSendDto fcmSendDto) throws IOException {
log.debug("[+] 푸시 메시지를 전송합니다. ");
int result = fcmService.sendMessageTo(fcmSendDto);
ApiResponseWrapper<Object> arw = ApiResponseWrapper
.builder()
.result(result)
.resultCode(SuccessCode.SELECT_SUCCESS.getStatus())
.resultMsg(SuccessCode.SELECT_SUCCESS.getMessage())
.build();
return new ResponseEntity<>(arw, HttpStatus.OK);
}
}
5. Service
💡 Service
- FCM Service를 처리하는 인터페이스입니다. sendMessageTo() 메서드를 추가하였습니다.
import java.io.IOException;
/**
* FCM SERVICE
*
* @author : lee
* @fileName : PushMessageService
* @since : 2/21/24
*/
@Service
public interface FcmService {
int sendMessageTo(FcmSendDto fcmSendDto) throws IOException;
}
6. ServiceImpl
💡 ServiceImpl
- FCM과 통신하여 모바일에서 받은 정보를 기반으로 메시지를 전송합니다.
메서드 | 설명 |
sendMessageTo | 메시지를 구성하고 토큰을 받아서 FCM으로 메시지 처리를 수행하는 비즈니스 로직 |
getAccessToken | Firebase Admin SDK의 비공개 키를 참조하여 Bearer 토큰을 발급 받습니다. |
makeMessage | FCM 전송 정보를 기반으로 메시지를 구성합니다. (Object -> String) |
💡 해당 부분 중 API_URL는 https://fcm.googleapis.com/v1/projects/><프로젝트 명>/messages:send 으로 구성이 되어 있습니다.
- Firebase에 접근하여 프로젝트 설정 - 프로젝트 ID 부분을 입력하시면 됩니다.
💡 [참고] 프로젝트 명은 어디서 확인이 가능할까?
- Firebase에 접근하여 프로젝트 설정 - 프로젝트 ID 부분을 입력하시면 됩니다.
[ 더 알아보기 ]
💡 Object Mapper에서 오류가 납니다.
- Jackson 라이브러리를 이용하여 직렬화를 수행하였습니다.
- 사용방법이 궁금하시면 아래의 글을 참고하시면 도움이 됩니다. https://adjh54.tistory.com/375
[Java] Spring Boot 환경에서 Jackson 모듈 활용하기 : JSON 파싱, 직렬화, 역 직렬화, JSON 파일 읽어오기/
해당 글에서는 Spring Boot 환경에서 Jackson 라이브러리를 활용하는 방법에 대해서 알아봅니다. 1) Jackson 💡 Jackson - JSON 데이터 작업을 하기 위한 인기 있는 Java 라이브러리입니다. - JSON 파일을 읽거
adjh54.tistory.com
/**
* FCM 서비스를 처리하는 구현체
*
* @author : FcmServiceImpl
* @fileName : PushMessageServiceImpl
* @since : 2/21/24
*/
@Service
public class FcmServiceImpl implements FcmService {
/**
* 푸시 메시지 처리를 수행하는 비즈니스 로직
*
* @param fcmSendDto 모바일에서 전달받은 Object
* @return 성공(1), 실패(0)
*/
@Override
public int sendMessageTo(FcmSendDto fcmSendDto) throws IOException {
String message = makeMessage(fcmSendDto);
RestTemplate restTemplate = new RestTemplate();
/**
* 추가된 사항 : RestTemplate 이용중 클라이언트의 한글 깨짐 증상에 대한 수정
* @refernece : https://stackoverflow.com/questions/29392422/how-can-i-tell-resttemplate-to-post-with-utf-8-encoding
*/
restTemplate.getMessageConverters()
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + getAccessToken());
HttpEntity entity = new HttpEntity<>(message, headers);
String API_URL = "<https://fcm.googleapis.com/v1/projects/adjh54-a0189/messages:send>";
ResponseEntity response = restTemplate.exchange(API_URL, HttpMethod.POST, entity, String.class);
System.out.println(response.getStatusCode());
return response.getStatusCode() == HttpStatus.OK ? 1 : 0;
}
/**
* Firebase Admin SDK의 비공개 키를 참조하여 Bearer 토큰을 발급 받습니다.
*
* @return Bearer token
*/
private String getAccessToken() throws IOException {
String firebaseConfigPath = "firebase/adjh54-dev-firebase-key.json";
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())
.createScoped(List.of("<https://www.googleapis.com/auth/cloud-platform>"));
googleCredentials.refreshIfExpired();
return googleCredentials.getAccessToken().getTokenValue();
}
/**
* FCM 전송 정보를 기반으로 메시지를 구성합니다. (Object -> String)
*
* @param fcmSendDto FcmSendDto
* @return String
*/
private String makeMessage(FcmSendDto fcmSendDto) throws JsonProcessingException {
ObjectMapper om = new ObjectMapper();
FcmMessageDto fcmMessageDto = FcmMessageDto.builder()
.message(FcmMessageDto.Message.builder()
.token(fcmSendDto.getToken())
.notification(FcmMessageDto.Notification.builder()
.title(fcmSendDto.getTitle())
.body(fcmSendDto.getBody())
.image(null)
.build()
).build()).validateOnly(false).build();
return om.writeValueAsString(fcmMessageDto);
}
}
💡 [참고] FCM 전송 API 문서
Firebase Cloud Messaging API | Firebase Cloud Messaging REST API
Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost.
firebase.google.com
3) 구성 테스트하기
1. API 호출
💡 API 호출
- [POST] http://localhost:8000/api/v1/fcm/send 엔드포인트로 JSON 데이터로 token, title, body 값을 포함하여 전송을 하여 성공적으로 결과코드로 1을 전달받았습니다.
💡 [참고] API로 호출하는 값 중 Token 값은 어떻게 확인이 가능할까?
- 제가 구성한 모바일 환경인 React Native에서는 아래와 같이 FCM Token을 발급받습니다.
- 아래와 같이 @react-native-firebase/messaging 라이브러리 내에서 getToken() 메서드를 호출하면 디바이스의 FCM 토큰을 발급받을 수 있습니다.
import messaging from '@react-native-firebase/messaging';
/**
* INIT APP
* @returns
*/
const App = () => {
useEffect(() => {
getFcmToken();
subscribe();
}, []);
/**
* FCM 토큰을 받습니다.
*/
const getFcmToken = async () => {
const fcmToken = await messaging().getToken();
console.log('[+] FCM Token :: ', fcmToken);
};
}
💡 위 메서드를 호출하면 아래와 같이 FCM 토큰 값이 발급되는데 해당 값을 JSON 객체에 포함하여 전송합니다.
2. 모바일 확인
💡 [참고] 모바일 환경에서 테스트를 해보고 싶으시면 React Native 기반의 아래의 글들을 참고하시면 도움이 됩니다.
[RN] Firebase Cloud Message(FCM) 이해 및 환경설정, 간단 테스트: Android
해당 글에서는 Firebase Cloud Message(FCM)에 대해 이해하고 환경을 구성하며 메시지를 수신하는 형태를 테스트하는 환경 구성 방법에 대해 이해를 돕기 위해 작성하였습니다. 1) FCM(Firebase Cloud Message)
adjh54.tistory.com
[RN] React Native Firebase Cloud Message(FCM) 활용하여 푸시 메시지 수신 구성 : Notifee
해당 글에서는 실제 FCM을 이용하여 메시지를 전송하고 수신하는 방법에 대한 활용방법에 대해 알아봅니다. 💡 [참고] FCM 최초 환경 구성 과정 및 Spring Boot 기반 API 구성에 대해 궁금하시면 아래
adjh54.tistory.com
💡 [참고] FCM의 예약 발송 기능에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
[Java] Spring boot Firebase Cloud Message(FCM) 구축 -2 : 예약 발송 Scheduler(Spring Boot Quartz)
해당 글에서는 Spring Boot 환경에서 FCM 예약 발송 기능을 Spring Boot Quartz(Scheduler)를 이용하여 구성하는 방법에 대해서 알아봅니다. 💡 [참고] FCM 관련해서 구성 내용에 대해 궁금하시면 아래의 글을
adjh54.tistory.com
💡[참고] 해당 구성한 내용의 Repository입니다.
blog-codes/spring-boot-fcm at main · adjh54ir/blog-codes
Contributor9 티스토리 블로그 내에서 활용한 내용들을 담은 레포지토리입니다. Contribute to adjh54ir/blog-codes development by creating an account on GitHub.
github.com
오늘도 감사합니다 😀