본문 바로가기
프로젝트 기록/Spring

[Spring / FCM] FCM 웹 푸시 알림 구현기 (서버 편)

by clean01 2024. 9. 22.

부트캠프에서 최종 프로젝트 "동상이농"을 진행하며 FCM을 이용한 알림 기능을 맡게 되었습니다.

해당 기능을 구현한 과정을 기록해보고자 합니다.

 

1. 비공개 키 생성

프로젝트 설정 > 서비스 계정 > 자바로 들어간 후, 하단에 있는 "새 비공개 키 생성" 버튼을 눌러 비공개키를 다운 받아줍니다.

 

다운 받은 비공개 키는 resources로 옮겨줍니다!

동상이농의 서버는 MSA 구조로 되어있는데, 멤버 모듈에서 FCM 알림을 처리할 예정이므로, 멤버 모듈의 resources에 넣어주었습니다.

 

2. 스프링 프로젝트에 firebase 의존성 추가

build.gradle에 해당 의존성을 추가해줍니다

dependencies {
  implementation 'com.google.firebase:firebase-admin:9.3.0'
}

 

3. 파이어베이스 앱 초기화 시키기

파이어베이스 앱 초기화 코드를 어디에 넣을까 하다가 그냥 FcmConfig라는 빈을 하나 만들어주었습니다.

굳이 이렇게 할 필욘 없지만, 혹시 추후에 FCM에 대한 설정이 늘어날 수도 있지 않을까 싶은 생각에 이렇게 만들었습니다.

 

secretFileName에는 시크릿 파일의 경로가 들어가면 되는데,

저는 해당 파일을 resoruces 바로 밑에 넣었으므로, 그냥 json 파일의 이름을 넣어주면 됩니다!

@Configuration
public class FcmConfig {
    @Value("${fcm.secret-file}")
    private String secretFileName;

    @PostConstruct
    public void initialize() {
        try {
            GoogleCredentials googleCredentials = GoogleCredentials
                    .fromStream(new ClassPathResource(secretFileName).getInputStream());
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(googleCredentials)
                    .build();
            FirebaseApp.initializeApp(options);
        } catch(FileNotFoundException e) {
            throw new BaseCustomException(SECRET_FILE_NOT_FOUND);
        } catch(IOException e) {
            throw new BaseCustomException(INVALID_SECRET_FILE);
        }

    }
}

 

4. 토큰을 저장할 수 있는 API를 만들자

FCM은 프론트에서 알림을 보낼 수 있는 토큰을 발급받은 후

그 토큰을 서버로 보내서 서버가 DB에 해당 키를 저장해놓고 알림을 보낼 때마다 DB에서 해당 키를 조회해서 이용하는 설계가 많은 것 같습니다.

 

따라서 Member entity에 fcmToken을 저장할 수 있도록 컬럼을 하나 만들어주고

 

Member.java

 

클라이언트로부터 받아온 fcm token을 저장해주는 API를 작성해줍니다.

 

FcmController.java

@RequiredArgsConstructor
@RequestMapping("/fcm")
@RestController
public class FcmController {
    private final FcmService fcmService;
    @PostMapping("/token")
    public ResponseEntity<Void> saveFcmToken(@RequestHeader Long myId,
                                             @RequestBody @Valid FcmTokenSaveRequest fcmTokenSaveRequest) {
        fcmService.saveFcmToken(myId, fcmTokenSaveRequest);
        return ResponseEntity.ok(null);
    }
}

 

FcmService.java

@RequiredArgsConstructor
@Service
public class FcmService {
    private final MemberRepository memberRepository;
    @Transactional
    public void saveFcmToken(Long memberId, FcmTokenSaveRequest fcmTokenSaveRequest) {
        Member member = memberRepository.findByIdOrThrow(memberId);
        member.updateFcmToken(fcmTokenSaveRequest.fcmToken());

    }
}

 

5. 알림을 보내는 API를 짜보자

이제 모든 세팅이 끝났습니다!

알림을 보내는 테스트 API를 짜보고 클라이언트에게 알림을 보내보겠습니다.

 

멤버 아이디가 myId인 사용자에게 테스트 알림을 보내는 API입니다.

 

FcmController.java

    // TODO: 추후 삭제 예정 (테스트용)
    @PostMapping("/test/notice")
    public ResponseEntity<Void> testNotification(@RequestHeader Long myId) {
        fcmService.sendTestMessage(myId);
        return ResponseEntity.ok(null);
    }

 

FcmService.java

    public void sendTestMessage(Long myId) {
        Member member = memberRepository.findByIdOrThrow(myId);
        String token = member.getFcmToken();

        if(token == null || token.isEmpty()) {
            throw new BaseCustomException(FCM_TOKEN_NOT_FOUND);
        }

        Message message = Message.builder()
                .setWebpushConfig(WebpushConfig.builder()
                        .setNotification(WebpushNotification.builder()
                                .setTitle("알림 제목")
                                .setBody("알림 내용")
                                .build())
                        .build())
                .setToken(token)
                .build();

        try {
            FirebaseMessaging.getInstance().sendAsync(message);
        } catch(Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
            throw new BaseCustomException(FCM_SEND_FAIL);
        }

 

포스트맨으로 테스트

우선 2번 사용자에게 fcm token을 저장해주었습니다.

 

그리고 2번 사용자에게 테스트 알림을 전송해보았습니다.

브라우저에서 알림이 잘 받아지는 것을 확인할 수 있었습니다.

 

 

다음은 Vue.js로 FCM 토큰을 발급받고, 서버가 보낸 알림을 수신하는 코드를 어떻게 작성했는지 포스팅 해보고자 합니다!

 

도움이 되셨다면 댓글과 좋아요 부탁드립니다~

 

 

Reference

https://firebase.google.com/docs/admin/setup?hl=ko&authuser=0&_gl=1*142f82t*_ga*OTAxMTEyODUzLjE3MjY5MDk1OTU.*_ga_CW55HF8NVT*MTcyNjkwOTU5NS4xLjEuMTcyNjkxMDYyMy42MC4wLjA.#java

 

서버에 Firebase Admin SDK 추가

Admin SDK는 권한이 있는 환경에서 Firebase와 상호작용할 수 있는 서버 라이브러리 집합입니다.

firebase.google.com