diff --git a/backend/pium/src/main/java/com/official/pium/admin/service/TestService.java b/backend/pium/src/main/java/com/official/pium/admin/service/TestService.java index b12cba39..0a3b2856 100644 --- a/backend/pium/src/main/java/com/official/pium/admin/service/TestService.java +++ b/backend/pium/src/main/java/com/official/pium/admin/service/TestService.java @@ -1,9 +1,6 @@ package com.official.pium.admin.service; -import com.official.pium.petPlant.domain.PetPlant; -import com.official.pium.petPlant.event.notification.NotificationEvent; import com.official.pium.petPlant.repository.PetPlantRepository; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; @@ -33,8 +30,8 @@ public class TestService { // log.info("동기 알림 테스트 종료. Thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); // } - public void sendWaterNotificationAsyncRampTest() { - List petPlants = petPlantRepository.findAllByMemberId(6L); +// public void sendWaterNotificationAsyncRampTest() { +// List petPlants = petPlantRepository.findAllByMemberId(7L); // List events = petPlants.stream() // .map(plant -> NotificationEvent.builder() // .title(plant.getNickname()) @@ -43,39 +40,39 @@ public void sendWaterNotificationAsyncRampTest() { // .build() // ).toList(); - for (int i = 0; i < 100; i++) { - PetPlant petPlant = petPlants.get(i); - NotificationEvent event = NotificationEvent.builder() - .title(petPlant.getNickname()) - .body("물줘") - .deviceToken(petPlant.getMember().getDeviceToken()) - .build(); - publisher.publishEvent(event); - } +// for (int i = 0; i < 100; i++) { +// PetPlant petPlant = petPlants.get(i); +// NotificationEvent event = NotificationEvent.builder() +// .title(petPlant.getNickname()) +// .body("물줘") +// .deviceToken(petPlant.getMember().getDeviceToken()) +// .build(); +// publisher.publishEvent(event); +// } // log.info("비동기 테스트 램프업 시작"); // for (int i = 0; i < 100; i++) { // NotificationEvent notificationEvent = events.get(i); // publisher.publishEvent(notificationEvent); // } - } - - public void sendWaterNotificationAsyncTest() { - List petPlants = petPlantRepository.findAllByMemberId(6L); - List events = petPlants.stream() - .map(plant -> NotificationEvent.builder() - .title(plant.getNickname()) - .body("(테스트 중) 물을 줄 시간이에요!") - .deviceToken(plant.getMember().getDeviceToken()) - .build() - ).toList(); +// } - int i = 1; - log.info("비동기 알림 테스트 시작. Thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); - for (NotificationEvent event : events) { - log.info(i++ + "번째 알림 이벤트"); - publisher.publishEvent(event); - } - log.info("비동기 알림 테스트 종료. Thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); - } +// public void sendWaterNotificationAsyncTest() { +// List petPlants = petPlantRepository.findAllByMemberId(7L); +// List events = petPlants.stream() +// .map(plant -> NotificationEvent.builder() +// .title(plant.getNickname()) +// .body("(테스트 중) 물을 줄 시간이에요!") +// .deviceToken(plant.getMember().getDeviceToken()) +// .build() +// ).toList(); +// +// int i = 1; +// log.info("비동기 알림 테스트 시작. Thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); +// for (NotificationEvent event : events) { +// log.info(i++ + "번째 알림 이벤트"); +// publisher.publishEvent(event); +// } +// log.info("비동기 알림 테스트 종료. Thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); +// } } diff --git a/backend/pium/src/main/java/com/official/pium/admin/ui/TestController.java b/backend/pium/src/main/java/com/official/pium/admin/ui/TestController.java index 555d26df..1d0514a0 100644 --- a/backend/pium/src/main/java/com/official/pium/admin/ui/TestController.java +++ b/backend/pium/src/main/java/com/official/pium/admin/ui/TestController.java @@ -1,5 +1,6 @@ package com.official.pium.admin.ui; +import com.official.pium.admin.service.TestService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,13 +10,7 @@ @RequestMapping("/test") public class TestController { -// private final TestService testService; - -// @GetMapping("/notifications") -// public ResponseEntity notificationTest() { -// testService.sendWaterNotificationTest(); -// return ResponseEntity.ok("알림 기능 테스트 성공"); -// } + private final TestService testService; // @GetMapping("/notifications/ramp") // public ResponseEntity notificationRampTest() { diff --git a/backend/pium/src/main/java/com/official/pium/notification/fcm/application/FcmMessageSender.java b/backend/pium/src/main/java/com/official/pium/notification/fcm/application/FcmMessageSender.java index a595c90b..eba7f6dc 100644 --- a/backend/pium/src/main/java/com/official/pium/notification/fcm/application/FcmMessageSender.java +++ b/backend/pium/src/main/java/com/official/pium/notification/fcm/application/FcmMessageSender.java @@ -1,81 +1,64 @@ package com.official.pium.notification.fcm.application; import com.google.auth.oauth2.GoogleCredentials; -import com.official.pium.notification.fcm.dto.FcmMessageResponse; -import com.official.pium.notification.fcm.exception.FcmException; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; import com.official.pium.notification.application.MessageSendManager; +import jakarta.annotation.PostConstruct; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.concurrent.ExecutionException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; -import java.io.IOException; @Slf4j @Component @RequiredArgsConstructor public class FcmMessageSender implements MessageSendManager { - @Value("${fcm.api.url}") - private String apiUrl; - - @Value("${fcm.key.path}") - private String keyPath; - - @Value("${fcm.key.scope}") - private String keyScope; + @Value("${fcm.json.path}") + private String FCM_JSON_PATH; - private final RestTemplate restTemplate; - - public void sendMessageTo(String targetToken, String title, String body) { + @PostConstruct + public void initialize() { try { - FcmMessageResponse message = makeMessage(targetToken, title, body); - - HttpHeaders headers = new HttpHeaders(); - headers.set(HttpHeaders.AUTHORIZATION, "Bearer " + getAccessToken()); - headers.set(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8"); - - HttpEntity request = new HttpEntity<>(message, headers); + ClassPathResource resource = new ClassPathResource(FCM_JSON_PATH); + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(resource.getInputStream())) + .build(); - ResponseEntity postResult = restTemplate.postForEntity( - apiUrl, - request, - FcmMessageResponse.class - ); - - log.info("FCM 메시지 전송 성공: {}", postResult.getBody()); - - } catch (Exception e) { - log.error("FCM 메시지 전송 실패", e); - throw new FcmException.FcmMessageSendException(e.getMessage()); + if (FirebaseApp.getApps().isEmpty()) { + FirebaseApp.initializeApp(options); + } + } catch (FileNotFoundException e) { + log.error("파일을 찾을 수 없습니다. ", e); + } catch (IOException e) { + log.error("FCM 인증이 실패했습니다. ", e); } } - private FcmMessageResponse makeMessage(String targetToken, String title, String body) { - return FcmMessageResponse.builder() - .message(FcmMessageResponse.Message.builder() - .token(targetToken) - .notification(FcmMessageResponse.Notification.builder() - .title(title) - .body(body) - .image(null) - .build() - ) - .build() - ) - .validate_only(false) + public void sendMessageTo(String targetToken, String title, String body) { + Notification notification = Notification.builder() + .setTitle(title) + .setBody(body) .build(); - } - - private String getAccessToken() throws IOException { - GoogleCredentials googleCredentials = GoogleCredentials - .fromStream(new ClassPathResource(keyPath).getInputStream()) - .createScoped(keyScope); - googleCredentials.refreshIfExpired(); - return googleCredentials.getAccessToken().getTokenValue(); + Message message = Message.builder() + .setToken(targetToken) + .setNotification(notification) + .build(); + try { + String response = FirebaseMessaging.getInstance().sendAsync(message).get(); + log.info("알림 전송 성공 : " + response); + } catch (InterruptedException e) { + log.error("FCM 알림 스레드에서 문제가 발생했습니다.", e); + } catch (ExecutionException e) { + log.error("FCM 알림 전송에 실패했습니다.", e); + } } } diff --git a/backend/pium/src/main/resources/application.yml b/backend/pium/src/main/resources/application.yml index 5b1ccb8f..7d605ec1 100644 --- a/backend/pium/src/main/resources/application.yml +++ b/backend/pium/src/main/resources/application.yml @@ -27,11 +27,9 @@ management: endpoints: enabled-by-default: false fcm: - key: - path: test/ - scope: https://www.googleapis.com/auth/firebase.messaging - api: - url: https://fcm.googleapis.com/v1/projects/project-id/messages:send + json: + path: config/pium-fcm.json + petPlant: image: directory: test diff --git a/backend/pium/src/test/resources/application.yml b/backend/pium/src/test/resources/application.yml index f25c9199..8fc7a303 100644 --- a/backend/pium/src/test/resources/application.yml +++ b/backend/pium/src/test/resources/application.yml @@ -64,11 +64,8 @@ server: max-http-form-post-size: 10MB fcm: - key: + json: path: config/pium-fcm.json - scope: https://www.googleapis.com/auth/firebase.messaging - api: - url: https://fcm.googleapis.com/v1/projects/pium-test/messages:send management: endpoint: