项目架构,这是作为demo展示使用:
Redis config:
package com.zy.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @Author: zy
* @Date: 2025-03-08-13:22
* @Description:
*/
@Configuration
public class RedisConfig {
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
Controller:
package com.zy.controller;
import com.zy.config.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
/**
* @Author: zy
* @Date: 2025-03-08-12:43
* @Description:
*/
@RestController
@Slf4j
@RequestMapping("/user")
public class SignController {
@Autowired
private RedisTemplate redisTemplate;
@PostMapping("/sign")
public Boolean sign() {
try {
//1. 获取登录用户
//Long userId = SSOThreadHolder.getUserAndCheck().getUserId();
Long userId = 1001012345L;
//2. 获取日期
LocalDateTime now = LocalDateTime.now();
for (int i = 0; i < 100; i++) {
LocalDate date = LocalDateTime.now().minusDays(i).toLocalDate();
String format = date.format(DateTimeFormatter.ofPattern(":yyyyMM"));
//3. 拼接key
String keySuffix = format;
String key = RedisConstants.USER_SIGN_KEY + userId + keySuffix;
log.info("redis key:" + key);
//4. 获取今天是本月的第几天
int dayOfMonth = date.getDayOfMonth();
//5. 写入redis setbit key offset 1
System.out.println("dayOfMonth:" + dayOfMonth);
Boolean aBoolean = redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
System.out.println("aboolean:" + aBoolean);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
return true;
}
@GetMapping("/signCount")
public String signCount() {
long l = countSignInDays("sign:1001012345:202503");
System.out.println("l:" + l);
return String.valueOf(l);
}
/**
* 统计当前月的签到总数
*
* @param key Redis键
* @return 签到总数
*/
public long countSignInDays(String key) {
key = "sign:1001012345:202503";
// 获取当前月的总天数
YearMonth currentYearMonth = YearMonth.now();
int daysInMonth = currentYearMonth.lengthOfMonth();
// 使用 execute 方法执行 BITCOUNT 命令
String finalKey = key;
Long bitCount = (Long) redisTemplate.execute((RedisConnection connection) -> {
// 检查键是否存在
if (!connection.exists(finalKey.getBytes())) {
return 0L;
}
// 执行 BITCOUNT 命令,统计指定范围内的 1 的数量
return connection.bitCount(finalKey.getBytes(), 0, daysInMonth - 1);
});
return Optional.ofNullable(bitCount).orElse(0L);
}
}
yml文件:
server:
port: 8090
spring:
#redis哨兵配置
redis:
sentinel:
master: mymaster
nodes: # 我这里使用的是哨兵模式,不影响,根据你自己的来,但是如果没有,为啥不搭建一下,自己使用呢
- localhost:26379
- localhost:26380
- localhost:26381
password: 你的密码
password: 你的密码
接口测试:
签到接口,在代码中模拟了100天的签到
统计接口:统计的什么,具体看代码