import com.akc.b2c.common.push.service.IPushNotificationService;
import com.akc.b2c.common.push.dto.PushNotificationResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class YourService {
private final IPushNotificationService pushNotificationService;
}
// 회원 ID만 알면 끝!
PushNotificationResponse response = pushNotificationService.sendByMemberId(
222L, // 회원 ID
"주문 확정",
"주문번호 #12345가 확정되었습니다",
null
);
if (response.isSuccess()) {
log.info("전송 성공: {}", response.getMessageId());
}
| API | 사용 시점 | 커버리지 |
|---|---|---|
| #1 Token 단일 | 특정 디바이스 지정 전송 | 3% |
| #2 Token 다수 | 여러 디바이스 동시 전송 | 2% |
| #3 Token + 템플릿 | 템플릿 기반 단일 전송 | 3% |
| #4 Token 다수 + 템플릿 | 템플릿 멀티캐스트 | 2% |
| #5 회원 ID 단일 ⭐ | 개인화 알림 (가장 많이 사용) | 50% |
| #6 회원 ID 다수 | 대량 발송 (공지, 이벤트) | 20% |
| #7 회원 ID 단일 + 템플릿 | 템플릿 개인화 알림 | 15% |
| #8 회원 ID 다수 + 템플릿 | 템플릿 대량 발송 | 5% |
PushNotificationRequest request = PushNotificationRequest.builder()
.deviceToken("dpanRX1ZSkw...FCM_토큰")
.title("주문 확정")
.body("주문번호 #12345가 확정되었습니다")
.data(Map.of(
"orderId", "12345",
"deepLink", "amano://order/12345"
))
.build();
PushNotificationResponse response = pushNotificationService.send(request);
POST /api/notifications/push/send?memberId=222
Content-Type: application/json
{
"deviceToken": "dpanRX1ZSkw...FCM_토큰",
"title": "주문 확정",
"body": "주문번호 #12345가 확정되었습니다",
"data": {
"orderId": "12345",
"deepLink": "amano://order/12345"
}
}
PushNotificationRequest request = PushNotificationRequest.builder()
.deviceTokens(List.of("token1", "token2", "token3"))
.title("시스템 점검 안내")
.body("오늘 밤 11시부터 점검이 진행됩니다")
.build();
PushNotificationResponse response = pushNotificationService.send(request);
log.info("성공: {}, 실패: {}", response.getSuccessCount(), response.getFailureCount());
POST /api/notifications/push/send-multicast?memberId=222
Content-Type: application/json
{
"deviceTokens": ["token1", "token2", "token3"],
"title": "시스템 점검 안내",
"body": "오늘 밤 11시부터 점검이 진행됩니다"
}
특징:
${변수명} 형태로 사용Map<String, String> params = Map.of(
"orderNo", "20260117-001",
"orderDate", "2026-01-17",
"amount", "50,000"
);
PushNotificationResponse response = pushNotificationService.sendByTemplate(
"dpanRX1ZSkw...FCM_토큰",
"PUSH0001", // 템플릿 ID
params
);
POST /api/notifications/push/send-by-template?memberId=222
Content-Type: application/json
{
"deviceToken": "dpanRX1ZSkw...FCM_토큰",
"templateId": "PUSH0001",
"params": {
"orderNo": "20260117-001",
"orderDate": "2026-01-17",
"amount": "50,000"
}
}
| 템플릿 ID | 제목 | 내용 | 파라미터 |
|---|---|---|---|
| PUSH0001 | 주문 확정 | 주문번호 ${orderNo}가 확정되었습니다 | orderNo, amount |
| PUSH0002 | 이벤트 알림 | ${eventName} - ${discount} 할인! | eventName, discount |
| PUSH0003 | 결제 완료 | ${amount}원 결제가 완료되었습니다 | amount, method |
**템플릿 (PUSH0001) DB 저장 내용 **:
{
"templateId": "PUSH0001",
"title": "주문 확정",
"body": "주문번호 ${orderNo}가 확정되었습니다. 금액: ${amount}원",
"dataKeys": {
"orderId": "${orderNo}",
"deepLink": "amano://order/${orderNo}",
"amount": "${amount}"
}
}
전송 코드:
Map<String, String> params = Map.of(
"orderNo", "20260117-001",
"amount", "50,000"
);
pushNotificationService.sendByTemplate(token, "PUSH0001", params);
실제 전송되는 메시지:
{
"title": "주문 확정",
"body": "주문번호 20260117-001가 확정되었습니다. 금액: 50,000원",
"data": {
"orderId": "20260117-001",
"deepLink": "amano://order/20260117-001",
"amount": "50,000"
}
}
💡 중요: title, body뿐만 아니라 data 필드의 값들도 모두 변수 치환됩니다!
언제? 특정 디바이스 그룹에 템플릿 메시지 전송
List<String> deviceTokens = List.of("token1", "token2", "token3");
Map<String, String> params = Map.of(
"eventName", "VIP 전용 이벤트",
"discount", "30%"
);
PushNotificationResponse response = pushNotificationService.sendMulticastByTemplate(
deviceTokens,
"PUSH0002", // 템플릿 ID
params
);
POST /api/notifications/push/send-multicast-by-template?memberId=222
Content-Type: application/json
{
"deviceTokens": ["token1", "token2", "token3"],
"templateId": "PUSH0002",
"params": {
"eventName": "VIP 전용 이벤트",
"discount": "30%"
}
}
언제? 주문, 결제, 쿠폰 지급 등 개인화 알림
장점:
Map<String, String> data = Map.of(
"couponId", "CP001",
"deepLink", "amano://coupon/CP001"
);
PushNotificationResponse response = pushNotificationService.sendByMemberId(
222L, // 회원 ID
"🎁 쿠폰 지급 완료",
"5,000원 할인 쿠폰이 지급되었습니다",
data
);
POST /api/notifications/push/send-to-all-devices?memberId=222
Content-Type: application/json
{
"title": "🎁 쿠폰 지급 완료",
"body": "5,000원 할인 쿠폰이 지급되었습니다",
"data": {
"couponId": "CP001",
"deepLink": "amano://coupon/CP001"
}
}
// 주문 확정 시
orderService.confirmOrder(orderId);
pushNotificationService.sendByMemberId(
order.getMemberId(),
"주문 확정",
"주문번호 #" + orderId + "가 확정되었습니다",
Map.of("orderId", orderId.toString())
);
// 결제 완료 시
paymentService.completePayment(paymentId);
pushNotificationService.sendByMemberId(
payment.getMemberId(),
"결제 완료",
payment.getAmount() + "원 결제가 완료되었습니다",
Map.of("paymentId", paymentId.toString())
);
언제? 공지사항, 이벤트, VIP 혜택 등 여러 회원에게 일괄 전송
List<Long> vipMembers = memberRepository.findVipMemberIds();
PushNotificationResponse response = pushNotificationService.sendByMemberIds(
vipMembers,
"💎 VIP 전용 혜택",
"VIP 회원님께 특별 할인 쿠폰을 드립니다",
Map.of("vipLevel", "GOLD")
);
POST /api/notifications/push/send-to-multiple-users
Content-Type: application/json
{
"memberIds": [100, 200, 300],
"title": "시스템 점검 안내",
"body": "금일 23:00 ~ 01:00 시스템 점검이 진행됩니다"
}
// 이벤트 당첨자 발표
List<Long> winners = eventService.getWinners(eventId);
pushNotificationService.sendByMemberIds(
winners,
"🎉 축하합니다! 당첨되셨습니다",
"신년 이벤트 추첨 결과 당첨되셨습니다",
Map.of("eventId", eventId.toString())
);
// 쿠폰 만료 알림 (만료 7일 전)
List<Long> expiringMembers = couponService.getMembersWithExpiringCoupons();
pushNotificationService.sendByMemberIds(
expiringMembers,
"⏰ 쿠폰 만료 임박",
"7일 후 쿠폰이 만료됩니다. 지금 사용하세요!",
null
);
언제? 템플릿을 사용한 개인화 알림 (주문, 결제 등)
Map<String, String> params = Map.of(
"orderNo", "20260117-001",
"amount", "50,000"
);
PushNotificationResponse response = pushNotificationService.sendByMemberIdWithTemplate(
222L, // 회원 ID
"PUSH0001", // 템플릿 ID
params
);
POST /api/notifications/push/send-by-member-template?memberId=222
Content-Type: application/json
{
"templateId": "PUSH0001",
"params": {
"orderNo": "20260117-001",
"amount": "50,000"
}
}
// 주문 확정 (템플릿 사용)
Map<String, String> params = Map.of(
"orderNo", order.getOrderNo(),
"orderDate", order.getCreatedAt().format(DateTimeFormatter.ISO_DATE),
"amount", String.valueOf(order.getTotalAmount())
);
pushNotificationService.sendByMemberIdWithTemplate(
order.getMemberId(),
"PUSH0001", // 주문 확정 템플릿
params
);
언제? 템플릿을 사용한 대량 발송 (이벤트, VIP 혜택 등)
List<Long> vipMembers = memberRepository.findVipMemberIds();
Map<String, String> params = Map.of(
"eventName", "VIP 전용 이벤트",
"discount", "30%",
"endDate", "2026-01-31"
);
PushNotificationResponse response = pushNotificationService.sendByMemberIdsWithTemplate(
vipMembers,
"PUSH0002", // 이벤트 템플릿
params
);
POST /api/notifications/push/send-to-multiple-users-by-template
Content-Type: application/json
{
"memberIds": [100, 200, 300],
"templateId": "PUSH0002",
"params": {
"eventName": "VIP 전용 이벤트",
"discount": "30%",
"endDate": "2026-01-31"
}
}
// 쿠폰 만료 알림 (템플릿 사용)
List<Long> expiringMembers = couponService.getMembersWithExpiringCoupons();
Map<String, String> params = Map.of(
"days", "7",
"couponName", "신규가입 쿠폰"
);
pushNotificationService.sendByMemberIdsWithTemplate(
expiringMembers,
"PUSH0004", // 쿠폰 만료 템플릿
params
);