[Spring Boot] FCM을 통해 Push알림 보내기2

smlee·2023년 3월 30일
2

SpringBoot - JPA

목록 보기
7/8
post-thumbnail

이전 포스트에서 FCM의 동작 과정을 살펴볼 수 있었다. 이번 포스트에서는 FCM을 Spring Boot 코드에 적용하는 것을 실행하려 한다.

📨 Spring Boot로 FCM 푸쉬 알림 보내기

(1) firebase 프로젝트 설정

Firebase 프로젝트 콘솔에 들어가서 프로젝트를 생성 후 설정 파일을 받아야 한다.


클라이언트 앱은 안드로이드 이므로 안드로이드 플랫폼이 설정되어 있어야 한다. (프로젝트 생성 시 플랫폼에 안드로이드를 설정해야한다.)

필자는 첫 번째 프로젝트로 생성하여 첫번째 프로젝트를 클릭하면 된다.

그 후, 프로젝트 개요 옆에 있는 톱니바퀴 모양 > 프로젝트 설정 > 서비스 계정에 들어가서 Admin SDK 구성 스니펫에 자바를 클릭하고 새 비공개 키 생성 버튼을 누른다.

그러면 비공개 키 데이터가 들어가 있는 json 파일을 다운로드할 수 있다. 필자는 다운로드 받은 json파일을 스프링부트 프로젝트의 config 파일들을 모아놓는 디렉터리에 저장하였다.

(2) Spring Boot 프로젝트 설정

gradle 파일에 다음과 같은 의존성을 추가한다.

implementation 'com.google.firebase:firebase-admin:6.8.1'
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.2.2'

그 후, API_URL을 config 파일 내에 등록한다.
API_URL은 메시지 전송을 위해 요청하는 주소로, "https://fcm.googleapis.com/v1/projects/{프로젝트 ID}/messages:send"이다.

프로젝트 ID는 프로젝트 설정 > 프로젝트 ID이다. (아래 이미지의 빨간색 박스)

여기까지 완료되었다면, 본격적으로 메세지 요청을 수행하는 서비스를 작성한다. 메세지 전송 수행을 위해 (1) 메세지 전송(sendMessageTo), (2) 메세지 생성(makeMessage), (3) 메세지 전송을 위한 접근 토큰 발급(getAccessToken) 총 3개의 메서드가 필요하다.

(a) FCM Message DTO

가장 먼저 FCM 푸쉬를 보낼 때의 DTO이다.
Firebase 공식 문서 예시에는 Message 안에 Data라는 필드가 없지만,
필자가 진행한 프로젝트에서는 추가적인 데이터를 보내야 했으므로 Data 필드를 추가하였다.

@Builder
@AllArgsConstructor
@Getter
public class FCMMessageDto {
    private boolean    validateOnly;
    private Message    message;

    @Builder
    @AllArgsConstructor
    @Getter
    public static class Message {
        private Notification notification;
        private String      token;
        private Data        data;
    }

    @Builder
    @AllArgsConstructor
    @Getter
    public static class Notification {
        private String  title;
        private String  body;
    }

    @Builder
    @AllArgsConstructor
    @Getter
    public static class Data{
        private String    name;
        private String    description;
    }

}

Notification 객체에는 title과 body가 있다.
title에는 알림 상단부에 들어가는 제목이 들어간다. 필자는 프로젝트명을 title에 넣었고, body에는 알림 내용을 넣었다.

또한, 프론트 단에서 처리할 데이터를 Data 객체 내에 담아 보내도록 하였다.

(b) FCM Service

(a)의 메세지 dto를 사용하여 매세지를 생성(makeMessage)하고, 메세지 전송(sendMessageTo) 및 접근 토큰 발급(getAccessToken)을 담고 있는 서비스 단을 작성할 것이다.

가장 먼저 getAccessToken은 firebase로부터 access token을 가져온다.

그리고 makeMessage를 통해 알림 보낼 내용을 넣고, sendMessageTo를 통해 알림을 보낼 클라이언트 앱에 푸쉬를 보내주면 된다.

@Service
@Slf4j
public class FcmService {

    private final ObjectMapper      objectMapper;

    @Autowired
    public FcmService(ObjectMapper objectMapper){
        this.objectMapper = objectMapper;
    }

    private String      getAccessToken() throws IOException {
        // firebase로 부터 access token을 가져온다.

        GoogleCredentials   googleCredentials = GoogleCredentials
                .fromStream(new ClassPathResource(FIREBASE_CONFIG_PATH).getInputStream())
                .createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));

        googleCredentials.refreshIfExpired();

        return googleCredentials.getAccessToken().getTokenValue();

    }

    /**
     * makeMessage : 알림 파라미터들을 FCM이 요구하는 body 형태로 가공한다.
     * @param targetToken : firebase token
     * @param title : 알림 제목
     * @param body : 알림 내용
     * @return
     * */
    public String   makeMessage(
            String targetToken, String title, String body, String name, String description
    ) throws JsonProcessingException {

        FCMMessageDto   fcmMessage = FCMMessageDto.builder()
                .message(
                        FCMMessageDto.Message.builder()
                                .token(targetToken)
                                .notification(
                                        FCMMessageDto.Notification.builder()
                                                .title(title)
                                                .body(body)
                                                .build()
                                )
                                .data(
                                        FCMMessageDto.Data.builder()
                                                .id(name)
                                                .isEnd(description)
                                                .build()
                                )
                                .build()
                )
                .validateOnly(false)
                .build();

        return objectMapper.writeValueAsString(fcmMessage);

    }

    /**
     * 알림 푸쉬를 보내는 역할을 하는 메서드
     * @param targetToken : 푸쉬 알림을 받을 클라이언트 앱의 식별 토큰
     * */
    public void     sendMessageTo(
            String targetToken, String title, String body, String id, String isEnd
    ) throws IOException{

        String      message = makeMessage(targetToken, title, body, id, isEnd);

        OkHttpClient    client = new OkHttpClient();
        RequestBody     requestBody = RequestBody.create(message, MediaType.get("application/json; charset=utf-8"));

        Request         request = new Request.Builder()
                .url(FIREBASE_ALARM_SEND_API_URI)
                .post(requestBody)
                .addHeader(HttpHeaders.AUTHORIZATION, "Bearer "+getAccessToken())
                .addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
                .build();

        Response        response = client.newCall(request).execute();

        log.info(response.body().string());

        return;
    }

}

이렇게 서비스 단을 작성했으면, 푸쉬 알림을 사용하는 api에서 fcmService 클래스를 가져와 sendMessageTo로 푸쉬를 쏴주기만 하면 된다.

📚 Reference

Firebase 공식 문서 - 클라우드 메세징 > 서버 환경

0개의 댓글