FCM 를 활용하여 댓글 알림 기능을 구현하고자 했습니다.
< 참고 > https://firebase.google.com/docs/cloud-messaging?hl=ko
token) - 현재의 프로젝트에서 사용할 방법tokens)topic)< 참고 > https://firebase.google.com/docs/cloud-messaging/server?hl=ko
프로젝트 설정 → 서비스 계정 탭에서 새로운 비공개 키 생성으로 .json 파일을 다운로드 할 수 있습니다.jinminboard-firebase-adminsdk-9ataf-770210e8eb.json{
"type": "service_account",
"project_id": "jinminboard",
"private_key_id": "{private_key_id}",
"private_key": "{private_key}",
"client_email": "firebase-adminsdk-9ataf@jinminboard.iam.gserviceaccount.com",
"client_id": "108834495148772815532",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-9ataf%40jinminboard.iam.gserviceaccount.com"
}< 참고 > https://firebase.google.com/docs/cloud-messaging/migrate-v1?hl=ko
Firebase 서비스에 대한 서버 요청을 승인하기 위해서 아래 방법들을 조합하여 사용할 수 있습니다.
- Google 애플리케이션 기본 사용자 인증 정보(ADC)
- 서비스 계정 JSON 파일
- 서비스 계정에서 생성된 수명이 짧은 OAuth 2.0 액세스 토큰
@Configuration
public class FirebaseConfig {
@Bean
public GoogleCredentials getGoogleCredentials() throws IOException {
return GoogleCredentials
.fromStream(new ClassPathResource("firebase/jinminboard-firebase-adminsdk-9ataf-770210e8eb.json").getInputStream())
.createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
}
@Bean
public FirebaseApp firebaseApp() throws IOException {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(getGoogleCredentials())
.build();
return FirebaseApp.initializeApp(options);
}
//비동기 통신을 위함
@Bean
public ListeningExecutorService firebaseAppExecutor() {
return MoreExecutors.newDirectExecutorService();
}
@Bean
public OkHttpClient okHttpClient() {
return new OkHttpClient();
}
}@Configuration : 클래스를 설정 파일로 저장(in Bean Factory)합니다.getGoogleCredentials() : Google의 인증 라이브러리와 Firebase 사용자 인증 정보를 사용하여 인증 정보를 반환하도록 합니다.firebaseApp() : 반환된 Google의 인증 정보를 통해 Firebase의 설정을 초기화 합니다.@Bean : 메서드를 빈 타입으로 팩토리에 정의합니다. (싱글톤)< 참고 > https://firebase.google.com/docs/cloud-messaging/send-message?hl=ko
메시지를 다음과 같은 타겟 유형으로 전송할 수 있습니다.
- 주제 이름
- 조건
- 기기 등록 토큰
- 기기 그룹 이름(기존 프로토콜 및 Node.js용 Firebase Admin SDK만 해당)
FcmMessage@Getter
public class FcmMessage {
@Key("validate_only")
@JsonIgnore
private boolean validateOnly;
// Message 에 해당하는 데이터는 많지만,
// 사용할 데이터는 notification(Notification), token(String) 뿐
// Notification => title(String), body(String)
@Key("message")
private Message message;
@Builder
public FcmMessage(boolean validateOnly, Message message) {
this.validateOnly = validateOnly;
this.message = message;
}
}Message 클래스에는 수많은 데이터가 담겨 있지만, 필요한 데이터만 사용하기 위해 FcmMessage 객체를 생성하도록 클래스를 작성했습니다.FirebaseCloudMessageService)@Slf4j
@Service
@RequiredArgsConstructor
public class FirebaseCloudMessageService {
private static final String API_URI = "https://fcm.googleapis.com/v1/projects/jinminboard/messages:send";
private final GoogleCredentials googleCredentials;
private final OkHttpClient client;
private final ObjectMapper objectMapper;
/**
* `targetToken`에 해당하는 기기로 푸시 알림 전송 요청
* (targetToken 은 프론트 사이드에서 얻기!)
*/
public void sendMessageTo(String targetToken, String title, String body) throws FirebaseMessagingException, IOException, ExecutionException, InterruptedException {
//Request + Response 사용
/*RequestBody requestBody = getRequestBody(makeFcmMessage(targetToken, title, body));
Request request = getRequest(requestBody);
Response response = getResponse(request);
log.info(response.body().string());*/
//FirebaseMessaging 사용
Message message = makeMessage(targetToken, title, body);
String response = FirebaseMessaging.getInstance().send(message);
log.info(response);
//비동기
String asyncMessage = FirebaseMessaging.getInstance().sendAsync(message).get();
}
private Response getResponse(Request request) throws IOException {
return client.newCall(request).execute();
}
private Request getRequest(RequestBody requestBody) {
return new Request.Builder()
.url(API_URI)
.post(requestBody)
.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + googleCredentials.getAccessToken().getTokenValue())
.addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
.build();
}
private RequestBody getRequestBody(String message) {
return RequestBody.create(message, MediaType.get("application/json; charset=utf-8"));
}
private String makeFcmMessage(String targetToken, String title, String body) throws JsonProcessingException {
FcmMessage fcmMessage = FcmMessage.builder()
.message(Message.builder()
.setToken(targetToken)
.setNotification(new Notification(title, body))
.build())
.validateOnly(false)
.build();
//log.info("message 변환(Object -> String) \n" + objectMapper.writeValueAsString(fcmMessage));
return objectMapper.writeValueAsString(fcmMessage);
}
private Message makeMessage(String targetToken, String title, String body) {
FcmMessage fcmMessage = FcmMessage.builder()
.message(Message.builder()
.setToken(targetToken)
.setNotification(new Notification(title, body))
.build())
.validateOnly(false)
.build();
return fcmMessage.getMessage();
}
}token과 Firebase 서버를 사용합니다. (Request, Response X)sendMessageTo(token, title, body) : Token(기기, 클라이언트)에게 메시지를 전송하는 메서드입니다.makeMessage(token, title, body) : 메시지를 생성합니다.FcmMessage 객체와 Builder를 활용하여 토큰과 알림 내용을 설정하여 생성합니다.CommentWriteService@Slf4j
@Service
@RequiredArgsConstructor
public class CommentWriteService {
private final CommentRepository commentRepository;
private final UserFindService userFindService;
private final BoardFindService boardFindService;
private final FirebaseCloudMessageService messageService;
@Transactional
public Long writeComment(Long userId, Long boardId, CommentWriteRequest commentWriteRequest) throws FirebaseMessagingException, IOException, ExecutionException, InterruptedException {
Board board = boardFindService.findById(boardId);
User user = userFindService.findById(userId);
Comment comment = Comment.builder()
.content(commentWriteRequest.getContent())
.writer(user.getName())
.board(board)
.build();
Comment savedComment = commentRepository.save(comment);
user.writeComment(savedComment);
String targetToken = board.getUser().getDeviceToken();
sendMessageToBoardWriter(targetToken, "Comment Notification!", comment.getWriter(), comment.getContent());
return savedComment.getComment_id();
}
private void sendMessageToBoardWriter(String targetToken, String title, String writer, String content) throws FirebaseMessagingException, IOException, ExecutionException, InterruptedException {
messageService.sendMessageTo(targetToken, title, "[" + writer + "]" + "가 댓글 : <" + content + ">을 작성했습니다.");
}
}sendMessageToBoardWriter()의 구현체는 FirebaseCloudMessageService의 sendMessageTo()입니다.
Escort Delhi Hotels: Your Private Gateway to Unforgettable Intimate Experiences in Delhi's Finest Hotels. Unlock the door to unparalleled pleasure with Escort Delhi Hotels. We specialize in providing access to captivating and incredibly sexy escorts who are experts in creating deeply intimate experiences within the luxurious setting of Delhi hotels. Imagine surrendering to your deepest sexual desires in a safe and discreet environment, guided by a top-notch professional dedicated to your satisfaction.
Hotel Grand Imperial Escorts
Hotel Grand Park Inn Escorts