PushNotificationService.java 8.23 KB
package com.ecommerce.notification.service;

import com.ecommerce.notification.model.Notification;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class PushNotificationService {
    
    private final ObjectMapper objectMapper;
    
    public boolean sendPushNotification(Notification notification) {
        try {
            String title = notification.getSubject();  // 使用 subject 作为标题
            String body = notification.getContent();   // 使用 content 作为内容
            
            // 将 metadata 字符串转换为 Map
            Map<String, Object> metadata = convertMetadataToMap(notification.getMetadata());
            
            // 根据类型发送推送通知
            switch (notification.getType().toUpperCase()) {
                case "PUSH":
                case "FCM":
                    return sendViaFcm(notification.getDeviceToken(), title, body, metadata);
                case "APNS":
                    return sendViaApns(notification.getDeviceToken(), title, body, metadata);
                case "WEB_PUSH":
                    return sendViaWebPush(notification.getDeviceToken(), title, body, metadata);
                case "IN_APP":
                    return sendInAppNotification(notification.getUserId(), title, body, metadata);
                default:
                    log.warn("Unsupported push notification type: {}", notification.getType());
                    return false;
            }
        } catch (Exception e) {
            log.error("Failed to send push notification: {}", e.getMessage());
            return false;
        }
    }
    
    private boolean sendViaFcm(String deviceToken, String title, String body, Map<String, Object> metadata) {
        try {
            if (deviceToken == null || deviceToken.trim().isEmpty()) {
                log.warn("FCM device token is missing");
                return false;
            }
            
            // FCM 推送实现
            log.info("Sending FCM notification to: {}, title: {}, body: {}", deviceToken, title, body);
            
            // 构建 FCM 消息
            Map<String, Object> message = new HashMap<>();
            message.put("token", deviceToken);
            
            Map<String, Object> notificationData = new HashMap<>();
            notificationData.put("title", title);
            notificationData.put("body", body);
            
            Map<String, Object> data = new HashMap<>();
            data.put("metadata", metadata);
            
            message.put("notification", notificationData);
            message.put("data", data);
            
            // 模拟 FCM 推送
            // 在实际实现中,这里会调用 FCM API
            // fcmService.send(message);
            
            log.info("FCM notification sent successfully to: {}", deviceToken);
            return true;
        } catch (Exception e) {
            log.error("FCM notification failed for token {}: {}", deviceToken, e.getMessage());
            return false;
        }
    }
    
    private boolean sendViaApns(String deviceToken, String title, String body, Map<String, Object> metadata) {
        try {
            if (deviceToken == null || deviceToken.trim().isEmpty()) {
                log.warn("APNS device token is missing");
                return false;
            }
            
            // APNS 推送实现
            log.info("Sending APNS notification to: {}, title: {}, body: {}", deviceToken, title, body);
            
            // 构建 APNS 消息
            Map<String, Object> aps = new HashMap<>();
            aps.put("alert", new HashMap<String, Object>() {{
                put("title", title);
                put("body", body);
            }});
            aps.put("sound", "default");
            aps.put("badge", 1);
            
            Map<String, Object> message = new HashMap<>();
            message.put("aps", aps);
            message.put("metadata", metadata);
            
            // 模拟 APNS 推送
            // 在实际实现中,这里会调用 APNS API
            // apnsService.send(deviceToken, message);
            
            log.info("APNS notification sent successfully to: {}", deviceToken);
            return true;
        } catch (Exception e) {
            log.error("APNS notification failed for token {}: {}", deviceToken, e.getMessage());
            return false;
        }
    }
    
    private boolean sendViaWebPush(String deviceToken, String title, String body, Map<String, Object> metadata) {
        try {
            if (deviceToken == null || deviceToken.trim().isEmpty()) {
                log.warn("Web Push subscription is missing");
                return false;
            }
            
            // Web Push 推送实现
            log.info("Sending Web Push notification to: {}, title: {}, body: {}", deviceToken, title, body);
            
            // 构建 Web Push 消息
            Map<String, Object> payload = new HashMap<>();
            payload.put("title", title);
            payload.put("body", body);
            payload.put("icon", "/icon.png");
            payload.put("data", metadata);
            
            // 模拟 Web Push 推送
            // 在实际实现中,这里会使用 Web Push 库
            // webPushService.send(deviceToken, payload);
            
            log.info("Web Push notification sent successfully to: {}", deviceToken);
            return true;
        } catch (Exception e) {
            log.error("Web Push notification failed for subscription {}: {}", deviceToken, e.getMessage());
            return false;
        }
    }
    
    private boolean sendInAppNotification(Long userId, String title, String body, Map<String, Object> metadata) {
        try {
            if (userId == null) {
                log.warn("User ID is missing for in-app notification");
                return false;
            }
            
            // 应用内通知实现
            log.info("Sending in-app notification to user: {}, title: {}, body: {}", userId, title, body);
            
            // 在实际实现中,这里会保存通知到数据库并通过 WebSocket 推送到前端
            // inAppNotificationService.saveAndSend(userId, title, body, metadata);
            
            log.info("In-app notification sent successfully to user: {}", userId);
            return true;
        } catch (Exception e) {
            log.error("In-app notification failed for user {}: {}", userId, e.getMessage());
            return false;
        }
    }
    
    private Map<String, Object> convertMetadataToMap(String metadata) {
        if (metadata == null || metadata.trim().isEmpty()) {
            return new HashMap<>();
        }
        
        try {
            return objectMapper.readValue(metadata, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            log.warn("Failed to parse metadata JSON: {}, using empty map", e.getMessage());
            return new HashMap<>();
        }
    }
    
    // 添加重载方法以支持不同的参数组合
    public boolean sendViaFcm(String deviceToken, String title, String body) {
        return sendViaFcm(deviceToken, title, body, new HashMap<>());
    }
    
    public boolean sendViaApns(String deviceToken, String title, String body) {
        return sendViaApns(deviceToken, title, body, new HashMap<>());
    }
    
    public boolean sendViaWebPush(String deviceToken, String title, String body) {
        return sendViaWebPush(deviceToken, title, body, new HashMap<>());
    }
    
    public boolean sendInAppNotification(Long userId, String title, String body) {
        return sendInAppNotification(userId, title, body, new HashMap<>());
    }
    
    // 批量发送方法
    public int sendBulkPushNotifications(Iterable<Notification> notifications) {
        int successCount = 0;
        for (Notification notification : notifications) {
            if (sendPushNotification(notification)) {
                successCount++;
            }
        }
        return successCount;
    }
}