文章目录
- 🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)
🌞 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 {@Beanpublic 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 {@Resourceprivate 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 # 最大活跃连接数,使用负值表示没有限制,最佳配置为核数*2max-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中获取每个用户的题目数量和用户的loginIdString 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;
}