Skip to content

Commit 4b34c99

Browse files
author
zhuoda
committed
v3.27
1 parent 921449f commit 4b34c99

34 files changed

Lines changed: 669 additions & 54 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
**<font color="#DC143C">国内首个满足《网络安全-三级等保》、《数据安全》</font>** 功能要求,支持登录限制、接口国产加解密、数据脱敏等一系列安全要求。
66

7-
**<font color="#DC143C">支持国产数据库:达梦、金仓、南大通用、OceanBase、GaussDB 高斯、阿里PolarDB、GoldenDB</font>**
7+
**<font color="#DC143C">支持国产数据库:达梦、金仓、南大通用、OceanBase、GaussDB 高斯、阿里PolarDB、GoldenDB】等,主流数据库:【Mysql, PostgreSQL】等</font>**
88

9-
前端提供 **<font color="#DC143C">JavaScript和TypeScript双版本</font>**,后端提供 **<font color="#DC143C">Java8+SpringBoot2.X和Java17+SpringBoot3.X 双版本</font>**
9+
**<font color="#DC143C">前端提供JavaScript和TypeScript双版本,后端提供Java8+SpringBoot2.X和Java17+SpringBoot3.X 双版本</font>**
1010

1111
同时 **<font color="#DC143C">重磅开源</font>** 开源六年来 **<font color="#DC143C">千余家企业验证过且正在使用</font>** 的代码规范: **<font color="#DC143C">《高质量代码思想》、《Vue3规范》、《Java规范》</font>** ,让大家在这浮躁的世界里感受到一股把代码写好的清流!同时又能节省大量时间,减少加班,快乐工作,保持谦逊,保持学习,**<font color="#DC143C">热爱代码,更热爱生活</font>**
1212
### **技术体系**

smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/manager/LoginManager.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,19 @@ public UserPermission loadUserPermission(Long employeeId) {
153153
}
154154

155155

156-
@CacheEvict(value = {AdminCacheConst.Login.USER_PERMISSION, AdminCacheConst.Login.REQUEST_EMPLOYEE}, allEntries = true)
157-
public void clear(){
156+
/**
157+
* 清除用户权限
158+
*/
159+
@CacheEvict(value = AdminCacheConst.Login.USER_PERMISSION)
160+
public void clearUserPermission(Long employeeId) {
161+
162+
}
163+
164+
/**
165+
* 清除用户登录信息
166+
*/
167+
@CacheEvict(value = AdminCacheConst.Login.REQUEST_EMPLOYEE)
168+
public void clearUserLoginInfo(Long employeeId) {
158169

159170
}
160171

smart-admin-api-java17-springboot3/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ public ResponseDTO<String> logout(RequestUser requestUser) {
317317
// sa token 登出
318318
StpUtil.logout();
319319

320-
// 清空登录信息缓存
321-
loginManager.clear();
320+
// 清除用户登录信息缓存和权限信息
321+
this.clearLoginEmployeeCache(requestUser.getUserId());
322322

323323
//保存登出日志
324324
LoginLogEntity loginEntity = LoginLogEntity.builder()
@@ -474,6 +474,7 @@ private void deleteEmailCode(Long employeeId) {
474474
}
475475

476476
public void clearLoginEmployeeCache(Long employeeId) {
477-
loginManager.clear();
477+
loginManager.clearUserPermission(employeeId);
478+
loginManager.clearUserLoginInfo(employeeId);
478479
}
479480
}

smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/config/CacheConfig.java

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@
55
import net.lab1024.sa.base.module.support.cache.CacheService;
66
import net.lab1024.sa.base.module.support.cache.CaffeineCacheServiceImpl;
77
import net.lab1024.sa.base.module.support.cache.RedisCacheServiceImpl;
8+
import net.lab1024.sa.base.module.support.redis.CustomRedisCacheManager;
89
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
10+
import org.springframework.cache.CacheManager;
911
import org.springframework.context.annotation.Bean;
1012
import org.springframework.context.annotation.Configuration;
1113
import org.springframework.data.redis.cache.RedisCacheConfiguration;
14+
import org.springframework.data.redis.cache.RedisCacheWriter;
1215
import org.springframework.data.redis.connection.RedisConnectionFactory;
1316
import org.springframework.data.redis.serializer.RedisSerializationContext;
1417

1518
/**
1619
* 缓存配置
1720
*
18-
* @author zhoumingfa
19-
* @date 2025/03/28
2021
*/
2122
@Configuration
2223
public class CacheConfig {
@@ -26,27 +27,44 @@ public class CacheConfig {
2627

2728

2829
@Resource
29-
private RedisConnectionFactory factory;
30+
private RedisConnectionFactory redisConnectionFactory;
3031

32+
/**
33+
* 创建自定义Redis缓存管理器Bean 整合spring-cache
34+
* Redis连接工厂,用于建立与Redis服务器的连接
35+
*
36+
* @return CacheManager Redis缓存管理器实例
37+
*/
3138
@Bean
3239
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
33-
public RedisCacheConfiguration redisCacheConfiguration() {
34-
return RedisCacheConfiguration.defaultCacheConfig()
40+
public CacheManager cacheManager() {
41+
// 使用非阻塞模式的缓存写入器,适用于大多数高并发场景
42+
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
43+
44+
// 构建默认缓存配置
45+
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
46+
// 禁止缓存 null 值,避免缓存穿透
3547
.disableCachingNullValues()
3648
.computePrefixWith(name -> "cache:" + name + ":")
37-
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
38-
}
49+
// 使用 FastJSON 序列化缓存值,支持复杂对象
50+
.serializeValuesWith(RedisSerializationContext.SerializationPair
51+
.fromSerializer(new GenericFastJsonRedisSerializer()));
3952

40-
@Bean
41-
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
42-
public CacheService redisCacheService() {
43-
return new RedisCacheServiceImpl();
53+
// 返回自定义缓存管理器,支持 cacheName#ttl 格式与永久缓存(#-1)
54+
return new CustomRedisCacheManager(redisCacheWriter, defaultCacheConfig);
4455
}
4556

46-
@Bean
47-
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = CAFFEINE_CACHE)
48-
public CacheService caffeineCacheService() {
49-
return new CaffeineCacheServiceImpl();
50-
}
57+
58+
@Bean
59+
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = REDIS_CACHE)
60+
public CacheService redisCacheService() {
61+
return new RedisCacheServiceImpl();
62+
}
63+
64+
@Bean
65+
@ConditionalOnProperty(prefix = "spring.cache", name = {"type"}, havingValue = CAFFEINE_CACHE)
66+
public CacheService caffeineCacheService() {
67+
return new CaffeineCacheServiceImpl();
68+
}
5169

5270
}

smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/cache/RedisCacheServiceImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.springframework.data.redis.connection.RedisConnection;
1111
import org.springframework.data.redis.connection.RedisConnectionFactory;
1212

13+
import java.nio.charset.StandardCharsets;
1314
import java.util.Collection;
1415
import java.util.List;
1516
import java.util.Set;
@@ -53,7 +54,7 @@ public List<String> cacheKey(String cacheName) {
5354

5455
if (keys != null) {
5556
return keys.stream().map(key -> {
56-
String redisKey = StrUtil.str(key, "utf-8");
57+
String redisKey = StrUtil.str(key, StandardCharsets.UTF_8);
5758
// 从 Redis 键中提取出最后一个冒号后面的字符串作为真正的键
5859
return redisKey.substring(redisKey.lastIndexOf(":") + 1);
5960
}).collect(Collectors.toList());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package net.lab1024.sa.base.module.support.cache.manager;
2+
3+
import cn.hutool.core.util.StrUtil;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.boot.convert.DurationStyle;
6+
import org.springframework.data.redis.cache.*;
7+
8+
import java.time.Duration;
9+
10+
import static net.lab1024.sa.base.common.constant.StringConst.COLON;
11+
12+
/**
13+
* 自定义 RedisCacheManager,支持在 cacheName 中通过 '#' 指定 TTL(过期时间)。
14+
* @Author CoderKK
15+
* @Date 2025-08-15 13:01:01
16+
* <p>
17+
* 支持格式:{@code cacheName#ttl},其中 ttl 支持 Spring 的 Duration 格式。
18+
* 特殊值:{@code -1} 表示永久缓存(永不过期)。
19+
* </p>
20+
*
21+
* <h3>使用示例:</h3>
22+
* <pre>
23+
* // 10 秒后过期
24+
* &#64;Cacheable(value = "user#10s", key = "#id")
25+
* // 2 小时后过期
26+
* &#64;Cacheable(value = "report#2h", key = "#date")
27+
* // 30 分钟后过期
28+
* &#64;Cacheable(value = "session#30m", key = "#token")
29+
* // 永不过期(永久缓存),适用于极少变化的配置数据
30+
* &#64;Cacheable(value = "appConfig#-1", key = "'globalSettings'")
31+
* // 无 TTL,使用全局默认过期时间(如 7 天)
32+
* &#64;Cacheable(value = "product", key = "#productId")
33+
* </pre>
34+
*
35+
* <h3>生成的 Redis Key 格式:</h3>
36+
* <pre>
37+
* cache:cacheName:key
38+
* 例如:cache:user:123
39+
* cache:appConfig:globalSettings
40+
* </pre>
41+
*
42+
* <h3>支持的 TTL 单位:</h3>
43+
* <ul>
44+
* <li>{@code ms} / {@code millis} / {@code milliseconds} - 毫秒</li>
45+
* <li>{@code s} / {@code secs} / {@code seconds} - 秒</li>
46+
* <li>{@code m} / {@code mins} / {@code minutes} - 分钟</li>
47+
* <li>{@code h} / {@code hrs} / {@code hours} - 小时</li>
48+
* <li>{@code d} / {@code days} - 天</li>
49+
* </ul>
50+
*
51+
* <h3>注意事项:</h3>
52+
* <ul>
53+
* <li>不写单位默认为毫秒</li>
54+
* <li>永久缓存(#-1)不会自动过期,请配合 &#64;CacheEvict 手动清理。</li>
55+
* <li>避免对频繁更新的数据使用永久缓存,防止数据陈旧。</li>
56+
* <li>cacheName 中的 '#' 只解析第一个,后续字符将作为 TTL 处理。</li>
57+
* </ul>
58+
*/
59+
@Slf4j
60+
public class CustomRedisCacheManager extends RedisCacheManager {
61+
62+
/**
63+
* 缓存全局前缀
64+
*/
65+
private static final String CACHE_PREFIX = "cache";
66+
67+
/**
68+
* 自定义 TTL 分隔符,用于在 cacheName 后附加过期时间
69+
*/
70+
private static final String CUSTOM_TTL_SEPARATOR = "#";
71+
72+
/**
73+
* 默认缓存过期时间:7 天
74+
*/
75+
private static final Duration DEFAULT_TTL = Duration.ofDays(7);
76+
77+
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
78+
super(cacheWriter, defaultCacheConfiguration);
79+
}
80+
81+
/**
82+
* 创建 RedisCache 实例,支持从 cacheName 解析 TTL
83+
*
84+
* @param name 缓存名称(支持 name#ttl 格式)
85+
* @param cacheConfig 默认缓存配置
86+
* @return RedisCache
87+
*/
88+
@Override
89+
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
90+
Duration ttl = parseTtlFromCacheName(name);
91+
if (ttl == null) {
92+
ttl = DEFAULT_TTL;
93+
}
94+
95+
CacheKeyPrefix keyPrefix = cacheName -> {
96+
if (StrUtil.isBlank(cacheName)) {
97+
return CACHE_PREFIX + COLON;
98+
}
99+
String[] parts = cacheName.split(CUSTOM_TTL_SEPARATOR, 2);
100+
String cleanName = StrUtil.trim(parts[0]);
101+
return CACHE_PREFIX + COLON + cleanName + COLON;
102+
};
103+
104+
// 构建最终缓存配置:设置 key 前缀 + TTL
105+
RedisCacheConfiguration config = cacheConfig.computePrefixWith(keyPrefix).entryTtl(ttl);
106+
107+
return super.createRedisCache(name, config);
108+
}
109+
110+
/**
111+
* 从 cacheName 中解析 TTL
112+
*
113+
* @param name 缓存名称,格式如:users#10m, products#2h, config#-1(永久)
114+
* @return 解析出的 Duration若无效则返回 null;若为 -1,则返回 Duration.ofMillis(-1) 表示永久缓存
115+
*/
116+
private Duration parseTtlFromCacheName(String name) {
117+
if (StrUtil.isBlank(name)) {
118+
return null;
119+
}
120+
121+
String[] parts = name.split(CUSTOM_TTL_SEPARATOR, 2);
122+
if (parts.length < 2) {
123+
return null; // 无 TTL 部分
124+
}
125+
126+
String ttlStr = StrUtil.trim(parts[1]);
127+
if (StrUtil.isBlank(ttlStr)) {
128+
return null;
129+
}
130+
131+
// 特殊处理:-1 表示永久缓存
132+
if ("-1".equals(ttlStr)) {
133+
return Duration.ofMillis(-1); // Spring Redis 中负数 Duration 表示永不过期
134+
}
135+
136+
try {
137+
Duration ttl = DurationStyle.detectAndParse(ttlStr);
138+
return ttl.toSeconds() > 0 ? ttl : null;
139+
} catch (IllegalArgumentException e) {
140+
log.debug("解析缓存 TTL 失败,cacheName='{}', ttl='{}', 错误: {}", name, ttlStr, e.getMessage());
141+
return null;
142+
}
143+
}
144+
}

smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/dict/domain/vo/DictDataVO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class DictDataVO implements Serializable {
3030
private String dictName;
3131

3232
@Schema(description = "字典禁用状态")
33-
private Integer dictDisabledFlag;
33+
private Boolean dictDisabledFlag;
3434

3535
@Schema(description = "字典项值")
3636
private String dataValue;

smart-admin-api-java17-springboot3/sa-base/src/main/java/net/lab1024/sa/base/module/support/dict/domain/vo/DictVO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class DictVO {
3030
private String remark;
3131

3232
@Schema(description = "禁用状态")
33-
private Integer disabledFlag;
33+
private Boolean disabledFlag;
3434

3535
@Schema(description = "创建时间")
3636
private LocalDateTime createTime;

0 commit comments

Comments
 (0)