初始化仓库

This commit is contained in:
2026-04-21 15:08:07 +08:00
parent 444d984122
commit b5119afb9f
195 changed files with 11034 additions and 19 deletions

View File

@@ -0,0 +1,28 @@
package xtools.boot.cache.redis;
import org.springframework.context.annotation.Import;
import xtools.boot.cache.redis.selector.BootCacheRedisImportSelector;
import xtools.boot.core.utils.ModuleLoadUtils;
/**
* <p>Title : BootCacheRedisConfiguration</p>
* <p>Description : BootCacheRedisConfiguration</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/01/01 09:30
*/
@Import(BootCacheRedisImportSelector.class)
public class BootCacheRedisConfiguration {
/**
* 构造方法
*/
public BootCacheRedisConfiguration() {
ModuleLoadUtils.loadSuccess(BootCacheRedisConfiguration.class);
}
}

View File

@@ -0,0 +1,458 @@
package xtools.boot.cache.redis.base;
import com.alibaba.fastjson2.JSON;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import xtools.base.config.BaseParams;
import xtools.core.ArrUtils;
import xtools.core.CollectionUtils;
import xtools.core.StringUtils;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;
/**
* <p>Title : RedisService</p>
* <p>Description : RedisService</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/01/01 09:30
*/
@Component
public class RedisService implements BaseParams {
/**
* RedisTemplate
**/
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* StringRedisTemplate
**/
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 获取组合 Key
*
* @param keys 多个 Key
* @return 组合 Key
*/
public String getKey(String... keys) {
if (ArrUtils.isEmpty(keys)) {
return null;
}
StringJoiner sj = new StringJoiner(CP_COLON);
for (String key : keys) {
sj.add(key);
}
return sj.toString();
}
/**
* 整数 值递增一
*
* @param key Key
* @return 递增后的值
*/
public Long incr(String key) {
return stringRedisTemplate.opsForValue().increment(key);
}
/**
* 保存数据
*
* @param key Key
* @param data 数据
*/
public void set(String key, Object data) {
this.set(key, data, null, null);
}
/**
* 保存数据
*
* @param key Key
* @param data 数据
* @param timeout 过期时间
*/
public void set(String key, Object data, Long timeout) {
this.set(key, data, timeout, TimeUnit.SECONDS);
}
/**
* 保存数据
*
* @param key Key
* @param data 数据
* @param timeout 过期时间
* @param unit 时间单位
*/
public void set(String key, Object data, Long timeout, TimeUnit unit) {
// 参数校验
if (StringUtils.isEmpty(key) || data == null) {
return;
}
// 序列化数据
String serializeData;
if (data instanceof String) {
serializeData = data.toString();
} else {
serializeData = JSON.toJSONString(data);
}
if (StringUtils.isEmpty(serializeData)) {
return;
}
if (unit == null) {
unit = TimeUnit.SECONDS;
}
// 判断是否有过期时间
if (timeout == null || timeout <= 0) {
stringRedisTemplate.opsForValue().set(key, serializeData);
} else {
stringRedisTemplate.opsForValue().set(key, serializeData, timeout, unit);
}
}
/**
* 保存数据(如果key存在则保存失败)
*
* @param key Key
* @param data 数据
* @return 保存结果
*/
public Boolean setNx(String key, Object data) {
return this.setNx(key, data, null, null);
}
/**
* 保存数据(如果key存在则保存失败)
*
* @param key Key
* @param data 数据
* @param timeout 有效时间
* @return 保存结果
*/
public Boolean setNx(String key, Object data, Long timeout) {
return this.setNx(key, data, timeout, TimeUnit.SECONDS);
}
/**
* 保存数据(如果key存在则保存失败)
*
* @param key Key
* @param data 数据
* @param timeout 有效时间
* @param unit 时间单位
* @return 保存结果
*/
public Boolean setNx(String key, Object data, Long timeout, TimeUnit unit) {
// 参数校验
if (StringUtils.isEmpty(key) || data == null) {
return false;
}
// 序列化数据
String serializeData;
if (data instanceof String) {
serializeData = data.toString();
} else {
serializeData = JSON.toJSONString(data);
}
if (StringUtils.isEmpty(serializeData)) {
return false;
}
if (unit == null) {
unit = TimeUnit.SECONDS;
}
// 判断是否有过期时间
if (timeout == null || timeout <= 0) {
return stringRedisTemplate.opsForValue().setIfAbsent(key, serializeData);
} else {
return stringRedisTemplate.opsForValue().setIfAbsent(key, serializeData, timeout, unit);
}
}
/**
* 获取数据
*
* @param <T> Class 类型
* @param key Key
* @param clazz Class
* @return 数据
*/
public <T> T get(String key, Class<T> clazz) {
// 参数校验
if (StringUtils.isEmpty(key)) {
return null;
}
// 从缓存获取数据
String data = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isEmpty(data)) {
return null;
}
return JSON.to(clazz, data);
}
/**
* 删除 key 对应的数据
*
* @param key Key
* @return 删除结果
*/
public Boolean del(String key) {
// 参数校验
if (StringUtils.isEmpty(key)) {
return false;
}
return stringRedisTemplate.delete(key);
}
/**
* 更改 Key
*
* @param oldKey 旧Key
* @param newKey 新Key
*/
public void rename(String oldKey, String newKey) {
// 参数校验
if (StringUtils.isEmpty(oldKey) || StringUtils.isEmpty(newKey)) {
return;
}
stringRedisTemplate.rename(oldKey, newKey);
}
/**
* 设置key的过期时间(秒)
*
* @param key Key
* @param timeout 时间(秒)
* @return 设置结果
*/
public Boolean expire(String key, long timeout) {
// 参数校验
if (StringUtils.isEmpty(key) || timeout <= 0) {
return false;
}
return stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 取消对 Key 过期时间的设置
*
* @param key Key
* @return true or false
*/
public Boolean persist(String key) {
// 参数校验
if (StringUtils.isEmpty(key)) {
return false;
}
return stringRedisTemplate.persist(key);
}
/**
* 查找所有匹配给定的模式的键
*
* @param pattern key的表达式,*表示多个,?表示一个
* @return 全部符合表达式记录
*/
public Set<String> getByPattern(String pattern) {
// 参数校验
if (StringUtils.isEmpty(pattern)) {
return null;
}
return stringRedisTemplate.keys(pattern);
}
/**
* 尝试获取锁
*
* @param key 锁的key
* @param value 请求标识(可用UUID)
* @param expireTime 过期时间(秒)
* @return 是否获取成功
*/
public boolean tryLock(String key, String value, long expireTime) {
Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
return Boolean.TRUE.equals(result);
}
/**
* 释放锁(使用Lua脚本保证原子性)
*
* @param key 锁的key
* @param value 请求标识
* @return 是否释放成功
*/
public boolean releaseLock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);
redisScript.setResultType(Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
return Long.valueOf(CP_NUM1).equals(result);
}
/**
* 保存 Hash 数据
*
* @param key Key
* @param map Hash 数据
* @return 保存结果
*/
public boolean hashPutAll(String key, Map<Object, String> map) {
// 参数校验
if (StringUtils.isEmpty(key)) {
return false;
}
if (CollectionUtils.isEmpty(map)) {
return false;
}
stringRedisTemplate.opsForHash().putAll(key, map);
return true;
}
/**
* 保存 Hash 数据
*
* @param key key
* @param hashKey hashKey
* @param data 数据
* @return 保存结果
*/
public boolean hashPut(String key, Object hashKey, Object data) {
// 参数校验
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
return false;
}
// 序列化数据
String serializeData;
if (data instanceof String) {
serializeData = data.toString();
} else {
serializeData = JSON.toJSONString(data);
}
if (StringUtils.isEmpty(serializeData)) {
return false;
}
stringRedisTemplate.opsForHash().putIfAbsent(key, hashKey, serializeData);
return true;
}
/**
* 保存 Hash 数据
*
* @param key key
* @param hashKey hashKey
* @param data 数据
* @param expireTime 过期时间(秒)
* @return 保存结果
*/
public boolean hashPut(String key, Object hashKey, Object data, long expireTime) {
// 参数校验
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
return false;
}
// 序列化数据
String serializeData;
if (data instanceof String) {
serializeData = data.toString();
} else {
serializeData = JSON.toJSONString(data);
}
if (StringUtils.isEmpty(serializeData)) {
return false;
}
String script =
"redis.call('HSET', KEYS[1], ARGV[1], ARGV[2]) " +
"redis.call('HEXPIRE', KEYS[1], ARGV[3], 'FIELDS', 1, ARGV[1]) " +
"return 1";
Long result = stringRedisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
hashKey, serializeData, String.valueOf(expireTime)
);
return Long.valueOf(CP_NUM1).equals(result);
}
/**
* 获取 Hash 中所有数据
*
* @param <T> 结果类型
* @param key key
* @param clazz 结果类型
* @return 数据集
*/
public <T> T hashEntries(String key, Class<T> clazz) {
// 参数校验
if (StringUtils.isEmpty(key)) {
return null;
}
Map<Object, Object> data = stringRedisTemplate.opsForHash().entries(key);
if (CollectionUtils.isEmpty(data)) {
return null;
}
return JSON.to(clazz, data);
}
/**
* 获取 Hash 中指定 Key 的数据
*
* @param <T> 结果类型
* @param key key
* @param hashKey hashKey
* @param clazz 结果类型
* @return 数据
*/
public <T> T hashGet(String key, Object hashKey, Class<T> clazz) {
// 参数校验
if (StringUtils.isEmpty(key) || Objects.isNull(hashKey)) {
return null;
}
Object data = stringRedisTemplate.opsForHash().get(key, hashKey);
return JSON.to(clazz, data);
}
/**
* 删除 Hash 中指定 Key 的数据
*
* @param key key
* @param hashKeys hashKey数组
* @return 删除结果
*/
public Long hashDelete(String key, Object... hashKeys) {
if (StringUtils.isBlank(key) || ArrUtils.isEmpty(hashKeys)) {
return 0L;
}
return stringRedisTemplate.opsForHash().delete(key, hashKeys);
}
/**
* 判断 Hash 中是否存在指定 Key 的数据
*
* @param key key
* @param hashKey hashKey
* @return 存在结果
*/
public boolean hashExists(String key, Object hashKey) {
if (StringUtils.isBlank(key) || Objects.isNull(hashKey)) {
return false;
}
return stringRedisTemplate.opsForHash().hasKey(key, hashKey);
}
}

View File

@@ -0,0 +1,30 @@
package xtools.boot.cache.redis.enums;
/**
* <p>Title : BaseCacheEnum</p>
* <p>Description : BaseCacheEnum</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/3/25 14:57
*/
public interface BaseCacheEnum {
/**
* 获取key
*
* @return key
*/
String key();
/**
* 获取超时时间
*
* @return 超时时间
*/
Long expireTime();
}

View File

@@ -0,0 +1,63 @@
package xtools.boot.cache.redis.monitor;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.Resource;
import org.springframework.data.redis.connection.RedisCommands;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import xtools.core.StringUtils;
import java.util.Objects;
import java.util.Properties;
/**
* <p>Title : RedisMonitor</p>
* <p>Description : RedisMonitor</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/01/01 09:30
*/
@Component
public class RedisMonitor {
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 状态
*
* @return 状态数据
*/
public JSONObject stats() {
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
if (Objects.isNull(factory)) {
return null;
}
// 获取redis命令
RedisCommands commands = factory.getConnection().commands();
// 获取相对应信息
Properties info = commands.info();
Object dbSize = commands.dbSize();
Properties commandStats = commands.info("commandstats");
JSONArray cmd = new JSONArray();
if (Objects.nonNull(commandStats)) {
commandStats.stringPropertyNames().forEach(key -> {
String property = commandStats.getProperty(key);
JSONObject data = JSONObject.of(
"name", StringUtils.removeStart(key, "cmdstat_"),
"value", StringUtils.substringBetween(property, "calls=", ",usec")
);
cmd.add(data);
});
}
// 封装数据
return JSONObject.of("info", info, "dbSize", dbSize, "cmd", cmd);
}
}

View File

@@ -0,0 +1,36 @@
package xtools.boot.cache.redis.selector;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* <p>Title : BootCacheRedisImportSelector</p>
* <p>Description : BootCacheRedisImportSelector</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/01/01 09:30
*/
public class BootCacheRedisImportSelector implements ImportBeanDefinitionRegistrar {
/**
* 根据给定的注释元数据,根据需要注册bean
*
* @param importingClassMetadata AnnotationMetadata
* @param registry BeanDefinitionRegistry
*/
@Override
public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) {
// 构建扫描对象
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true);
// 扫描包下路径
scanner.scan("xtools.boot.cache.redis");
}
}

View File

@@ -0,0 +1,36 @@
package xtools.boot.cache.redis.utils;
import xtools.boot.cache.redis.base.RedisService;
import xtools.boot.core.utils.SpringContextUtils;
/**
* <p>Title : RedisUtils</p>
* <p>Description : RedisUtils</p>
* <p>DevelopTools : Idea_x64_v2026.1</p>
* <p>DevelopSystem : macOS Sequoia 15.7.5</p>
* <p>Company : org.xujun</p>
*
* @author : XuJun
* @version : 5.0.0
* @date : 2026/2/10 09:02
*/
public class RedisUtils {
/**
* Redis 服务
**/
private static RedisService redisService;
/**
* 获取 Redis 服务
*
* @return Redis 服务
*/
public static RedisService get() {
if (redisService != null) {
return redisService;
}
return SpringContextUtils.getBean(RedisService.class);
}
}