You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot下Firebase通知:同一Token消息间隔5分钟发送实现

解决同一Token重复推送Firebase通知的问题

核心思路

针对每个设备Token记录最后一次推送通知的时间,每次触发推送前先判断当前时间与上次推送时间的间隔是否超过5分钟,只有满足条件才执行推送操作,并更新最后推送时间。

具体实现

1. 选择存储方式

  • 单机部署:使用ConcurrentHashMap存储Token和对应的最后推送时间,保证线程安全。
  • 分布式部署:推荐用Redis,支持多实例共享状态。

2. 单机场景实现(基于ConcurrentHashMap)

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

// 全局缓存,存储Token与最后推送时间戳
private static final ConcurrentHashMap<String, Long> LAST_PUSH_TIME = new ConcurrentHashMap<>();
// 5分钟间隔,转换为毫秒
private static final long MIN_INTERVAL = TimeUnit.MINUTES.toMillis(5);

public void sendChatNotification(User user){
    String token = user.getToken();
    if(token == null) {
        return;
    }

    long currentTime = System.currentTimeMillis();
    // 获取上次推送时间,无记录则返回0
    long lastPushTime = LAST_PUSH_TIME.getOrDefault(token, 0L);

    // 检查是否满足推送间隔
    if(currentTime - lastPushTime >= MIN_INTERVAL) {
        try {
            Notification notification = Notification.builder()
                    .setTitle("Title")
                    .setBody("Body")
                    .build();
            Message message = Message.builder()
                    .setToken(token)
                    .setNotification(notification)
                    .putData("payload", "logged-home")
                    .build();
            firebaseMessaging.send(message);
            // 更新最后推送时间
            LAST_PUSH_TIME.put(token, currentTime);
        } catch (FirebaseMessagingException error) {
            throw new ApiRequestException("Error!");
        }
    }
}

3. 分布式场景实现(基于Redis)

import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;

private final StringRedisTemplate redisTemplate;
// 5分钟间隔
private static final long MIN_INTERVAL = 5;
// Redis键前缀,避免键冲突
private static final String PUSH_TIME_KEY_PREFIX = "chat:push:last_time:";

// 通过构造函数注入StringRedisTemplate
public YourService(StringRedisTemplate redisTemplate) {
    this.redisTemplate = redisTemplate;
}

public void sendChatNotification(User user){
    String token = user.getToken();
    if(token == null) {
        return;
    }

    String key = PUSH_TIME_KEY_PREFIX + token;
    String lastPushTimeStr = redisTemplate.opsForValue().get(key);
    long currentTime = System.currentTimeMillis();

    // 无推送记录或已满足间隔条件时执行推送
    if(lastPushTimeStr == null || currentTime - Long.parseLong(lastPushTimeStr) >= TimeUnit.MINUTES.toMillis(MIN_INTERVAL)) {
        try {
            Notification notification = Notification.builder()
                    .setTitle("Title")
                    .setBody("Body")
                    .build();
            Message message = Message.builder()
                    .setToken(token)
                    .setNotification(notification)
                    .putData("payload", "logged-home")
                    .build();
            firebaseMessaging.send(message);
            // 更新Redis记录,设置1小时过期时间清理无效条目
            redisTemplate.opsForValue().set(key, String.valueOf(currentTime), 1, TimeUnit.HOURS);
        } catch (FirebaseMessagingException error) {
            throw new ApiRequestException("Error!");
        }
    }
}

额外优化建议

  • 单机场景下,可定时清理ConcurrentHashMap中长时间未推送的Token记录,避免内存占用过高。
  • 若需要合并间隔内的多条消息,可在缓存中暂存未推送的消息内容,间隔达标后合并成一条通知发送,提升用户体验。

内容的提问来源于stack exchange,提问作者Luis Rotoly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:32:09