Skip to content

Commit

Permalink
Merge pull request #346 from IceButler/refactor/#333-notificationService
Browse files Browse the repository at this point in the history
#333 fcmUtils, 알림 비동기 처리
  • Loading branch information
psyeon1120 authored Aug 6, 2024
2 parents 6b7656a + c613918 commit 223e014
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,88 +1,52 @@
package com.example.icebutler_server.alarm.service;

import com.example.icebutler_server.alarm.dto.FcmMessage;
import com.example.icebutler_server.alarm.entity.PushNotification;
import com.example.icebutler_server.alarm.repository.PushNotificationRepository;
import com.example.icebutler_server.global.util.Constant;
import com.example.icebutler_server.global.util.FcmUtils;
import com.example.icebutler_server.user.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.GoogleCredentials;
import lombok.RequiredArgsConstructor;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.json.JsonParseException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

@Component
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class NotificationServiceImpl implements NotificationService {
private final String API_URL = "https://fcm.googleapis.com/v1/projects/icebutler-46914/messages:send";
private final ObjectMapper objectMapper;

private final PushNotificationRepository notificationRepository;
private final FcmUtils fcmUtils;


// TODO 냉장고 유저 탈퇴 로직 리팩 후 호출
@Transactional
@Override
public void sendWithdrawalAlarm(User user, String fridgeName) throws JsonParseException, IOException {
String messageBody = fridgeName+"에서 탈퇴되었습니다.";
if(user.getFcmToken()!=null){
FcmMessage message = FcmMessage.makeMessage(user.getFcmToken(), Constant.PushNotification.FRIDGE, messageBody);
Response response = sendMessage(objectMapper.writeValueAsString(message));
this.notificationRepository.save(PushNotification.toEntity(Constant.PushNotification.FRIDGE, messageBody, user));
public void sendWithdrawalAlarm(User user, String fridgeName) {
String messageBody = fridgeName + "에서 탈퇴되었습니다.";
if (user.getFcmToken() != null) {
fcmUtils.sendMessage((user.getFcmToken()), Constant.PushNotification.FRIDGE, messageBody);
}
this.notificationRepository.save(PushNotification.toEntity(Constant.PushNotification.FRIDGE, messageBody, user));
}
// TODO 냉장고 유저 초대 리펙 후 호출

@Transactional
@Override
public void sendJoinFridgeAlarm(User user, String fridgeName) throws IOException {
String messageBody = fridgeName+"에서 초대되었습니다.";
if(user.getFcmToken()!=null) {
FcmMessage message = FcmMessage.makeMessage(user.getFcmToken(), Constant.PushNotification.FRIDGE, messageBody);
Response response = sendMessage(objectMapper.writeValueAsString(message));
this.notificationRepository.save(PushNotification.toEntity(Constant.PushNotification.FRIDGE, messageBody, user));
public void sendJoinFridgeAlarm(User user, String fridgeName) {
String messageBody = fridgeName + "에서 초대되었습니다.";
if (user.getFcmToken() != null) {
fcmUtils.sendMessage((user.getFcmToken()), Constant.PushNotification.FRIDGE, messageBody);
}
this.notificationRepository.save(PushNotification.toEntity(Constant.PushNotification.FRIDGE, messageBody, user));
}

@Transactional
@Override
public void sendShelfLifeAlarm(User user, String fridgeName, String foodName) throws IOException {
String messageBody = foodName+" 소비기한이 임박해요!";
if(user.getFcmToken()!=null) {
FcmMessage message = FcmMessage.makeMessage(user.getFcmToken(), fridgeName, messageBody);
Response response = sendMessage(objectMapper.writeValueAsString(message));
this.notificationRepository.save(PushNotification.toEntity(fridgeName, messageBody, user));
String messageBody = foodName + " 소비기한이 임박해요!";
if (user.getFcmToken() != null) {
fcmUtils.sendMessage((user.getFcmToken()), fridgeName, messageBody);
}
}


@NotNull
private Response sendMessage(String message) throws IOException {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = RequestBody.create(message,
MediaType.get("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(API_URL)
.post(requestBody)
.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + getAccessToken())
.addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
.build();

return client.newCall(request).execute();
}

private String getAccessToken() throws IOException {
String firebaseConfigPath = "firebase/firebase_service_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();
this.notificationRepository.save(PushNotification.toEntity(fridgeName, messageBody, user));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,10 @@ public Long addFridge(AddFridgeReq addFridgeReq, Long ownerId) {
fridgeUserRepository.saveAll(members);
cartRepository.save(Cart.toEntity(fridge));

try {
for (FridgeUser fridgeUser : members)
alarmService.sendJoinFridgeAlarm(fridgeUser.getUser(), fridge.getFridgeName());
} catch (IOException e) {
e.printStackTrace();
}

for (FridgeUser fridgeUser : members)
alarmService.sendJoinFridgeAlarm(fridgeUser.getUser(), fridge.getFridgeName());


return fridge.getId();
}
Expand Down Expand Up @@ -140,15 +138,13 @@ private void updateFridgeUsers(EditFridgeReq editFridgeReq, Fridge fridge) {
this.fridgeUserRepository.deleteByFridgeAndUserIn(fridge, membersToDelete);
}

try {
for (User user : membersToAdd)
alarmService.sendJoinFridgeAlarm(user, fridge.getFridgeName());

for (User user : membersToDelete)
alarmService.sendWithdrawalAlarm(user, fridge.getFridgeName());
} catch (IOException e) {
e.printStackTrace();
}
for (User user : membersToAdd)
alarmService.sendJoinFridgeAlarm(user, fridge.getFridgeName());

for (User user : membersToDelete)
alarmService.sendWithdrawalAlarm(user, fridge.getFridgeName());

}

private void exchangeFridgeOwner(FridgeUser owner, FridgeUser newOwner) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum ReturnCode {

// 서버 에러
INTERNAL_SERVER_ERROR("E0000", HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러입니다."),
FIREBASE_SERVER_ERROR("E0001", HttpStatus.INTERNAL_SERVER_ERROR, "알림 발송에 실패했습니다."),

// Food
INVALID_FOOD_CATEGORY("F0000", HttpStatus.BAD_REQUEST, "존재하지 않는 카테고리입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.example.icebutler_server.global.util;

import com.example.icebutler_server.alarm.dto.FcmMessage;
import com.example.icebutler_server.global.exception.BaseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.GoogleCredentials;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

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

import static com.example.icebutler_server.global.exception.ReturnCode.FIREBASE_SERVER_ERROR;

@Slf4j
@Component
@RequiredArgsConstructor
public class FcmUtils {
public static final String FIREBASE_CONFIG_PATH = "firebase/firebase_service_key.json";
public static final String NOTIFICATION_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
public static final String MEDIA_TYPE_JSON_UTF_8 = "application/json; charset=utf-8";
public static final String CONTENT_TYPE_JSON_UTF_8 = "application/json; UTF-8";
private static final String API_URL = "https://fcm.googleapis.com/v1/projects/icebutler-46914/messages:send";
public static final String BEARER = "Bearer ";

private final ObjectMapper objectMapper;

public void sendMessage(String targetToken, String title, String body) {
String message = makeMessage(targetToken, title, body);

OkHttpClient client = new OkHttpClient();
RequestBody requestBody = RequestBody.create(message, MediaType.get(MEDIA_TYPE_JSON_UTF_8));
Request request = new Request.Builder()
.url(API_URL)
.post(requestBody)
.addHeader(HttpHeaders.AUTHORIZATION, BEARER + getAccessToken())
.addHeader(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_JSON_UTF_8)
.build();

client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
log.info("알림 실패: ", e.toString());
throw new BaseException(FIREBASE_SERVER_ERROR);
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) {
log.info("알림 성공: ", response.body().toString());
}
});

}

public String makeMessage(String targetToken, String title, String body) {
try {
FcmMessage message = FcmMessage.makeMessage(targetToken, title, body);
return objectMapper.writeValueAsString(message);
} catch (JsonProcessingException e) {
throw new BaseException(FIREBASE_SERVER_ERROR);
}
}

private String getAccessToken() {
try {
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(new ClassPathResource(FIREBASE_CONFIG_PATH).getInputStream())
.createScoped(List.of(NOTIFICATION_SCOPE));
googleCredentials.refreshIfExpired();
return googleCredentials.getAccessToken().getTokenValue();
} catch (IOException e) {
throw new BaseException(FIREBASE_SERVER_ERROR);
}
}

}

0 comments on commit 223e014

Please sign in to comment.