μ΄ νλ‘μ νΈλ Spring Boot νλ μμν¬λ₯Ό μ¬μ©νμ¬ κ΅¬μΆλ Firebase Cloud Messaging(FCM) νΈμ μλ¦Όμ μ μ‘νκΈ° μν κ°λ ₯ν μλΉμ€μ λλ€. Android λ° iOS κΈ°κΈ°μ νΈμ μλ¦Όμ μμ μ μΌλ‘ λκΈ°μ΄μ λ£κ³ λ°μ‘ν΄μΌ νλ μλ리μ€λ₯Ό μν΄ μ€κ³λμμ΅λλ€.
μ£Όμ κΈ°λ₯:
- Spring Boot ν΅ν©: μλ ꡬμ±, μμ‘΄μ± κ΄λ¦¬ λ° λ°°ν¬ μ©μ΄μ±μ μν΄ Spring Bootλ₯Ό νμ©ν©λλ€.
- λΉλκΈ° μ μ‘: λΆν μν©μμλ μ ν리μΌμ΄μ
μ μλ΅μ±μ μ μ§νκΈ° μν΄ Springμ
@AsyncκΈ°λ₯μ νμ©ν λ ΌλΈλ‘νΉ νΈμ μλ¦Ό λ°μ‘. - λκΈ°μ΄ κΈ°λ° μ²λ¦¬: νΈμ λ©μμ§κ° μ μ₯λκ³ μ²΄κ³μ μΌλ‘ μ²λ¦¬λλ λκΈ°μ΄ λ©μ»€λμ¦(λ°μ΄ν°λ² μ΄μ€ ꡬν νμ)κ³Ό ν¨κ» μλνλλ‘ μ€κ³.
- ν¬λ‘μ€ νλ«νΌ μ§μ: FCMμ ν΅ν΄ Androidμ iOS νλ«νΌ λͺ¨λμ μλ¦Όμ ν¬λ§·ν νκ³ μ μ‘νλ λ‘μ§ ν¬ν¨.
- κ΅¬μ± κ°λ₯: FCM μλ² μΈλΆ μ 보 λ° μμ
μ€ν λ§€κ°λ³μλ
application.propertiesμ Java ꡬμ±μ ν΅ν΄ μΈλΆνλ¨.
μ΄ μλΉμ€λ λ€μκ³Ό κ°μ μ£Όμ κ΅¬μ± μμλ‘ μ΄λ£¨μ΄μ Έ μμ΅λλ€:
PushScheduleBean: λκΈ°μ΄μμ μ²λ¦¬ν΄μΌ ν 보λ₯ μ€μΈ νΈμ μλ¦Όμ μ£ΌκΈ°μ μΌλ‘ νμΈνλ Spring κ΄λ¦¬ λΉ(μΌλ°μ μΌλ‘@Scheduledμ»΄ν¬λνΈμ΄λ, μ΄ λ²μ μμλ μ€μΌμ€λ§ μ΄λ Έν μ΄μ μ΄ μΆκ°λμ§ μμ).PushDispatchService: κ°λ³ νΈμ μλ¦Όμ μ€μ μ²λ¦¬ λ° μ μ‘μ λ΄λΉνλ Spring@Service. μ€μΌμ€λ¬λ API μ€λ λκ° μ°¨λ¨λλ κ²μ λ°©μ§νκΈ° μν΄ Springμ@Async("taskExecutor")κΈ°λ₯μ μ¬μ©νμ¬ μ΄λ¬ν μμ μ λΉλκΈ°μ μΌλ‘ μν.PushSendService(μΈν°νμ΄μ€): νΈμ μλ¦Όκ³Ό κ΄λ ¨λ λ°μ΄ν° μ‘μΈμ€ μμ μ μν κ³μ½μ μ μ. λκΈ° μ€μΈ λ©μμ§ μ°ΎκΈ°, μν μ λ°μ΄νΈ(μ: WAIT, ING, COMPLETE, FAILED) λ° νΈμ μλ λ‘κΉ μ μν λ©μλ ν¬ν¨. μ ν리μΌμ΄μ μ΄ μμ ν μλνλ €λ©΄ μ΄ μΈν°νμ΄μ€μ ꡬν(μ: Spring Data JPA λλ MyBatis μ¬μ©)μ΄ νμν©λλ€.MyMap(μμ ν΄λμ€): νμ¬ μ΄ ν΄λμ€λHashMap<String, Object>λ₯Ό νμ₯νλ©° μ»΄ν¬λνΈ κ° λ°μ΄ν° μ μ‘μ μ¬μ©λ©λλ€.getString()κ³ΌgetInt()κ°μ ν¬νΌ λ©μλλ₯Ό ν¬ν¨ν©λλ€. λ λμ νμ μμ μ±κ³Ό μ μ§λ³΄μμ±μ μν΄MyMapμ¬μ©μ νΉμ λ°μ΄ν° μ μ‘ κ°μ²΄(DTO)λ‘ λ체νλ κ²μ΄ κ°λ ₯ν κΆμ₯λ©λλ€.- Spring Framework: μμ‘΄μ± μ£Όμ , μ»΄ν¬λνΈ κ΄λ¦¬ λ° λΉλκΈ° μ€νμ μν ν΅μ¬ νλ μμν¬.
- RestTemplate: FCM μλ²μ HTTP POST μμ²μ 보λ΄λ λ° μ¬μ©.
- Jackson: FCMμ© Java κ°μ²΄λ₯Ό JSON νμ΄λ‘λλ‘ μ§λ ¬ννκ³ FCM μλ΅μ μμ§λ ¬ννλ λ° μ¬μ©.
μ ν리μΌμ΄μ
ꡬμ±μ μ£Όλ‘ src/main/resources/application.propertiesμμ κ΄λ¦¬λ©λλ€.
ꡬμ±ν΄μΌ ν μ£Όμ μμ±:
-
FCM μλ² ν€:
fcm.server.key=YOUR_FCM_SERVER_KEY(Firebase μ½μμμ λ°μ μ€μ FCM μλ² ν€λ‘YOUR_FCM_SERVER_KEYλ₯Ό λ체νμΈμ.) -
FCM μλ² URL:
fcm.server.url=https://fcm.googleapis.com/fcm/send(μ΄λ νμ€ FCM λ κ±°μ HTTP API μλν¬μΈνΈμ λλ€. FCM v1 APIλ₯Ό μ¬μ©νλ κ²½μ° μ΄ URLμ΄ λ³κ²½λ©λλ€.) -
λΉλκΈ° μμ μ€νκΈ°: λΉλκΈ° μμ μ€νκΈ°λ
syworks.base.config.AsyncConfig.javaμμ ꡬμ±λ©λλ€. μ΄ Java κ΅¬μ± ν΄λμ€μμ μ§μ μ½μ΄ ν ν¬κΈ°, μ΅λ ν ν¬κΈ° λ° λκΈ°μ΄ μ©λκ³Ό κ°μ λ§€κ°λ³μλ₯Ό μ‘°μ ν μ μμ΅λλ€.// AsyncConfig.java μμ executor.setCorePoolSize(5); executor.setMaxPoolSize(10); executor.setQueueCapacity(25); executor.setThreadNamePrefix("PushNotifier-");
- Java: λ²μ 11 (
pom.xmlμ λͺ μλ¨). - Maven: νλ‘μ νΈ λΉλμ©.
- FCM μλ² ν€: Firebase νλ‘μ νΈ μ½μμμ μ»μ μ μμ.
- λ°μ΄ν°λ² μ΄μ€ λ°
PushSendServiceꡬν: λ©μμ§λ₯Ό λκΈ°μ΄μ λ£κ³ μλλ₯Ό λ‘κΉ νκΈ° μν λ°μ΄ν°λ² μ΄μ€κ° νμν©λλ€. μ νν λ°μ΄ν°λ² μ΄μ€ κΈ°μ κ³Ό μνΈ μμ©νκΈ° μν΄PushSendServiceμΈν°νμ΄μ€μ ꡬνμ μ 곡ν΄μΌ ν©λλ€.
-
application.propertiesꡬμ±:fcm.server.keyμ€μ .PushSendServiceꡬνμ νμν κ²½μ° λ°μ΄ν°λ² μ΄μ€ μ°κ²° μμ± μ€μ (μ΄ κΈ°λ³Έ νλ‘μ νΈμμλ λ€λ£¨μ§ μμ).
-
νλ‘μ νΈ λΉλ:
mvn clean package
-
μ ν리μΌμ΄μ μ€ν:
java -jar target/push-application-0.0.1-SNAPSHOT.jar
(μ€μ μν°ν©νΈ μ΄λ¦μ΄ λ€λ₯Έ κ²½μ°
push-application-0.0.1-SNAPSHOT.jarλ₯Ό ν΄λΉ μ΄λ¦μΌλ‘ λ체νμΈμ.)
μ°Έκ³ : μ ν리μΌμ΄μ
μ μμλμ§λ§, PushSendServiceμ ꡬ체μ μΈ κ΅¬νμ΄ μ 곡λκ³ Spring λΉμΌλ‘ ꡬμ±λ λκΉμ§ νΈμ μ€μΌμ€λ§ λ° μ μ‘ κΈ°λ₯μ΄ μ λλ‘ μλνμ§ μμ΅λλ€.
-
PushApplication.java(syworks.base.PushApplication): λ©μΈ Spring Boot μ ν리μΌμ΄μ ν΄λμ€. λΉλκΈ° μ²λ¦¬λ₯Ό νμ±ννκΈ° μν΄@SpringBootApplicationκ³Ό@EnableAsyncλ‘ μ΄λ Έν μ΄μ μ΄ λ¬λ € μμ΅λλ€. -
AsyncConfig.java(syworks.base.config.AsyncConfig):PushDispatchServiceμ μμ κ³Ό κ°μ λΉλκΈ° μμ μ μ€ννλ λ° μ¬μ©λλThreadPoolTaskExecutorλΉ(taskExecutor)μ μ μνλ Spring@Configurationν΄λμ€. -
PushScheduleBean.java(syworks.base.scheduler.PushScheduleBean): μ€μΌμ€λ§λλλ‘ μλλ μλΉμ€ λΉ.PushSendServiceλ₯Ό μ¬μ©νμ¬ λκΈ° μ€μΈ νΈμ λ©μμ§λ₯Ό μ‘°νν λ€μPushDispatchServiceμ μ μ‘μ μμν©λλ€. -
PushDispatchService.java(syworks.base.service.PushDispatchService): μ΄ μλΉμ€λ νΈμ μλ¦Όμ μ μ‘νκΈ° μν ν΅μ¬ λ‘μ§μ ν¬ν¨ν©λλ€. FCM λ©μμ§λ₯Ό ꡬμ±νκ³ ,RestTemplateμ ν΅ν΄ μ μ‘νλ©°,PushSendServiceλ₯Ό μ¬μ©νμ¬ κ²°κ³Όλ₯Ό κΈ°λ‘ν©λλ€.sendPushNotificationλ©μλλ λΉλκΈ°μμ λλ€. -
PushSendService.java(μΈν°νμ΄μ€) (syworks.base.service.PushSendService): μ ν리μΌμ΄μ μ νμν λ°μ΄ν° μ‘μΈμ€ λ©μλλ₯Ό μ μνλ μΈν°νμ΄μ€(μ:findPushStatus,getOldestWatingMsg,updateStatus,insertPushLog). ꡬ체μ μΈ κ΅¬νμ΄ νμν©λλ€. -
MyMap.java(syworks.base.common.MyMap): λ°μ΄ν° μ μ‘μ μ¬μ©λλHashMapμ νμ₯νλ μμ ν΄λμ€μ λλ€. μ½λ νμ§κ³Ό μ μ§λ³΄μμ± ν₯μμ μν΄ νλ‘λμ νκ²½μμλ κ°λ ₯ν νμ μ DTOλ‘ λ체νλ κ²μ΄ κΆμ₯λ©λλ€.
PushSendServiceꡬν: λ©μμ§ λκΈ°μ΄ λ° λ‘κΉ μ μν λ°μ΄ν°λ² μ΄μ€μ μνΈ μμ©νκΈ° μν΄PushSendServiceμ ꡬ체μ μΈ κ΅¬ν(μ: Spring Data JPA, JDBC λλ MyBatis μ¬μ©) μ 곡.MyMapμ DTOλ‘ λ체: νμ μμ μ±κ³Ό μ½λ λͺ νμ±μ κ°μ νκΈ° μν΄ μλΉμ€ κ³μΈ΅ κ° λ°μ΄ν° μ λ¬μ μν λ°μ΄ν° μ μ‘ κ°μ²΄(DTO) λμ .- ν¬κ΄μ μΈ μ€λ₯ μ²λ¦¬: μΌμμ μΈ FCM μ μ‘ μ€ν¨μ λν μ¬μλ λ©μ»€λμ¦μ ν¬ν¨ν μ€λ₯ μ²λ¦¬ κ°μ .
- FCM v1 API: λ λ§μ κΈ°λ₯κ³Ό λ λμ 보μμ μν΄ λ κ±°μ FCM HTTP APIμμ μλ‘μ΄ FCM HTTP v1 APIλ‘ λ§μ΄κ·Έλ μ΄μ (νμ΄λ‘λ ꡬ쑰 λ° μΈμ¦ λ³κ²½ νμ).
- λ°λ λ ν° ν: μ§μμ μΌλ‘ μ μ‘μ μ€ν¨νλ λ©μμ§λ₯Ό μ²λ¦¬νκΈ° μν μ λ΅ κ΅¬ν.
- μ€μΌμ€λ§ ꡬμ±:
PushScheduleBeanμ@Scheduledμ΄λ Έν μ΄μ μ μΆκ°νκ³ cron ννμμapplication.propertiesλ₯Ό ν΅ν΄ κ΅¬μ± κ°λ₯νκ² λ§λ€κΈ°. - λͺ¨λν°λ§ λ° λ©νΈλ¦: νΈμ λκΈ°μ΄ λ° μ μ‘ μλ λͺ¨λν°λ§μ μν΄ Spring Boot Actuator λλ Micrometerμ ν΅ν©.
- λ¨μ λ° ν΅ν© ν μ€νΈ νμ₯: ν μ€νΈ λ°μ΄ν°λ² μ΄μ€(μ: H2)μμ μνΈ μμ©μ ν¬ν¨νλ ν΅ν© ν μ€νΈλ₯Ό ν¬ν¨ν λ ν¬κ΄μ μΈ ν μ€νΈ μΆκ°.
- 보μ: FCM μλ² ν€ κ΄λ¦¬μ κ΄λ ¨λ 보μ μΈ‘λ©΄ κ²ν λ° κ°ν(μ: Spring Cloud Config λλ νκ²½ λ³μ μ¬μ©).