package com.ruoyi.approve.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.concurrent.TimeUnit; //基于redis的一个每日计数器 @Component public class DailyRedisCounter { private static final String KEY_PREFIX = "daily_counter:"; private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd"); private final StringRedisTemplate redisTemplate; public DailyRedisCounter(StringRedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } /** * 获取指定计数器在今日的数值,并自增1 * @param counterName 计数器名称(例如:login_count、order_count) * @return 今日自增后的计数值 */ public long incrementAndGet(String counterName) { String key = getKey(counterName); long count = redisTemplate.opsForValue().increment(key, 1); // 仅在第一次设置时设置过期时间(避免重复设置) if (count == 1) { long secondsUntilMidnight = calculateSecondsUntilMidnight(); redisTemplate.expire(key, secondsUntilMidnight, TimeUnit.SECONDS); } return count; } /** * 获取指定计数器在今日的当前数值 * @param counterName 计数器名称 * @return 今日当前计数值,若不存在则返回0 */ public long getCurrentCount(String counterName) { String key = getKey(counterName); String value = redisTemplate.opsForValue().get(key); return value != null ? Long.parseLong(value) : 0; } /** * 计算距离次日凌晨的秒数 */ private long calculateSecondsUntilMidnight() { LocalDate tomorrow = LocalDate.now().plusDays(1); LocalDate midnight = tomorrow.atStartOfDay().toLocalDate(); return java.time.Duration.between( LocalDate.now().atTime(23, 59, 59), midnight.atTime(0, 0, 0) ).getSeconds() + 1; } /** * 生成Redis键 */ private String getKey(String counterName) { String today = LocalDate.now().format(DATE_FORMAT); return KEY_PREFIX + counterName + ":" + today; } }