부트캠프에서 최종 프로젝트 "동상이농"을 진행하며 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
'프로젝트 기록 > Spring' 카테고리의 다른 글
[Spring Data JPA] MariaDB에서의 동시성 이슈로 인한 갱신 이상 문제와 그 해결법(비관적 락, 낙관적 락) (2) | 2024.11.20 |
---|---|
[Spring / Redis] 이중화 서버에서의 웹 소켓 채팅 + SSE 알림 구현기 (11) | 2024.09.07 |
[Spring / Redis] @RedisHash 어노테이션을 붙인 객체를 레디스에 저장했을때, 그 값을 확인하는 방법 (0) | 2024.05.18 |
[Spring / Project] 응답 객체에서 상속 구조를 사용해보자 (0) | 2024.05.13 |