fcm 이용해서 앱 푸쉬 구현

2024. 12. 4. 21:25·Dev

 

의존성

spring boot 버전 : 2.7.7
implementation 'com.google.firebase:firebase-admin:9.1.0'

 

 

https://firework-ham.tistory.com/111
Google Firebase에서 새로운 프로젝트를 생성하고 새로운 비공개 키를 다운받습니다.

  1. Client에서 Firebase 서버에 요청을 해서 Token을 발급받습니다.
  2. 우리 서버에 Client에서 발급 받은 Token을 저장합니다.
  3. 서버에서 Push 알림을 보내야할 때 Token과 Message를 만들어서 Firebase 서버에 전송합니다.
  4. Firebase 서버에서 Push 알림을 Device에 전송합니다.

구현

일단 firebase 프로젝트를 만들면서 생성된 json파일을 resources 폴더에 복사해서 저장해줍니다.

의존성 추가

fcm 토큰은 회원가입시 client에서 넘겨줘서 db에 저장하는 방식으로 저장했습니다.

 

 

fcm DTO 만들기

@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FcmMessage {

    private boolean validateOnly;
    private Message message;

    @Builder
    @Getter
    @AllArgsConstructor(access = AccessLevel.PROTECTED)
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public static class Message{
        private Notification notification;
        private String token;
    }


    @Builder
    @Getter
    @AllArgsConstructor(access = AccessLevel.PROTECTED)
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    public static class Notification{
        private String title;
        private String body;
    }
}

메세지 만드는 로직

FCM 메시지를 생성하여 JSON 문자열로 변환합니다.

    private String makeMessage(String targetToken, String title, String body) throws JsonParseException, JsonProcessingException {
        FcmMessage fcmMessage = FcmMessage.builder()
                .message(
                        FcmMessage.Message.builder()
                                .token(targetToken)
                                .notification(FcmMessage.Notification.builder()
                                        .title(title)
                                        .body(body).build())
                                .build())
                                        .validateOnly(false).build();
        return objectMapper.writeValueAsString(fcmMessage);
    }

 

FCM 액세스 토큰을 가져옵니다.

    private String getAccessToken() throws IOException{
        String fireBaseConfigPath = "firebase/sm-project-firebase.json";

        try{
        //설정 파일에서 자격 증명을 로드하고, 필요한 권한 범위로 설정
        GoogleCredentials googleCredentials = GoogleCredentials
                .fromStream(new ClassPathResource(fireBaseConfigPath).getInputStream())
                .createScoped(List.of("https://www.googleapis.com/auth/cloud-platform"));
        googleCredentials.refreshIfExpired();
        //액세스 토큰을 반환, 자격 증명이 만료된 경우 갱신합니다. 
        return googleCredentials.getAccessToken().getTokenValue();
    } catch (IOException e) {
        throw new FcmHandler(ErrorStatus.FCM_REQUEST_TOKEN_ERROR);
    }
 }

 

FCM에 메시지를 보내는 기능
Feign Client를 이용해서 FCM에 메세지를 보냅니다.

@Transactional
    public void sendMessage(String targetToken, String title, String body) throws IOException {
        String aosMessage = makeMessage(targetToken, title, body);

        FcmResponseDTO fcmResponse = fcmFeignClient.getFCMResponse("Bearer " + getAccessToken(),aosMessage);
        logger.info("성공? : {}",fcmResponse);
        logger.info("보낸 메세지 : {}",aosMessage);
    }

 

FCM에 요청 보내기

@FeignClient(name = "FcmFeignClient", url = "https://fcm.googleapis.com", configuration = FcmFeignConfiguration.class)
@Component
public interface FcmFeignClient {


    @PostMapping("/v1/projects/sm-project-ea2a9/messages:send")
    FcmResponseDTO getFCMResponse(@RequestHeader("Authorization") String token, @RequestBody String fcmMessage);
}

테스트 컨트롤러

실제로 이 기능은 일정 시간마다 실행하는 @Scheduled를 이용하지만 테스트를 위해서 컨트롤러를 만들어서 테스트해보았습니다.

//controller
@PostMapping("/fcm/send")
@Operation(summary = "앱 푸쉬 전송 api", description = "")
public ResponseDTO<?> pushMessage() throws IOException {

        //Member member = memberQueryService.findMemberById(Long.valueOf(authentication.getName().toString())).orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND));
        memberService.sendPushAlarm();

        return ResponseDTO.of(SuccessStatus.MEMBER_PUSH_SUCCESS,null);
    }

//service
@Scheduled(cron = "0 0 17 * * ?")
public void sendPushAlarm() throws IOException {
        List<Refrigerator> refrigeratorList = refrigeratorRepository.findAll();
        Map<String,Integer> map = new HashMap<>();
        Date currentTime = new Date();

        refrigeratorList.stream().forEach(refrigerator -> {
            foodRepository.findTop5ByRefrigeratorOrderByExpireDesc(refrigerator).stream().forEach(food -> {
                map.put(food.getName(), (int) (currentTime.getTime() - food.getExpire().getTime()));
            });
            try {
                String result = map.entrySet().stream()
                        .map(entry -> entry.getKey() + "의 유통기한: " + entry.getValue() + "일 남음")
                        .collect(Collectors.joining("\n"));
                Member member = memberRepository.findByMemberRefrigeratorListContaining(refrigerator);
                fcmService.sendMessage(member.getFcmTokenList().get(0).getToken(),"유통기한이 곧 지나는 식품들입니다.",result);

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });



    }

'Dev' 카테고리의 다른 글

GCP에 ElasticSearch 띄워서 검색 기능 구현하기  (2) 2024.12.04
위치 기반으로 글 조회 기능 구현  (1) 2024.12.04
소켓 통신(채팅방 구현)  (0) 2024.12.04
OCR로 영수증 데이터 가져와서 식품 데이터 분류하기(분류 모델 만들기) + Trouble shooting  (0) 2024.12.04
ElasticSearch로 검색 성능 높이기  (0) 2024.12.04
'Dev' 카테고리의 다른 글
  • GCP에 ElasticSearch 띄워서 검색 기능 구현하기
  • 위치 기반으로 글 조회 기능 구현
  • 소켓 통신(채팅방 구현)
  • OCR로 영수증 데이터 가져와서 식품 데이터 분류하기(분류 모델 만들기) + Trouble shooting
khjoon
khjoon
  • khjoon
    기록기록
    khjoon
  • 전체
    오늘
    어제
    • 분류 전체보기 (37)
      • Security (2)
      • Dev (14)
      • Infra (12)
      • Ops (9)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
khjoon
fcm 이용해서 앱 푸쉬 구현
상단으로

티스토리툴바