文章目录
- 🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)
- 🌟 亮点功能
- 📦 spring cloud模块概览
- 常用工具
- 🔗 更多信息
- 1.sun-club-subject集成redis
- 1.sun-club-domain引入依赖
- 2.sun-club-domain引入redis的工具类
- 1.RedisConfig.java
- 2.RedisUtil.java
- 3.在application.yml下集成redis(是在spring下的)
- 2.SubjectInfoDomainServiceImpl.java 修改逻辑
- 1.依赖注入
- 2.每添加一个题目都会计入排行榜
- 3.getContributeList方法
- 3.测试
- 1.登录后新增题目
- 2.获取排行榜
🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)
轻松高效的现代化开发体验
Sun Frame 是我个人开源的一款基于 SpringBoot 的轻量级框架,专为中小型企业设计。它提供了一种快速、简单且易于扩展的开发方式。
我们的开发文档记录了整个项目从0到1的任何细节,实属不易,请给我们一个Star!🌟
您的支持是我们持续改进的动力。
您的支持是我们持续改进的动力。
🌟 亮点功能
- 组件化开发:灵活选择,简化流程。
- 高性能:通过异步日志和 Redis 缓存提升性能。
- 易扩展:支持多种数据库和消息队列。
📦 spring cloud模块概览
- Nacos 服务:高效的服务注册与发现。
- Feign 远程调用:简化服务间通信。
- 强大网关:路由与限流。
常用工具
- 日志管理:异步处理与链路追踪。
- Redis 集成:支持分布式锁与缓存。
- Swagger 文档:便捷的 API 入口。
- 测试支持:SpringBoot-Test 集成。
- EasyCode:自定义EasyCode模板引擎,一键生成CRUD。
🔗 更多信息
- 开源地址:Gitee Sun Frame
- 详细文档:语雀文档
1.sun-club-subject集成redis
1.sun-club-domain引入依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.4.2</version>
</dependency>
<!-- redis的pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.9.0</version>
</dependency>
<!-- jackson序列化 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.7</version>
</dependency>
2.sun-club-domain引入redis的工具类
1.RedisConfig.java
package com.sunxiansheng.subject.domain.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
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.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Description: 原生 redis 的 template 的序列化器会产生乱码问题,重写改为 jackson
* @Author sun
* @Create 2024/6/5 14:16
* @Version 1.0
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer());
return redisTemplate;
}
private Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jsonRedisSerializer.setObjectMapper(objectMapper);
return jsonRedisSerializer;
}
}
2.RedisUtil.java
package com.sunxiansheng.subject.domain.redis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Description: RedisUtil工具类
* @Author sun
* @Create 2024/6/5 14:17
* @Version 1.0
*/
@Component
@Slf4j
public class RedisUtil {
@Resource
private RedisTemplate redisTemplate;
private static final String CACHE_KEY_SEPARATOR = ".";
/**
* 构建缓存key
* @param strObjs
* @return
*/
public String buildKey(String... strObjs) {
return Stream.of(strObjs).collect(Collectors.joining(CACHE_KEY_SEPARATOR));
}
/**
* 是否存在key
* @param key
* @return
*/
public boolean exist(String key) {
return redisTemplate.hasKey(key);
}
/**
* 删除key
* @param key
* @return
*/
public boolean del(String key) {
return redisTemplate.delete(key);
}
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
public boolean setNx(String key, String value, Long time, TimeUnit timeUnit) {
return redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit);
}
public String get(String key) {
return (String) redisTemplate.opsForValue().get(key);
}
public Boolean zAdd(String key, String value, Long score) {
return redisTemplate.opsForZSet().add(key, value, Double.valueOf(String.valueOf(score)));
}
public Long countZset(String key) {
return redisTemplate.opsForZSet().size(key);
}
public Set<String> rangeZset(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
public Long removeZset(String key, Object value) {
return redisTemplate.opsForZSet().remove(key, value);
}
public void removeZsetList(String key, Set<String> value) {
value.stream().forEach((val) -> redisTemplate.opsForZSet().remove(key, val));
}
public Double score(String key, Object value) {
return redisTemplate.opsForZSet().score(key, value);
}
public Set<String> rangeByScore(String key, long start, long end) {
return redisTemplate.opsForZSet().rangeByScore(key, Double.valueOf(String.valueOf(start)), Double.valueOf(String.valueOf(end)));
}
/**
* 可以使用这个来实现排行榜,指定键就相当于指定了一个排行榜,再指定成员和分数,则会给排行榜中的这个成员加分数
* @param key zset的键
* @param obj 成员,一般为用户的唯一标识
* @param score 分数
* @return
*/
public Object addScore(String key, Object obj, double score) {
return redisTemplate.opsForZSet().incrementScore(key, obj, score);
}
public Object rank(String key, Object obj) {
return redisTemplate.opsForZSet().rank(key, obj);
}
/**
* 从 Redis 有序集合(Sorted Set)中按分数范围获取成员及其分数
* @param key 排行榜的key
* @param start 起始位置(包含)
* @param end 结束位置(包含)
* @return Set<ZSetOperations.TypedTuple<String>> : 每个 TypedTuple 对象包含以下内容:value: 集合中的成员,score: 成员的分数。
*/
public Set<ZSetOperations.TypedTuple<String>> rankWithScore(String key, long start, long end) {
Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
return set;
}
}
3.在application.yml下集成redis(是在spring下的)
# redis
redis:
password: # Redis服务器密码
database: 0 # 默认数据库为0号
timeout: 10000ms # 连接超时时间是10000毫秒
lettuce:
pool:
max-active: 8 # 最大活跃连接数,使用负值表示没有限制,最佳配置为核数*2
max-wait: 10000ms # 最大等待时间,单位为毫秒,使用负值表示没有限制,这里设置为10秒
max-idle: 200 # 最大空闲连接数
min-idle: 5 # 最小空闲连接数
cluster:
nodes:
2.SubjectInfoDomainServiceImpl.java 修改逻辑
1.依赖注入
2.每添加一个题目都会计入排行榜
3.getContributeList方法
@Override
public List<SubjectInfoBO> getContributeList() {
// 从redis中得到排行榜信息
Set<ZSetOperations.TypedTuple<String>> typedTuples = redisUtil.rankWithScore(RANK_KEY, 0, 5);
// 打日志
if (log.isInfoEnabled()) {
log.info("SubjectInfoDomainServiceImpl getContributeList typedTuples:{}", typedTuples);
}
// 判空
if (CollectionUtils.isEmpty(typedTuples)) {
return Collections.emptyList();
}
// 如果查到了,就封装到BO中
List<SubjectInfoBO> boList = new LinkedList<>();
typedTuples.forEach(rank -> {
SubjectInfoBO subjectInfoBO = new SubjectInfoBO();
// 从redis中获取每个用户的题目数量和用户的loginId
String loginId = rank.getValue();
int subjectCount = rank.getScore().intValue();
// 设置题目数量
subjectInfoBO.setSubjectCount(subjectCount);
// rpc调用根据loginId来查询该用户的昵称和头像
UserInfo userInfo = userRpc.getUserInfo(loginId);
subjectInfoBO.setCreateUser(userInfo.getNickName());
subjectInfoBO.setCreateUserAvatar(userInfo.getAvater());
boList.add(subjectInfoBO);
});
return boList;
}