Browse Source

代码优化

Woody 1 month ago
parent
commit
07f83f5eb5

+ 0 - 214
framework-base/src/main/java/com/chelvc/framework/base/cache/Caching.java

@@ -1,214 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.function.BiFunction;
-import java.util.function.Supplier;
-
-import org.apache.commons.lang3.tuple.Pair;
-
-/**
- * 信息缓存接口
- *
- * @author Woody
- * @date 2024/1/30
- */
-public interface Caching {
-    /**
-     * 获取缓存内容
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param <K>    缓存标识类型
-     * @param <V>    缓存内容类型
-     * @return 缓存对象实例
-     */
-    <K, V> V get(Naming naming, K id);
-
-    /**
-     * 获取缓存内容
-     *
-     * @param naming   缓存命名
-     * @param id       对象标识
-     * @param supplier 缓存对象缺失回调函数
-     * @param <K>      缓存标识类型
-     * @param <V>      缓存内容类型
-     * @return 缓存对象实例
-     */
-    <K, V> V get(Naming naming, K id, Supplier<V> supplier);
-
-    /**
-     * 批量获取缓存内容
-     *
-     * @param naming 缓存命名
-     * @param min    最小排序数字
-     * @param max    最大排序数字
-     * @param size   获取数量
-     * @param <V>    缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    <V> List<V> list(Naming naming, long min, long max, int size);
-
-    /**
-     * 批量获取缓存内容
-     *
-     * @param naming    缓存命名
-     * @param min       最小排序数字
-     * @param max       最大排序数字
-     * @param size      获取数量
-     * @param supplier  缓存对象缺失回调函数
-     * @param converter 缓存信息转换器
-     * @param <K>       缓存标识类型
-     * @param <V>       缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    <K, V> List<V> list(Naming naming, long min, long max, int size, BiFunction<Naming, Boolean, List<V>> supplier,
-                        Converter<K, V> converter);
-
-    /**
-     * 批量随机获取缓存内容
-     *
-     * @param naming 缓存命名
-     * @param min    最小排序数字
-     * @param max    最大排序数字
-     * @param size   获取数量(当size < 0 时获取全部内容)
-     * @param <V>    缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    <V> List<V> random(Naming naming, long min, long max, int size);
-
-    /**
-     * 批量随机获取缓存内容
-     *
-     * @param naming    缓存命名
-     * @param min       最小排序数字
-     * @param max       最大排序数字
-     * @param size      获取数量(当size < 0 时获取全部内容)
-     * @param supplier  缓存对象缺失回调函数
-     * @param converter 缓存信息转换器
-     * @param <K>       缓存标识类型
-     * @param <V>       缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    <K, V> List<V> random(Naming naming, long min, long max, int size, BiFunction<Naming, Boolean, List<V>> supplier,
-                          Converter<K, V> converter);
-
-    /**
-     * 设置缓存内容
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param value  缓存内容
-     * @param <K>    缓存标识类型
-     * @param <V>    缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean set(Naming naming, K id, V value);
-
-    /**
-     * 设置缓存内容
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param value  缓存内容
-     * @param order  排序数字
-     * @param <K>    缓存标识类型
-     * @param <V>    缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean set(Naming naming, K id, V value, long order);
-
-    /**
-     * 批量设置缓存内容
-     *
-     * @param naming    缓存命名
-     * @param values    缓存内容集合
-     * @param converter 缓存信息转换器
-     * @param <K>       缓存标识类型
-     * @param <V>       缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean set(Naming naming, Collection<V> values, Converter<K, V> converter);
-
-    /**
-     * 更新缓存内容
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param value  缓存内容
-     * @param order  排序数字
-     * @param <K>    缓存标识类型
-     * @param <V>    缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean update(Naming naming, K id, V value, long order);
-
-    /**
-     * 更新缓存内容
-     *
-     * @param naming    缓存命名
-     * @param value     缓存内容
-     * @param converter 缓存信息转换器
-     * @param <K>       缓存标识类型
-     * @param <V>       缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean update(Naming naming, V value, Converter<K, V> converter);
-
-    /**
-     * 批量更新缓存内容
-     *
-     * @param pairs     缓存命名/对象集合
-     * @param converter 缓存信息转换器
-     * @param <K>       缓存标识类型
-     * @param <V>       缓存内容类型
-     * @return true/false
-     */
-    <K, V> boolean update(Collection<Pair<Naming, V>> pairs, Converter<K, V> converter);
-
-    /**
-     * 移除缓存数据
-     *
-     * @param naming 缓存命名
-     * @return true/false
-     */
-    boolean remove(Naming naming);
-
-    /**
-     * 移除缓存数据
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param <K>    缓存标识类型
-     * @return true/false
-     */
-    <K> boolean remove(Naming naming, K id);
-
-    /**
-     * 移除缓存数据
-     *
-     * @param pairs 缓存命名/标识集合
-     * @param <K>   缓存标识类型
-     * @return true/false
-     */
-    <K> boolean remove(Collection<Pair<Naming, K>> pairs);
-
-    /**
-     * 清理缓存数据,移除所有相关缓存数据
-     *
-     * @param naming 缓存命名
-     * @param id     对象标识
-     * @param <K>    缓存标识类型
-     * @return true/false
-     */
-    <K> boolean clear(Naming naming, K id);
-
-    /**
-     * 清理缓存数据,移除所有相关缓存数据
-     *
-     * @param pairs 移除命名/标识集合
-     * @param <K>   缓存标识类型
-     * @return true/false
-     */
-    <K> boolean clear(Collection<Pair<Naming, K>> pairs);
-}

+ 0 - 27
framework-base/src/main/java/com/chelvc/framework/base/cache/Converter.java

@@ -1,27 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-/**
- * 缓存信息转换接口
- *
- * @param <K> 缓存标识类型
- * @param <V> 缓存内容类型
- * @author Woody
- * @date 2024/1/30
- */
-public interface Converter<K, V> {
-    /**
-     * 获取缓存对象标识
-     *
-     * @param object 缓存对象实例
-     * @return 对象标识
-     */
-    K id(V object);
-
-    /**
-     * 获取缓存对象排序
-     *
-     * @param object 缓存对象实例
-     * @return 排序数字
-     */
-    long order(V object);
-}

+ 0 - 209
framework-base/src/main/java/com/chelvc/framework/base/cache/Naming.java

@@ -1,209 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import com.chelvc.framework.common.util.AssertUtils;
-import com.chelvc.framework.common.util.StringUtils;
-import lombok.Getter;
-import lombok.NonNull;
-
-/**
- * 缓存命名对象
- *
- * @author Woody
- * @date 2024/1/30
- */
-@Getter
-public class Naming implements Serializable {
-    /**
-     * 主体缓存名称
-     */
-    private final String primary;
-
-    /**
-     * 索引缓存名称集合
-     */
-    private final List<String> indexes;
-
-    /**
-     * 获取缓存标识列表
-     */
-    private final List<String> keys;
-
-    /**
-     * 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     */
-    private final long duration;
-
-    /**
-     * 缓存内容是否降序排序
-     */
-    private final boolean reversed;
-
-    private Naming(@NonNull String primary, @NonNull List<String> indexes, long duration, boolean reversed) {
-        AssertUtils.nonempty(primary, () -> "Naming primary must not be empty");
-        AssertUtils.nonempty(indexes, () -> "Naming index must not be empty");
-        this.primary = primary;
-        this.indexes = Collections.unmodifiableList(indexes);
-        this.duration = duration;
-        this.reversed = reversed;
-
-        // 组装缓存标识列表
-        int i = 0;
-        String[] keys = new String[indexes.size() + 1];
-        keys[i++] = primary;
-        for (String index : indexes) {
-            keys[i++] = index;
-        }
-        this.keys = Arrays.asList(keys);
-    }
-
-    @Override
-    public String toString() {
-        return StringUtils.join(this.keys, "|");
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param name 缓存名称
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String name) {
-        return of(name, name, -1, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param name     缓存名称
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String name, long duration) {
-        return of(name, name, duration, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param name     缓存名称
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String name, boolean reversed) {
-        return of(name, name, -1, reversed);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param name     缓存名称
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String name, long duration, boolean reversed) {
-        return of(name, name, duration, reversed);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary 主体缓存名称
-     * @param index   索引缓存名称
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull String index) {
-        return of(primary, index, -1, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param index    索引缓存名称
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull String index, long duration) {
-        return of(primary, index, duration, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param index    索引缓存名称
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull String index, boolean reversed) {
-        return of(primary, index, -1, reversed);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param index    索引缓存名称
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull String index, long duration, boolean reversed) {
-        AssertUtils.nonempty(index, () -> "Naming index must not be empty");
-        return of(primary, Collections.singletonList(index), duration, reversed);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary 主体缓存名称
-     * @param indexes 索引缓存名称列表
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull List<String> indexes) {
-        return new Naming(primary, indexes, -1, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param indexes  索引缓存名称列表
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull List<String> indexes, long duration) {
-        return new Naming(primary, indexes, duration, false);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param indexes  索引缓存名称列表
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull List<String> indexes, boolean reversed) {
-        return new Naming(primary, indexes, -1, reversed);
-    }
-
-    /**
-     * 构建缓存命名对象
-     *
-     * @param primary  主体缓存名称
-     * @param indexes  索引缓存名称列表
-     * @param duration 缓存有效时长(秒),当 duration > 0 时有效,否则表示永久有效
-     * @param reversed 缓存内容是否降序排序
-     * @return 缓存命名对象实例
-     */
-    public static Naming of(@NonNull String primary, @NonNull List<String> indexes, long duration, boolean reversed) {
-        return new Naming(primary, indexes, duration, reversed);
-    }
-}

+ 0 - 94
framework-base/src/main/java/com/chelvc/framework/base/cache/NamingAdapter.java

@@ -1,94 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-import java.util.List;
-import java.util.Objects;
-
-import lombok.NonNull;
-
-/**
- * 缓存命名适配接口
- *
- * @param <Q> 查询对象类型
- * @param <V> 缓存对象类型
- * @author Woody
- * @date 2024/1/30
- */
-public interface NamingAdapter<Q, V> {
-    /**
-     * 获取主体缓存命名
-     *
-     * @return 缓存命名对象实例
-     */
-    Naming primary();
-
-    /**
-     * 序列化查询对象
-     *
-     * @param object 查询对象实例
-     * @return 缓存名称列表
-     */
-    List<String> query2string(Q object);
-
-    /**
-     * 序列化更新对象
-     *
-     * @param object 更新对象实例
-     * @return 缓存名称列表
-     */
-    List<String> modify2string(V object);
-
-    /**
-     * 比较缓存对象命名是否相同
-     *
-     * @param object 缓存对象
-     * @param other  缓存对象
-     * @return true/false
-     */
-    default boolean equals(V object, V other) {
-        return Objects.equals(object, other);
-    }
-
-    /**
-     * 查询对象缓存命名适配
-     *
-     * @param object 对象实例
-     * @return 缓存命名对象实例
-     */
-    default Naming querying(@NonNull Q object) {
-        return this.querying(object, this.primary().getDuration());
-    }
-
-    /**
-     * 查询对象缓存命名适配
-     *
-     * @param object   对象实例
-     * @param duration 缓存有效时长(秒)
-     * @return 缓存命名对象实例
-     */
-    default Naming querying(@NonNull Q object, long duration) {
-        Naming primary = this.primary();
-        return Naming.of(primary.getPrimary(), this.query2string(object), duration, primary.isReversed());
-    }
-
-    /**
-     * 更新对象缓存命名适配
-     *
-     * @param object 对象实例
-     * @return 缓存命名对象实例
-     */
-    default Naming modifying(@NonNull V object) {
-        return this.modifying(object, this.primary().getDuration());
-    }
-
-    /**
-     * 更新对象缓存命名适配
-     *
-     * @param object   对象实例
-     * @param duration 缓存有效时长(秒)
-     * @return 缓存命名对象实例
-     */
-    default Naming modifying(@NonNull V object, long duration) {
-        Naming primary = this.primary();
-        return Naming.of(primary.getPrimary(), this.modify2string(object), duration, primary.isReversed());
-    }
-}

+ 0 - 318
framework-base/src/main/java/com/chelvc/framework/base/cache/ObjectCaching.java

@@ -1,318 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.BiFunction;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import com.chelvc.framework.common.util.ObjectUtils;
-import lombok.NonNull;
-import org.apache.commons.lang3.tuple.Pair;
-
-/**
- * 对象缓存抽象实现
- *
- * @param <K> 对象标识类型
- * @param <Q> 查询对象类型
- * @param <V> 缓存对象类型
- * @author Woody
- * @date 2024/1/30
- */
-public abstract class ObjectCaching<K, Q, V> {
-    private volatile Caching caching;
-    private volatile Converter<K, V> converter;
-    private volatile NamingAdapter<Q, V> namingAdapter;
-
-    /**
-     * 缓存开关是否开启
-     *
-     * @return true/false
-     */
-    protected boolean isEnabled() {
-        return true;
-    }
-
-    /**
-     * 初始化数据缓存
-     *
-     * @return 缓存对象实例
-     */
-    protected abstract Caching initializeCaching();
-
-    /**
-     * 初始化缓存信息转换器
-     *
-     * @return 缓存信息转换器实例
-     */
-    protected abstract Converter<K, V> initializeConverter();
-
-    /**
-     * 初始化缓存命名适配器
-     *
-     * @return 缓存命名适配器对象实例
-     */
-    protected abstract NamingAdapter<Q, V> initializeNamingAdapter();
-
-    /**
-     * 获取数据缓存器
-     *
-     * @return 缓存对象实例
-     */
-    protected final Caching getCaching() {
-        if (this.caching == null) {
-            synchronized (Caching.class) {
-                if (this.caching == null) {
-                    this.caching = Objects.requireNonNull(this.initializeCaching());
-                }
-            }
-        }
-        return this.caching;
-    }
-
-    /**
-     * 获取缓存信息转换器
-     *
-     * @return 缓存信息转换器实例
-     */
-    protected final Converter<K, V> getConverter() {
-        if (this.converter == null) {
-            synchronized (Converter.class) {
-                if (this.converter == null) {
-                    this.converter = Objects.requireNonNull(this.initializeConverter());
-                }
-            }
-        }
-        return this.converter;
-    }
-
-    /**
-     * 获取缓存命名适配器
-     *
-     * @return 缓存命名适配器实例
-     */
-    protected final NamingAdapter<Q, V> getNamingAdapter() {
-        if (this.namingAdapter == null) {
-            synchronized (NamingAdapter.class) {
-                if (this.namingAdapter == null) {
-                    this.namingAdapter = Objects.requireNonNull(this.initializeNamingAdapter());
-                }
-            }
-        }
-        return this.namingAdapter;
-    }
-
-    /**
-     * 获取缓存对象
-     *
-     * @param id 对象标识
-     * @return 对象实例
-     */
-    public V get(@NonNull K id) {
-        if (!this.isEnabled()) {
-            return null;
-        }
-        Naming naming = this.getNamingAdapter().primary();
-        return this.getCaching().get(naming, id);
-    }
-
-    /**
-     * 获取缓存对象
-     *
-     * @param id       对象标识
-     * @param supplier 缓存对象缺失回调函数
-     * @return 对象实例
-     */
-    public V get(@NonNull K id, @NonNull Supplier<V> supplier) {
-        if (this.isEnabled()) {
-            Naming naming = this.getNamingAdapter().primary();
-            return this.getCaching().get(naming, id, supplier);
-        }
-        return supplier.get();
-    }
-
-    /**
-     * 批量获取缓存对象
-     *
-     * @param query 查询对象
-     * @param min   最小排序数字
-     * @param max   最大排序数字
-     * @param size  获取数量
-     * @return 缓存对象实例列表
-     */
-    public List<V> list(@NonNull Q query, long min, long max, int size) {
-        if (this.isEnabled()) {
-            Naming naming = this.getNamingAdapter().querying(query);
-            return this.getCaching().list(naming, min, max, size);
-        }
-        return Collections.emptyList();
-    }
-
-    /**
-     * 批量获取缓存对象
-     *
-     * @param query    查询对象
-     * @param min      最小排序数字
-     * @param max      最大排序数字
-     * @param size     获取数量
-     * @param supplier 缓存对象缺失回调函数
-     * @return 缓存对象实例列表
-     */
-    public List<V> list(@NonNull Q query, long min, long max, int size,
-                        @NonNull BiFunction<Naming, Boolean, List<V>> supplier) {
-        Naming naming = this.getNamingAdapter().querying(query);
-        if (this.isEnabled()) {
-            return this.getCaching().list(naming, min, max, size, supplier, this.getConverter());
-        }
-        List<V> objects = supplier.apply(naming, true);
-        if (ObjectUtils.isEmpty(objects)) {
-            return Collections.emptyList();
-        }
-        return objects.size() <= size ? objects : objects.subList(0, size);
-    }
-
-    /**
-     * 批量随机获取缓存对象
-     *
-     * @param query 查询对象
-     * @param min   最小排序数字
-     * @param max   最大排序数字
-     * @param size  获取数量(当size < 0 时获取全部内容)
-     * @return 缓存对象实例列表
-     */
-    public List<V> random(@NonNull Q query, long min, long max, int size) {
-        if (this.isEnabled()) {
-            Naming naming = this.getNamingAdapter().querying(query);
-            return this.getCaching().random(naming, min, max, size);
-        }
-        return Collections.emptyList();
-    }
-
-    /**
-     * 批量随机获取缓存对象
-     *
-     * @param query    查询对象
-     * @param min      最小排序数字
-     * @param max      最大排序数字
-     * @param size     获取数量(当size < 0 时获取全部内容)
-     * @param supplier 补充缓存列表回调函数
-     * @return 缓存对象实例列表
-     */
-    public List<V> random(@NonNull Q query, long min, long max, int size,
-                          @NonNull BiFunction<Naming, Boolean, List<V>> supplier) {
-        Naming naming = this.getNamingAdapter().querying(query);
-        if (this.isEnabled()) {
-            return this.getCaching().random(naming, min, max, size, supplier, this.getConverter());
-        }
-        List<V> objects = supplier.apply(naming, true);
-        if (ObjectUtils.isEmpty(objects)) {
-            return Collections.emptyList();
-        }
-        return size < 0 || objects.size() <= size ? objects : objects.subList(0, size);
-    }
-
-    /**
-     * 清空缓存数据
-     *
-     * @return true/false
-     */
-    public boolean clear() {
-        Naming naming = this.getNamingAdapter().primary();
-        return this.getCaching().remove(naming);
-    }
-
-    /**
-     * 设置缓存对象
-     *
-     * @param object 对象实例
-     * @return true/false
-     */
-    public boolean set(@NonNull V object) {
-        if (!this.isEnabled()) {
-            return false;
-        }
-        K id = this.getConverter().id(object);
-        Naming naming = this.getNamingAdapter().primary();
-        return this.getCaching().set(naming, id, object);
-    }
-
-    /**
-     * 批量设置缓存对象
-     *
-     * @param objects 对象实例集合
-     * @return true/false
-     */
-    public boolean set(@NonNull Collection<V> objects) {
-        if (!this.isEnabled() || ObjectUtils.isEmpty(objects)) {
-            return false;
-        }
-        Naming naming = this.getNamingAdapter().primary();
-        return this.getCaching().set(naming, objects, this.getConverter());
-    }
-
-    /**
-     * 更新缓存对象
-     *
-     * @param object 对象实例
-     * @return true/false
-     */
-    public boolean update(@NonNull V object) {
-        if (!this.isEnabled()) {
-            return false;
-        }
-        K id = this.getConverter().id(object);
-        long order = this.getConverter().order(object);
-        Naming naming = this.getNamingAdapter().modifying(object);
-        return this.getCaching().update(naming, id, object, order);
-    }
-
-    /**
-     * 批量更新缓存对象
-     *
-     * @param objects 对象实例集合
-     * @return true/false
-     */
-    public boolean update(@NonNull Collection<V> objects) {
-        if (!this.isEnabled() || ObjectUtils.isEmpty(objects)) {
-            return false;
-        }
-        NamingAdapter<Q, V> adapter = this.getNamingAdapter();
-        List<Pair<Naming, V>> pairs = objects.stream().map(object -> Pair.of(adapter.modifying(object), object))
-                .collect(Collectors.toList());
-        return this.getCaching().update(pairs, this.getConverter());
-    }
-
-    /**
-     * 移除缓存对象
-     *
-     * @param object 对象实例
-     * @return true/false
-     */
-    public boolean remove(@NonNull V object) {
-        if (!this.isEnabled()) {
-            return false;
-        }
-        K id = this.getConverter().id(object);
-        Naming naming = this.getNamingAdapter().modifying(object);
-        return this.getCaching().clear(naming, id);
-    }
-
-    /**
-     * 批量移除缓存对象
-     *
-     * @param objects 对象实例集合
-     * @return true/false
-     */
-    public boolean remove(@NonNull Collection<V> objects) {
-        if (!this.isEnabled() || ObjectUtils.isEmpty(objects)) {
-            return false;
-        }
-        Converter<K, V> converter = this.getConverter();
-        NamingAdapter<Q, V> adapter = this.getNamingAdapter();
-        List<Pair<Naming, K>> pairs = objects.stream()
-                .map(object -> Pair.of(adapter.modifying(object), converter.id(object))).collect(Collectors.toList());
-        return this.getCaching().clear(pairs);
-    }
-}

+ 0 - 127
framework-base/src/main/java/com/chelvc/framework/base/cache/ObjectNamingAdapter.java

@@ -1,127 +0,0 @@
-package com.chelvc.framework.base.cache;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.TreeMap;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import com.chelvc.framework.common.util.AssertUtils;
-import com.chelvc.framework.common.util.ObjectUtils;
-import com.chelvc.framework.common.util.StringUtils;
-import com.google.common.collect.Lists;
-import lombok.NonNull;
-import org.apache.commons.lang3.tuple.Pair;
-
-/**
- * 基于对象的缓存命名适配器实现
- *
- * @param <Q> 查询对象类型
- * @param <V> 缓存对象类型
- * @author Woody
- * @date 2024/1/30
- */
-public class ObjectNamingAdapter<Q, V> implements NamingAdapter<Q, V> {
-    /**
-     * 主体缓存命名
-     */
-    private final Naming primary;
-
-    /**
-     * 对象属性/Getter方法映射表
-     */
-    private final Map<String, Pair<Function<Q, ?>, Function<V, ?>>> getters;
-
-    public ObjectNamingAdapter(@NonNull Naming primary,
-                               @NonNull Map<String, Pair<Function<Q, ?>, Function<V, ?>>> getters) {
-        AssertUtils.nonempty(getters, () -> "Naming adapter getters must not be empty");
-        getters.forEach((field, functions) -> {
-            AssertUtils.nonempty(field, () -> "Naming adapter getter field must not be empty");
-            AssertUtils.nonnull(functions, () -> "Naming adapter getters must not be null");
-            AssertUtils.nonnull(functions.getLeft(), () -> "Naming adapter getters left must not be null");
-            AssertUtils.nonnull(functions.getRight(), () -> "Naming adapter getters right must not be null");
-        });
-        this.primary = primary;
-        this.getters = new TreeMap<>(getters);
-    }
-
-    @Override
-    public Naming primary() {
-        return this.primary;
-    }
-
-    @Override
-    public List<String> query2string(@NonNull Q object) {
-        StringBuilder buffer = new StringBuilder(this.primary.getPrimary());
-        this.getters.forEach((field, functions) -> {
-            Object value = functions.getLeft().apply(object);
-            buffer.append(":").append(field).append(StringUtils.EQUAL);
-            if (ObjectUtils.notBlank(value)) {
-                int length = buffer.length();
-                ObjectUtils.stream(value).filter(StringUtils::notEmpty).map(Object::toString)
-                        .sorted().forEach(item -> buffer.append("#").append(item));
-                if (buffer.length() > length) {
-                    buffer.append("#");
-                }
-            }
-        });
-        return Collections.singletonList(buffer.toString());
-    }
-
-    @Override
-    public List<String> modify2string(@NonNull V object) {
-        // 对象属性值排列
-        List<List<StringBuilder>> conditions = Lists.newArrayListWithCapacity(this.getters.size());
-        this.getters.forEach((field, functions) -> {
-            Stream<?> values = ObjectUtils.stream(functions.getRight().apply(object));
-            List<StringBuilder> buffers = values.distinct().map(value -> {
-                StringBuilder buffer = new StringBuilder(field).append(StringUtils.EQUAL);
-                if (StringUtils.notEmpty(value)) {
-                    buffer.append("*#").append(value).append("#*");
-                }
-                return buffer;
-            }).collect(Collectors.toList());
-            if (ObjectUtils.notEmpty(buffers)) {
-                conditions.add(buffers);
-            }
-        });
-        if (ObjectUtils.isEmpty(conditions)) {
-            return Collections.emptyList();
-        }
-
-        // 组合匹配条件
-        List<StringBuilder> roots = Collections.emptyList();
-        for (List<StringBuilder> buffers : conditions) {
-            if (ObjectUtils.isEmpty(roots)) {
-                buffers.forEach(buffer -> buffer.insert(0, ":").insert(0, this.primary.getPrimary()));
-                roots = buffers;
-            } else if (buffers.size() > 1) {
-                roots = roots.stream().flatMap(root -> buffers.stream().map(
-                        buffer -> new StringBuilder(root).append(":").append(buffer)
-                )).collect(Collectors.toList());
-            } else {
-                roots.forEach(root -> root.append(":").append(buffers.get(0)));
-            }
-        }
-        return roots.stream().map(StringBuilder::toString).collect(Collectors.toList());
-    }
-
-    @Override
-    public boolean equals(V object, V other) {
-        if (object == other || ObjectUtils.isEmpty(this.getters)) {
-            return Objects.equals(object, other);
-        } else if (object != null && other != null) {
-            for (Pair<Function<Q, ?>, Function<V, ?>> functions : this.getters.values()) {
-                Function<V, ?> function = functions.getRight();
-                if (!ObjectUtils.equals(function.apply(object), function.apply(other))) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-}

+ 26 - 75
framework-base/src/main/java/com/chelvc/framework/base/context/LoggingContextHolder.java

@@ -2,6 +2,7 @@ package com.chelvc.framework.base.context;
 
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 
 import ch.qos.logback.classic.Level;
@@ -41,34 +42,27 @@ public final class LoggingContextHolder {
     /**
      * 获取日志信息
      *
-     * @param messages 消息内容数组
-     * @return 消息内容
-     */
-    public static String message(@NonNull Object... messages) {
-        return message(SessionContextHolder.getRequest(), messages);
-    }
-
-    /**
-     * 获取日志信息
-     *
-     * @param request Http请求对象
+     * @param request 请求对象
      * @param t       异常对象实例
      * @return 消息内容
      */
-    public static String message(HttpServletRequest request, Throwable t) {
+    public static String message(ServletRequest request, Throwable t) {
         return message(request, ObjectUtils.ifNull(t, Throwable::getMessage));
     }
 
     /**
      * 获取日志信息
      *
-     * @param request  Http请求对象
+     * @param request  请求对象
      * @param messages 消息内容数组
      * @return 消息内容
      */
-    public static String message(HttpServletRequest request, @NonNull Object... messages) {
-        String uri = ObjectUtils.ifNull(request, HttpServletRequest::getRequestURI);
-        String method = ObjectUtils.ifNull(request, HttpServletRequest::getMethod);
+    public static String message(ServletRequest request, @NonNull Object... messages) {
+        String uri = null, method = null;
+        if (request instanceof HttpServletRequest) {
+            uri = ((HttpServletRequest) request).getRequestURI();
+            method = ((HttpServletRequest) request).getMethod();
+        }
         String parameter = request == null || HttpUtils.isMultipart(request) ? null : HttpUtils.serialize(request);
         return message(uri, method, parameter, messages);
     }
@@ -160,20 +154,10 @@ public final class LoggingContextHolder {
      * 打印正常日志
      *
      * @param logger   日志处理器
+     * @param request  请求对象
      * @param messages 消息数组
      */
-    public static void info(@NonNull Logger logger, @NonNull Object... messages) {
-        logger.info(message(messages));
-    }
-
-    /**
-     * 打印正常日志
-     *
-     * @param logger   日志处理器
-     * @param request  Http请求对象
-     * @param messages 消息数组
-     */
-    public static void info(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Object... messages) {
+    public static void info(@NonNull Logger logger, ServletRequest request, @NonNull Object... messages) {
         logger.info(message(request, messages));
     }
 
@@ -202,24 +186,14 @@ public final class LoggingContextHolder {
         }
     }
 
-    /**
-     * 打印告警日志
-     *
-     * @param logger   日志处理器
-     * @param messages 消息数组
-     */
-    public static void warn(@NonNull Logger logger, @NonNull Object... messages) {
-        logger.warn(message(messages));
-    }
-
     /**
      * 打印告警日志
      *
      * @param logger  日志处理器
-     * @param request Http请求对象
+     * @param request 请求对象
      * @param t       异常对象实例
      */
-    public static void warn(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Throwable t) {
+    public static void warn(@NonNull Logger logger, ServletRequest request, @NonNull Throwable t) {
         warn(logger, request, t, false);
     }
 
@@ -227,12 +201,11 @@ public final class LoggingContextHolder {
      * 打印告警日志
      *
      * @param logger  日志处理器
-     * @param request Http请求对象
+     * @param request 请求对象
      * @param t       异常对象实例
      * @param tracing 是否打印堆栈
      */
-    public static void warn(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Throwable t,
-                            boolean tracing) {
+    public static void warn(@NonNull Logger logger, ServletRequest request, @NonNull Throwable t, boolean tracing) {
         if (tracing) {
             logger.warn(message(request, t), t);
         } else {
@@ -244,10 +217,10 @@ public final class LoggingContextHolder {
      * 打印告警日志
      *
      * @param logger   日志处理器
-     * @param request  Http请求对象
+     * @param request  请求对象
      * @param messages 消息数组
      */
-    public static void warn(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Object... messages) {
+    public static void warn(@NonNull Logger logger, ServletRequest request, @NonNull Object... messages) {
         logger.warn(message(request, messages));
     }
 
@@ -261,24 +234,14 @@ public final class LoggingContextHolder {
         logger.error(message(t), t);
     }
 
-    /**
-     * 打印错误日志
-     *
-     * @param logger   日志处理器
-     * @param messages 消息数组
-     */
-    public static void error(@NonNull Logger logger, @NonNull Object... messages) {
-        logger.error(message(messages));
-    }
-
     /**
      * 打印错误日志
      *
      * @param logger  日志处理器
-     * @param request Http请求对象
+     * @param request 请求对象
      * @param t       异常对象实例
      */
-    public static void error(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Throwable t) {
+    public static void error(@NonNull Logger logger, ServletRequest request, @NonNull Throwable t) {
         logger.error(message(request, t), t);
     }
 
@@ -286,10 +249,10 @@ public final class LoggingContextHolder {
      * 打印错误日志
      *
      * @param logger   日志处理器
-     * @param request  Http请求对象
+     * @param request  请求对象
      * @param messages 消息数组
      */
-    public static void error(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Object... messages) {
+    public static void error(@NonNull Logger logger, ServletRequest request, @NonNull Object... messages) {
         logger.error(message(request, messages));
     }
 
@@ -305,26 +268,14 @@ public final class LoggingContextHolder {
         }
     }
 
-    /**
-     * 打印调试日志
-     *
-     * @param logger   日志处理器
-     * @param messages 消息数组
-     */
-    public static void debug(@NonNull Logger logger, @NonNull Object... messages) {
-        if (logger.isDebugEnabled()) {
-            logger.debug(message(messages));
-        }
-    }
-
     /**
      * 打印调试日志
      *
      * @param logger  日志处理器
-     * @param request Http请求对象
+     * @param request 请求对象
      * @param t       异常对象实例
      */
-    public static void debug(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Throwable t) {
+    public static void debug(@NonNull Logger logger, ServletRequest request, @NonNull Throwable t) {
         if (logger.isDebugEnabled()) {
             logger.debug(message(request, t), t);
         }
@@ -334,10 +285,10 @@ public final class LoggingContextHolder {
      * 打印调试日志
      *
      * @param logger   日志处理器
-     * @param request  Http请求对象
+     * @param request  请求对象
      * @param messages 消息数组
      */
-    public static void debug(@NonNull Logger logger, @NonNull HttpServletRequest request, @NonNull Object... messages) {
+    public static void debug(@NonNull Logger logger, ServletRequest request, @NonNull Object... messages) {
         if (logger.isDebugEnabled()) {
             logger.debug(message(request, messages));
         }

+ 3 - 2
framework-base/src/main/java/com/chelvc/framework/base/interceptor/ControllerAccessInterceptor.java

@@ -2,6 +2,7 @@ package com.chelvc.framework.base.interceptor;
 
 import ch.qos.logback.classic.Level;
 import com.chelvc.framework.base.context.LoggingContextHolder;
+import com.chelvc.framework.base.context.SessionContextHolder;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
@@ -54,11 +55,11 @@ public class ControllerAccessInterceptor {
     public Object logging(ProceedingJoinPoint point) throws Throwable {
         boolean debug = this.isDebug(point);
         if (debug) {
-            LoggingContextHolder.debug(log, point.getArgs());
+            LoggingContextHolder.debug(log, SessionContextHolder.getRequest(), point.getArgs());
         }
         Object value = point.proceed();
         if (debug) {
-            LoggingContextHolder.debug(log, value);
+            LoggingContextHolder.debug(log, SessionContextHolder.getRequest(), value);
         }
         return value;
     }

+ 10 - 12
framework-group/src/main/java/com/chelvc/framework/group/GroupClient.java

@@ -20,7 +20,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 @FeignClient(value = "${group.store-server}")
 public interface GroupClient {
     /**
-     * 获取分组标识
+     * 获取场景分组
      *
      * @param scene 场景标识
      * @return 分组标识
@@ -29,30 +29,28 @@ public interface GroupClient {
     Caps get(@PathVariable("scene") String scene);
 
     /**
-     * 批量获取分组标识
+     * 批量获取场景分组
      *
-     * @param scenes 分组场景集合
-     * @return 分组场景/标识映射表
+     * @param scenes 场景标识集合
+     * @return 场景/分组映射表
      */
     @GetMapping("/grouping")
     Map<String, Caps> get(@RequestParam("scenes") Collection<String> scenes);
 
     /**
-     * 设置分组标识,如果分组不存在则设置分组,否则忽略
+     * 设置场景分组
      *
-     * @param scene 分组场景
+     * @param scene 场景标识
      * @param group 分组标识
-     * @return 分组标识
      */
     @PostMapping("/grouping/{scene}/{group}")
-    Caps set(@PathVariable("scene") String scene, @PathVariable("group") Caps group);
+    void set(@PathVariable("scene") String scene, @PathVariable("group") Caps group);
 
     /**
-     * 批量设置分组标识,如果分组不存在则设置分组,否则忽略
+     * 批量设置场景分组
      *
-     * @param groups 分组场景/标识映射表
-     * @return 分组场景/标识映射表
+     * @param groups 场景/分组映射表
      */
     @PostMapping("/grouping")
-    Map<String, Caps> set(@RequestBody Map<String, Caps> groups);
+    void set(@RequestBody Map<String, Caps> groups);
 }

+ 9 - 9
framework-group/src/main/java/com/chelvc/framework/group/GroupStore.java

@@ -13,7 +13,7 @@ import com.chelvc.framework.common.model.Caps;
  */
 public interface GroupStore {
     /**
-     * 获取分组标识
+     * 获取场景分组
      *
      * @param scene 场景标识
      * @return 分组标识
@@ -21,27 +21,27 @@ public interface GroupStore {
     Caps get(String scene);
 
     /**
-     * 批量获取分组标识
+     * 批量获取场景分组
      *
-     * @param scenes 分组场景集合
-     * @return 分组场景/标识映射表
+     * @param scenes 分组标识集合
+     * @return 场景/分组映射表
      */
     Map<String, Caps> get(Collection<String> scenes);
 
     /**
-     * 设置分组标识,如果分组不存在则设置分组,否则忽略
+     * 设置场景分组,如果分组不存在则设置分组,否则忽略
      *
-     * @param scene 分组场景
+     * @param scene 场景标识
      * @param group 分组标识
      * @return 分组标识
      */
     Caps set(String scene, Caps group);
 
     /**
-     * 批量设置分组标识,如果分组不存在则设置分组,否则忽略
+     * 批量设置场景分组,如果分组不存在则设置分组,否则忽略
      *
-     * @param groups 分组场景/标识映射表
-     * @return 分组场景/标识映射表
+     * @param groups 分组/场景映射表
+     * @return 分组/场景映射表
      */
     Map<String, Caps> set(Map<String, Caps> groups);
 }

+ 110 - 23
framework-group/src/main/java/com/chelvc/framework/group/RedisGroupStore.java

@@ -6,6 +6,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import com.chelvc.framework.base.context.SessionContextHolder;
 import com.chelvc.framework.common.model.Caps;
@@ -14,11 +15,15 @@ import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.group.context.GroupContextHolder;
 import com.chelvc.framework.redis.context.RedisContextHolder;
 import com.chelvc.framework.redis.context.RedisHashHolder;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import lombok.NonNull;
+import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisOperations;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.SessionCallback;
 
 /**
  * 场景分组存储Redis缓存实现
@@ -43,6 +48,94 @@ public class RedisGroupStore implements GroupStore {
         return id == null ? null : ("group:" + id);
     }
 
+    /**
+     * 设置场景分组,如果存在则使用原值,否则更新
+     *
+     * @param key   缓存标识
+     * @param scene 场景标识
+     * @param group 分组标识
+     * @return 分组标识
+     */
+    private Caps setnx(String key, String scene, Caps group) {
+        // 更新场景分组缓存
+        RedisTemplate<String, Object> template = RedisContextHolder.getDefaultTemplate();
+        List<Object> results = template.executePipelined(new SessionCallback<Object>() {
+            @Override
+            @SuppressWarnings("unchecked")
+            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
+                // 设置分组信息,如果已存在则忽略
+                operations.opsForHash().putIfAbsent((K) key, scene, group.name());
+
+                // 设置分组过期时间(1天)
+                operations.expire((K) key, 1, TimeUnit.DAYS);
+                return null;
+            }
+        });
+
+        // 如果缓存更新成功则持久化分组信息
+        if (Boolean.TRUE.equals(results.get(0))) {
+            this.client.set(scene, group);
+            return group;
+        }
+
+        // 如果分组已存在则获取已有分组
+        HashOperations<String, String, String> operations = template.opsForHash();
+        return StringUtils.ifEmpty(operations.get(key, scene), Caps::valueOf);
+    }
+
+    /**
+     * 批量设置场景分组,如果存在则使用原值,否则更新
+     *
+     * @param key    缓存标识
+     * @param groups 场景/分组映射表
+     * @return 场景/分组映射表
+     */
+    private Map<String, Caps> setnx(String key, Map<String, Caps> groups) {
+        // 批量更新场景分组缓存
+        Map<String, Caps> stored = Maps.newLinkedHashMap(groups);
+        RedisTemplate<String, Object> template = RedisContextHolder.getDefaultTemplate();
+        List<Object> results = template.executePipelined(new SessionCallback<Object>() {
+            @Override
+            @SuppressWarnings("unchecked")
+            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
+                // 设置分组信息,如果已存在则忽略
+                stored.forEach((scene, group) -> operations.opsForHash().putIfAbsent((K) key, scene, group.name()));
+
+                // 设置分组过期时间(1天)
+                operations.expire((K) key, 1, TimeUnit.DAYS);
+                return null;
+            }
+        });
+
+        // 获取缓存已存在的场景标识
+        List<String> exists = Lists.newLinkedList();
+        Iterator<String> iterator = stored.keySet().iterator();
+        for (int i = 0, size = results.size(); i < size && iterator.hasNext(); i++) {
+            String scene = iterator.next();
+            if (!Boolean.TRUE.equals(results.get(i))) {
+                exists.add(scene);
+
+                // 移除更新失败(已存在)场景分组
+                iterator.remove();
+            }
+        }
+
+        // 持久化缓存更新成功的场景分组
+        if (ObjectUtils.notEmpty(stored)) {
+            this.client.set(stored);
+        }
+
+        // 重新加载已存在缓存的场景分组
+        if (ObjectUtils.notEmpty(exists)) {
+            HashOperations<String, String, String> operations = template.opsForHash();
+            List<String> values = operations.multiGet(key, exists);
+            for (int i = 0, size = exists.size(); i < size; i++) {
+                stored.put(exists.get(i), StringUtils.ifEmpty(values.get(i), Caps::valueOf));
+            }
+        }
+        return stored;
+    }
+
     @Override
     public Caps get(@NonNull String scene) {
         String key = this.key();
@@ -61,7 +154,7 @@ public class RedisGroupStore implements GroupStore {
         HashOperations<String, String, String> operations = template.opsForHash();
         group = StringUtils.ifEmpty(operations.get(key, scene), Caps::valueOf);
         if (group == null && (group = this.client.get(scene)) != null) {
-            RedisHashHolder.set(template, key, scene, group, Duration.ofDays(2));
+            RedisHashHolder.set(template, key, scene, group, Duration.ofDays(1));
         }
         return group;
     }
@@ -75,29 +168,29 @@ public class RedisGroupStore implements GroupStore {
 
         // 优先获取配置分组
         List<String> nones = Lists.newLinkedList();
-        Map<String, Caps> mapping = Maps.newHashMapWithExpectedSize(scenes.size());
+        Map<String, Caps> groups = Maps.newHashMapWithExpectedSize(scenes.size());
         for (String scene : scenes) {
             Caps group = GroupContextHolder.getConfig(scene);
             if (group == null) {
                 nones.add(scene);
             } else {
-                mapping.put(scene, group);
+                groups.put(scene, group);
             }
         }
 
         // 批量获取缓存分组映射
+        RedisTemplate<String, Object> template = RedisContextHolder.getDefaultTemplate();
         if (ObjectUtils.notEmpty(nones)) {
-            RedisTemplate<String, Object> template = RedisContextHolder.getDefaultTemplate();
             HashOperations<String, String, String> operations = template.opsForHash();
-            List<String> groups = operations.multiGet(key, nones);
+            List<String> values = operations.multiGet(key, nones);
 
             int i = 0;
             Iterator<String> iterator = nones.iterator();
             while (iterator.hasNext()) {
-                String group = groups.get(i++);
+                String group = values.get(i++);
                 String scene = iterator.next();
                 if (StringUtils.notEmpty(group)) {
-                    mapping.put(scene, Caps.valueOf(group));
+                    groups.put(scene, Caps.valueOf(group));
                     iterator.remove();
                 }
             }
@@ -107,24 +200,17 @@ public class RedisGroupStore implements GroupStore {
         if (ObjectUtils.notEmpty(nones)) {
             Map<String, Caps> reloads = this.client.get(nones);
             if (ObjectUtils.notEmpty(reloads)) {
-                mapping.putAll(reloads);
-                RedisHashHolder.set(RedisContextHolder.getDefaultTemplate(), key, reloads, Duration.ofDays(2));
+                groups.putAll(reloads);
+                RedisHashHolder.set(template, key, reloads, Duration.ofDays(1));
             }
         }
-        return mapping;
+        return groups;
     }
 
     @Override
     public Caps set(@NonNull String scene, @NonNull Caps group) {
         String key = this.key();
-        if (StringUtils.isEmpty(key)) {
-            return group;
-        }
-
-        // 重置场景分组并更新缓存
-        group = this.client.set(scene, group);
-        RedisHashHolder.set(RedisContextHolder.getDefaultTemplate(), key, scene, group, Duration.ofDays(2));
-        return group;
+        return StringUtils.isEmpty(key) ? group : this.setnx(key, scene, group);
     }
 
     @Override
@@ -132,11 +218,12 @@ public class RedisGroupStore implements GroupStore {
         String key = this.key();
         if (StringUtils.isEmpty(key) || ObjectUtils.isEmpty(groups)) {
             return groups;
+        } else if (groups.size() == 1) {
+            Map.Entry<String, Caps> entry = groups.entrySet().iterator().next();
+            String scene = entry.getKey();
+            Caps group = this.setnx(key, scene, entry.getValue());
+            return group == entry.getValue() ? groups : ImmutableMap.of(scene, group);
         }
-
-        // 重置场景分组并更新缓存
-        groups = this.client.set(groups);
-        RedisHashHolder.set(RedisContextHolder.getDefaultTemplate(), key, groups, Duration.ofDays(2));
-        return groups;
+        return this.setnx(key, groups);
     }
 }

+ 0 - 687
framework-redis/src/main/java/com/chelvc/framework/redis/cache/RedisZSetCaching.java

@@ -1,687 +0,0 @@
-package com.chelvc.framework.redis.cache;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.function.BiFunction;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import com.chelvc.framework.base.cache.Caching;
-import com.chelvc.framework.base.cache.Converter;
-import com.chelvc.framework.base.cache.Naming;
-import com.chelvc.framework.common.util.AssertUtils;
-import com.chelvc.framework.common.util.DateUtils;
-import com.chelvc.framework.common.util.ObjectUtils;
-import com.google.common.collect.Lists;
-import lombok.NonNull;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.tuple.Pair;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.script.DefaultRedisScript;
-import org.springframework.data.redis.core.script.RedisScript;
-
-/**
- * 基于Redis ZSet的缓存实现
- *
- * @author Woody
- * @date 2024/1/30
- */
-@Slf4j
-public class RedisZSetCaching implements Caching {
-    /**
-     * 缓存获取并延长过期时间脚本
-     */
-    private static final RedisScript<Object> GET_DEFER_SCRIPT = new DefaultRedisScript<>(
-            "local value = redis.call('GET', KEYS[1]) " +
-                    "if value ~= false then local ttl = redis.call('TTL', KEYS[1]) " +
-                    "if ttl > 0 and ttl < 60 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end end " +
-                    "return value", Object.class
-    );
-
-    /**
-     * 缓存设置脚本
-     */
-    private static final RedisScript<Boolean> SET_SCRIPT = new DefaultRedisScript<>(
-            "redis.call('SET', KEYS[1]..':'..ARGV[1], ARGV[2]) " +
-                    "return redis.call('ZADD', KEYS[2], ARGV[3], ARGV[1])", Boolean.class
-    );
-
-    /**
-     * 缓存设置并设置过期时间脚本
-     */
-    private static final RedisScript<Boolean> SET_EXPIRE_SCRIPT = new DefaultRedisScript<>(
-            "redis.call('SET', KEYS[1]..':'..ARGV[1], ARGV[2], 'EX', ARGV[4]) " +
-                    "local result = redis.call('ZADD', KEYS[2], ARGV[3], ARGV[1]) " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[4]) return result", Boolean.class
-    );
-
-    /**
-     * 缓存批量设置脚本
-     */
-    private static final RedisScript<Long> BATCH_SET_SCRIPT = new DefaultRedisScript<>(
-            "local number = 0 for i = 1, #ARGV, 3 do " +
-                    "redis.call('SET', KEYS[1]..':'..ARGV[i], ARGV[i + 1]) " +
-                    "redis.call('ZADD', KEYS[2], ARGV[i + 2], ARGV[i]) " +
-                    "number = number + 1 end return number", Long.class
-    );
-
-    /**
-     * 缓存批量设置并设置过期时间脚本
-     */
-    private static final RedisScript<Long> BATCH_SET_EXPIRE_SCRIPT = new DefaultRedisScript<>(
-            "local number = 0 for i = 2, #ARGV, 3 do " +
-                    "redis.call('SET', KEYS[1]..':'..ARGV[i], ARGV[i + 1], 'EX', ARGV[1]) " +
-                    "redis.call('ZADD', KEYS[2], ARGV[i + 2], ARGV[i]) number = number + 1 end " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[1]) return number", Long.class
-    );
-
-    /**
-     * 缓存更新脚本
-     */
-    private static final RedisScript<?> UPDATE_SCRIPT = new DefaultRedisScript<>(
-            "local function update(key) local cursor = 0 " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', key, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do redis.call('ZADD', matches[i], ARGV[3], ARGV[1]) end " +
-                    "end until (cursor <= 0) end local unique = KEYS[1]..':'..ARGV[1] " +
-                    "redis.call('SET', unique, ARGV[2]) for i = 2, #KEYS do update(KEYS[i]) end"
-    );
-
-    /**
-     * 缓存更新并设置过期时间脚本
-     */
-    private static final RedisScript<?> UPDATE_EXPIRE_SCRIPT = new DefaultRedisScript<>(
-            "local function update(key) local cursor = 0 " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', key, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do redis.call('ZADD', matches[i], ARGV[3], ARGV[1]) end " +
-                    "end until (cursor <= 0) end redis.call('SET', KEYS[1]..':'..ARGV[1], ARGV[2], 'EX', ARGV[4]) " +
-                    "for i = 2, #KEYS do update(KEYS[i]) end"
-    );
-
-    /**
-     * 缓存批量更新脚本
-     */
-    private static final RedisScript<?> BATCH_UPDATE_SCRIPT = new DefaultRedisScript<>(
-            "local function update(key, id, order) local cursor = 0 " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', key, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do redis.call('ZADD', matches[i], order, id) end " +
-                    "end until (cursor <= 0) end local n = 0 for i = 1, #ARGV, 5 do " +
-                    "for j = n + 2, n + ARGV[i + 4] do update(KEYS[j], ARGV[i], ARGV[i + 2]) end " +
-                    "local unique = KEYS[n + 1]..':'..ARGV[i] " +
-                    "if tonumber(ARGV[i + 3]) < 1 then redis.call('SET', unique, ARGV[i + 1]) else " +
-                    "redis.call('SET', unique, ARGV[i + 1], 'EX', ARGV[i + 3]) n = n + ARGV[i + 4] end end"
-    );
-
-    /**
-     * 缓存升序批量获取脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> ASC_LIST_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local ids = redis.call('ZRANGEBYSCORE', KEYS[2], '('..ARGV[1], ARGV[2], 'LIMIT', 0, ARGV[3]) " +
-                    "local values = {} for i = 1, #ids do local value = redis.call('GET', KEYS[1]..':'..ids[i]) " +
-                    "if value ~= false then table.insert(values, value) end end return values", List.class
-    );
-
-    /**
-     * 缓存升序批量获取并设置过期时间脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> ASC_LIST_DEFER_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local ids = redis.call('ZRANGEBYSCORE', KEYS[2], '('..ARGV[1], ARGV[2], 'LIMIT', 0, ARGV[3]) " +
-                    "local values = {} for i = 1, #ids do local unique = KEYS[1]..':'..ids[i] " +
-                    "local value = redis.call('GET', unique) if value ~= false then " +
-                    "local ttl = redis.call('TTL', unique) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', unique, ARGV[4]) end table.insert(values, value) end end " +
-                    "local ttl = redis.call('TTL', KEYS[2]) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[4]) end return values", List.class
-    );
-
-    /**
-     * 缓存降序批量获取脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> DESC_LIST_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local ids = redis.call('ZREVRANGEBYSCORE', KEYS[2], '('..ARGV[1], ARGV[2], 'LIMIT', 0, ARGV[3]) " +
-                    "local values = {} for i = 1, #ids do local value = redis.call('GET', KEYS[1]..':'..ids[i]) " +
-                    "if value ~= false then table.insert(values, value) end end return values", List.class
-    );
-
-    /**
-     * 缓存降序批量获取并设置过期时间脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> DESC_LIST_DEFER_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local ids = redis.call('ZREVRANGEBYSCORE', KEYS[2], '('..ARGV[1], ARGV[2], 'LIMIT', 0, ARGV[3]) " +
-                    "local values = {} for i = 1, #ids do local unique = KEYS[1]..':'..ids[i] " +
-                    "local value = redis.call('GET', unique) " +
-                    "if value ~= false then local ttl = redis.call('TTL', unique) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', unique, ARGV[4]) end table.insert(values, value) end end " +
-                    "local ttl = redis.call('TTL', KEYS[2]) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[4]) end return values", List.class
-    );
-
-    /**
-     * 缓存随机全部获取脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> RANDOM_ALL_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local randoms = {} local function random(bound) " +
-                    "local index = math.random(0, bound) " +
-                    "if randoms[index] == nil then randoms[index] = 0 return index " +
-                    "else return random(bound) end end " +
-                    "local values = {} local total = redis.call('ZCOUNT', KEYS[2], ARGV[1], ARGV[2]) " +
-                    "if total == 0 then return values end math.randomseed(ARGV[3]) " +
-                    "for i = 1, total do local index = random(total - 1) " +
-                    "local ids = redis.call('ZRANGE', KEYS[2], index, index) " +
-                    "local value = redis.call('GET', KEYS[1]..':'..ids[1]) " +
-                    "if value ~= false then table.insert(values, value) end end return values", List.class
-    );
-
-    /**
-     * 缓存随机批量获取脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> RANDOM_LIST_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local randoms = {} local function random(bound) " +
-                    "local index = math.random(0, bound) " +
-                    "if randoms[index] == nil then randoms[index] = 0 return index " +
-                    "else return random(bound) end end " +
-                    "local values = {} local total = redis.call('ZCOUNT', KEYS[2], ARGV[1], ARGV[2]) " +
-                    "if total == 0 then return values end " +
-                    "local offset = redis.call('ZCOUNT', KEYS[2], '-INF', '('..ARGV[1]) " +
-                    "local size = tonumber(ARGV[4]) " +
-                    "if size < 0 then size = total elseif size > total then size = total end " +
-                    "math.randomseed(ARGV[3]) " +
-                    "for i = 1, size do local index = random(total - 1) + offset " +
-                    "local ids = redis.call('ZRANGE', KEYS[2], index, index) " +
-                    "local value = redis.call('GET', KEYS[1]..':'..ids[1]) " +
-                    "if value ~= false then table.insert(values, value) end end return values", List.class
-    );
-
-    /**
-     * 缓存随机全部获取并设置过期时间脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> RANDOM_ALL_DEFER_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local randoms = {} local function random(bound) " +
-                    "local index = math.random(0, bound) " +
-                    "if randoms[index] == nil then randoms[index] = 0 return index " +
-                    "else return random(bound) end end " +
-                    "local values = {} local total = redis.call('ZCOUNT', KEYS[2], ARGV[1], ARGV[2]) " +
-                    "if total == 0 then return values end math.randomseed(ARGV[3]) " +
-                    "for i = 1, total do local index = random(total - 1) " +
-                    "local ids = redis.call('ZRANGE', KEYS[2], index, index) " +
-                    "local unique = KEYS[1]..':'..ids[1] local value = redis.call('GET', unique) " +
-                    "if value ~= false then local ttl = redis.call('TTL', unique) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', unique, ARGV[4]) end table.insert(values, value) end " +
-                    "end local ttl = redis.call('TTL', KEYS[2]) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[4]) end return values", List.class
-    );
-
-    /**
-     * 缓存随机批量获取并设置过期时间脚本
-     */
-    @SuppressWarnings("rawtypes")
-    private static final RedisScript<List> RANDOM_LIST_DEFER_SCRIPT = new DefaultRedisScript<>(
-            "if redis.call('EXISTS', KEYS[2]) == 0 then return nil end " +
-                    "local randoms = {} local function random(bound) " +
-                    "local index = math.random(0, bound) " +
-                    "if randoms[index] == nil then randoms[index] = 0 return index " +
-                    "else return random(bound) end end " +
-                    "local values = {} local total = redis.call('ZCOUNT', KEYS[2], ARGV[1], ARGV[2]) " +
-                    "if total == 0 then return values end " +
-                    "local offset = redis.call('ZCOUNT', KEYS[2], '-INF', '('..ARGV[1]) " +
-                    "local size = tonumber(ARGV[4]) " +
-                    "if size < 0 then size = total elseif size > total then size = total end " +
-                    "math.randomseed(ARGV[3]) " +
-                    "for i = 1, size do local index = random(total - 1) + offset " +
-                    "local ids = redis.call('ZRANGE', KEYS[2], index, index) " +
-                    "local unique = KEYS[1]..':'..ids[1] local value = redis.call('GET', unique) " +
-                    "if value ~= false then local ttl = redis.call('TTL', unique) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', unique, ARGV[5]) end table.insert(values, value) end " +
-                    "end local ttl = redis.call('TTL', KEYS[2]) if ttl > 0 and ttl < 60 then " +
-                    "redis.call('EXPIRE', KEYS[2], ARGV[5]) end return values", List.class
-    );
-
-    /**
-     * 缓存清理脚本
-     */
-    private static final RedisScript<Boolean> CLEAR_SCRIPT = new DefaultRedisScript<>(
-            "local count = 0 local function clear(key) local cursor = 0 " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', key, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then " +
-                    "cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do count = count + redis.call('ZREM', matches[i], ARGV[1]) end " +
-                    "end until (cursor <= 0) end for i = 2, #KEYS do clear(KEYS[i]) end " +
-                    "count = count + redis.call('DEL', KEYS[1]..':'..ARGV[1]) " +
-                    "if count > 0 then return 1 else return 0 end", Boolean.class
-    );
-
-    /**
-     * 缓存批量清理脚本
-     */
-    private static final RedisScript<Boolean> BATCH_CLEAR_SCRIPT = new DefaultRedisScript<>(
-            "local count = 0 local function clear(key, value) local cursor = 0 " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', key, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then " +
-                    "cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do count = count + redis.call('ZREM', matches[i], value) end " +
-                    "end until (cursor <= 0) end local n = 0 for i = 1, #ARGV, 2 do " +
-                    "for j = n + 2, n + ARGV[i + 1] do clear(KEYS[j], ARGV[i]) end " +
-                    "count = count + redis.call('DEL', KEYS[n + 1]..':'..ARGV[i]) n = n + ARGV[i + 1] end " +
-                    "if count > 0 then return 1 else return 0 end", Boolean.class
-    );
-
-    /**
-     * 缓存移除脚本
-     */
-    private static final RedisScript<Boolean> REMOVE_SCRIPT = new DefaultRedisScript<>(
-            "local count = redis.call('ZREM', KEYS[2], ARGV[1]) + redis.call('DEL', KEYS[1]..':'..ARGV[1]) " +
-                    "if count > 0 then return 1 else return 0 end", Boolean.class
-    );
-
-    /**
-     * 缓存移批量除脚本
-     */
-    private static final RedisScript<Boolean> BATCH_REMOVE_SCRIPT = new DefaultRedisScript<>(
-            "local count = 0 for i = 1, #ARGV do count = count + redis.call('ZREM', KEYS[i * 2], ARGV[i]) " +
-                    "count = count + redis.call('DEL', KEYS[i * 2 - 1]..':'..ARGV[i]) end " +
-                    "if count > 0 then return 1 else return 0 end", Boolean.class
-    );
-
-    /**
-     * 缓存全部移除脚本
-     */
-    private static final RedisScript<Boolean> REMOVE_ALL_SCRIPT = new DefaultRedisScript<>(
-            "local count = 0 for i = 1, #KEYS do local cursor = 0 local pattern = KEYS[i]..':'..'*' " +
-                    "repeat local result = redis.call('SCAN', cursor, 'MATCH', pattern, 'COUNT', 1000) " +
-                    "if (result ~= nil and #result > 0) then cursor = tonumber(result[1]) local matches = result[2] " +
-                    "for i = 1, #matches do count = count + redis.call('DEL', matches[i]) end end " +
-                    "until (cursor <= 0) end if count > 0 then return 1 else return 0 end", Boolean.class
-    );
-
-    private final RedisTemplate<String, Object> template;
-
-    public RedisZSetCaching(@NonNull RedisTemplate<String, Object> template) {
-        this.template = template;
-    }
-
-    /**
-     * 批量获取缓存内容,如果对应ZSet Key不存在则返回null
-     *
-     * @param naming 缓存命名
-     * @param min    最小排序数字
-     * @param max    最大排序数字
-     * @param size   获取数量
-     * @param <V>    缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    @SuppressWarnings("unchecked")
-    private <V> List<V> listing(@NonNull Naming naming, long min, long max, int size) {
-        AssertUtils.check(max >= min, () -> "max must not be less than min");
-        AssertUtils.check(size > 0, () -> "size must be greater than 0");
-        List<String> keys = naming.getKeys();
-        List<V> values = null;
-        try {
-            if (naming.isReversed()) {
-                if (naming.getDuration() > 0) {
-                    values = this.template.execute(DESC_LIST_DEFER_SCRIPT, keys, max, min, size, naming.getDuration());
-                } else {
-                    values = this.template.execute(DESC_LIST_SCRIPT, keys, max, min, size);
-                }
-            } else {
-                if (naming.getDuration() > 0) {
-                    values = this.template.execute(ASC_LIST_DEFER_SCRIPT, keys, min, max, size, naming.getDuration());
-                } else {
-                    values = this.template.execute(ASC_LIST_SCRIPT, keys, min, max, size);
-                }
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache list failed: {}, {}", naming, t.getMessage());
-        }
-        return values != null && values.size() == 1 && values.get(0) == null ? null : values;
-    }
-
-    /**
-     * 批量随机获取缓存内容,如果对应ZSet Key不存在则返回null
-     *
-     * @param naming 缓存命名
-     * @param min    最小排序数字
-     * @param max    最大排序数字
-     * @param size   获取数量(当size < 0 时获取全部内容)
-     * @param <V>    缓存内容类型
-     * @return 缓存对象实例列表
-     */
-    @SuppressWarnings("unchecked")
-    private <V> List<V> randomizing(@NonNull Naming naming, long min, long max, int size) {
-        AssertUtils.check(max >= min, () -> "max must not be less than min");
-        AssertUtils.check(size != 0, () -> "size must be less than or greater than 0");
-        List<String> keys = naming.getKeys();
-        long seed = Long.parseLong(new StringBuilder(String.valueOf(DateUtils.seconds())).reverse().substring(0, 7));
-        List<V> values = null;
-        try {
-            if (size < 0) {
-                if (naming.getDuration() > 0) {
-                    values = this.template.execute(RANDOM_ALL_DEFER_SCRIPT, keys, min, max, seed, naming.getDuration());
-                } else {
-                    values = this.template.execute(RANDOM_ALL_SCRIPT, keys, min, max, seed);
-                }
-            } else {
-                if (naming.getDuration() > 0) {
-                    values = this.template.execute(RANDOM_LIST_DEFER_SCRIPT, keys, min, max, seed, size,
-                            naming.getDuration());
-                } else {
-                    values = this.template.execute(RANDOM_LIST_SCRIPT, keys, min, max, seed, size);
-                }
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache random list failed: {}, {}", naming, t.getMessage());
-        }
-        return values != null && values.size() == 1 && values.get(0) == null ? null : values;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <K, V> V get(@NonNull Naming naming, @NonNull K id) {
-        String key = naming.getPrimary() + ":" + id;
-        V value = null;
-        try {
-            if (naming.getDuration() > 0) {
-                List<String> keys = Collections.singletonList(key);
-                value = (V) this.template.execute(GET_DEFER_SCRIPT, keys, naming.getDuration());
-            } else {
-                value = (V) this.template.opsForValue().get(key);
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache get failed: {}, {}", key, t.getMessage());
-        }
-        return value;
-    }
-
-    @Override
-    public <K, V> V get(@NonNull Naming naming, @NonNull K id, @NonNull Supplier<V> supplier) {
-        V value = this.get(naming, id);
-        if (value == null && (value = supplier.get()) != null) {
-            this.set(naming, id, value);
-        }
-        return value;
-    }
-
-    @Override
-    public <V> List<V> list(@NonNull Naming naming, long min, long max, int size) {
-        List<V> values = this.listing(naming, min, max, size);
-        return ObjectUtils.ifEmpty(values, Collections::emptyList);
-    }
-
-    @Override
-    public <K, V> List<V> list(@NonNull Naming naming, long min, long max, int size,
-                               @NonNull BiFunction<Naming, Boolean, List<V>> supplier,
-                               @NonNull Converter<K, V> converter) {
-        // 从缓存加载数据
-        List<V> values = this.listing(naming, min, max, size);
-        boolean initial = Objects.isNull(values);
-        if (!initial && values.size() >= size) {
-            return values;
-        }
-
-        // 重新加载并更新缓存数据
-        List<V> suppliers = supplier.apply(naming, initial);
-        if (ObjectUtils.isEmpty(suppliers)) {
-            return ObjectUtils.ifEmpty(values, Collections::emptyList);
-        } else if (ObjectUtils.isEmpty(values)) {
-            this.set(naming, suppliers, converter);
-        } else {
-            Set<K> exists = values.stream().map(converter::id).collect(Collectors.toSet());
-            List<V> news = suppliers.stream().filter(value -> !exists.contains(converter.id(value)))
-                    .collect(Collectors.toList());
-            if (ObjectUtils.notEmpty(news)) {
-                this.set(naming, news, converter);
-            }
-        }
-
-        // 返回最多 size 个数据
-        return suppliers.size() <= size ? suppliers : suppliers.subList(0, size);
-    }
-
-    @Override
-    public <V> List<V> random(@NonNull Naming naming, long min, long max, int size) {
-        List<V> values = this.randomizing(naming, min, max, size);
-        return ObjectUtils.ifEmpty(values, Collections::emptyList);
-    }
-
-    @Override
-    public <K, V> List<V> random(@NonNull Naming naming, long min, long max, int size,
-                                 @NonNull BiFunction<Naming, Boolean, List<V>> supplier,
-                                 @NonNull Converter<K, V> converter) {
-        // 从缓存加载数据
-        List<V> values = this.randomizing(naming, min, max, size);
-        boolean initial = Objects.isNull(values);
-        if (!initial && values.size() >= size) {
-            return values;
-        }
-
-        // 重新加载并更新缓存数据
-        List<V> suppliers = supplier.apply(naming, initial);
-        if (ObjectUtils.isEmpty(suppliers)) {
-            return ObjectUtils.ifEmpty(values, Collections::emptyList);
-        } else if (ObjectUtils.isEmpty(values)) {
-            this.set(naming, suppliers, converter);
-        } else {
-            Set<K> exists = values.stream().map(converter::id).collect(Collectors.toSet());
-            List<V> news = suppliers.stream().filter(value -> !exists.contains(converter.id(value)))
-                    .collect(Collectors.toList());
-            if (ObjectUtils.notEmpty(news)) {
-                this.set(naming, news, converter);
-            }
-        }
-
-        // 如果size < 0 则返回所有数据,否则返回最多 size 个数据
-        return size < 0 ? suppliers : suppliers.size() <= size ? suppliers : suppliers.subList(0, size);
-    }
-
-
-    @Override
-    public <K, V> boolean set(@NonNull Naming naming, @NonNull K id, @NonNull V value) {
-        String key = naming.getPrimary() + ":" + id;
-        try {
-            if (naming.getDuration() > 0) {
-                this.template.opsForValue().set(key, value, naming.getDuration(), TimeUnit.SECONDS);
-            } else {
-                this.template.opsForValue().set(key, value);
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache set failed: {}, {}", key, t.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public <K, V> boolean set(@NonNull Naming naming, @NonNull K id, @NonNull V value, long order) {
-        List<String> keys = naming.getKeys();
-        Boolean success = null;
-        try {
-            if (naming.getDuration() > 0) {
-                success = this.template.execute(SET_EXPIRE_SCRIPT, keys, id, value, order, naming.getDuration());
-            } else {
-                success = this.template.execute(SET_SCRIPT, keys, id, value, order);
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache set failed: {}, {}, {}", naming, id, t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-
-    @Override
-    public <K, V> boolean set(@NonNull Naming naming, @NonNull Collection<V> values,
-                              @NonNull Converter<K, V> converter) {
-        if (ObjectUtils.isEmpty(values)) {
-            return false;
-        }
-
-        int i = 0;
-        Object[] args;
-        if (naming.getDuration() > 0) {
-            args = new Object[values.size() * 3 + 1];
-            args[i++] = naming.getDuration();
-        } else {
-            args = new Object[values.size() * 3];
-        }
-        for (V value : values) {
-            args[i++] = converter.id(value);
-            args[i++] = value;
-            args[i++] = converter.order(value);
-        }
-        List<String> keys = naming.getKeys();
-        Long number = null;
-        try {
-            if (naming.getDuration() > 0) {
-                number = this.template.execute(BATCH_SET_EXPIRE_SCRIPT, keys, args);
-            } else {
-                number = this.template.execute(BATCH_SET_SCRIPT, keys, args);
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache batch set failed: {}, {}", naming, t.getMessage());
-        }
-        return number != null && number == values.size();
-    }
-
-    @Override
-    public <K, V> boolean update(@NonNull Naming naming, @NonNull K id, @NonNull V value, long order) {
-        List<String> keys = naming.getKeys();
-        try {
-            if (naming.getDuration() > 0) {
-                this.template.execute(UPDATE_EXPIRE_SCRIPT, keys, id, value, order, naming.getDuration());
-            } else {
-                this.template.execute(UPDATE_SCRIPT, keys, id, value, order);
-            }
-        } catch (Throwable t) {
-            log.warn("Redis cache update failed: {}, {}, {}", naming, id, t.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public <K, V> boolean update(@NonNull Naming naming, @NonNull V value, @NonNull Converter<K, V> converter) {
-        return this.update(naming, converter.id(value), value, converter.order(value));
-    }
-
-    @Override
-    public <K, V> boolean update(@NonNull Collection<Pair<Naming, V>> pairs, @NonNull Converter<K, V> converter) {
-        if (ObjectUtils.isEmpty(pairs)) {
-            return false;
-        }
-        List<String> keys = Lists.newLinkedList();
-        Object[] args = new Object[pairs.size() * 5];
-        int i = 0;
-        for (Pair<Naming, V> pair : pairs) {
-            keys.addAll(pair.getKey().getKeys());
-            args[i++] = converter.id(pair.getValue());
-            args[i++] = pair.getValue();
-            args[i++] = converter.order(pair.getValue());
-            args[i++] = pair.getKey().getDuration();
-            args[i++] = pair.getKey().getKeys().size();
-        }
-        try {
-            this.template.execute(BATCH_UPDATE_SCRIPT, keys, args);
-        } catch (Throwable t) {
-            log.warn("Redis cache batch update failed: {}", t.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public boolean remove(@NonNull Naming naming) {
-        List<String> keys = naming.getKeys().stream().distinct().collect(Collectors.toList());
-        Boolean success = null;
-        try {
-            success = this.template.execute(REMOVE_ALL_SCRIPT, keys);
-        } catch (Throwable t) {
-            log.warn("Redis cache remove failed: {}, {}", naming, t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-
-    @Override
-    public <K> boolean remove(@NonNull Naming naming, @NonNull K id) {
-        List<String> keys = naming.getKeys();
-        Boolean success = null;
-        try {
-            success = this.template.execute(REMOVE_SCRIPT, keys, id);
-        } catch (Throwable t) {
-            log.warn("Redis cache remove failed: {}, {}, {}", naming, id, t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-
-    @Override
-    public <K> boolean remove(@NonNull Collection<Pair<Naming, K>> pairs) {
-        if (ObjectUtils.isEmpty(pairs)) {
-            return false;
-        }
-        List<String> keys = Lists.newArrayListWithCapacity(pairs.size() * 2);
-        Object[] args = new Object[pairs.size()];
-        int i = 0;
-        for (Pair<Naming, K> pair : pairs) {
-            keys.add(pair.getKey().getPrimary());
-            keys.add(pair.getKey().getIndexes().get(0));
-            args[i++] = pair.getValue();
-        }
-        Boolean success = null;
-        try {
-            success = this.template.execute(BATCH_REMOVE_SCRIPT, keys, args);
-        } catch (Throwable t) {
-            log.warn("Redis cache batch remove failed: {}, ", t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-
-    @Override
-    public <K> boolean clear(@NonNull Naming naming, @NonNull K id) {
-        List<String> keys = naming.getKeys();
-        Boolean success = null;
-        try {
-            success = this.template.execute(CLEAR_SCRIPT, keys, id);
-        } catch (Throwable t) {
-            log.warn("Redis cache clear failed: {}, {}, {}", naming, id, t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-
-    @Override
-    public <K> boolean clear(@NonNull Collection<Pair<Naming, K>> pairs) {
-        if (ObjectUtils.isEmpty(pairs)) {
-            return false;
-        }
-        List<String> keys = Lists.newLinkedList();
-        Object[] args = new Object[pairs.size() * 2];
-        int i = 0;
-        for (Pair<Naming, K> pair : pairs) {
-            keys.addAll(pair.getKey().getKeys());
-            args[i++] = pair.getValue();
-            args[i++] = pair.getKey().getKeys().size();
-        }
-        Boolean success = null;
-        try {
-            success = this.template.execute(BATCH_CLEAR_SCRIPT, keys, args);
-        } catch (Throwable t) {
-            log.warn("Redis cache batch clear failed: {}", t.getMessage());
-        }
-        return Boolean.TRUE.equals(success);
-    }
-}

+ 4 - 5
framework-redis/src/main/java/com/chelvc/framework/redis/context/RedisHashHolder.java

@@ -27,17 +27,16 @@ public final class RedisHashHolder {
     /**
      * Redis带过期时间HMSET脚本
      */
-    private static final String SET_DURATION_SCRIPT = "if redis.call('HMSET', KEYS[1], unpack(ARGV, 2)) then " +
-            "if redis.call('TTL', KEYS[1]) < tonumber(ARGV[1]) then redis.call('EXPIRE', KEYS[1], ARGV[1]) end " +
-            "return 1 end return 0";
+    private static final String SET_DURATION_SCRIPT =
+            "if redis.call('HMSET', KEYS[1], unpack(ARGV, 2)) then " +
+                    "redis.call('EXPIRE', KEYS[1], ARGV[1]) return 1 end return 0";
 
     /**
      * Redis带过期时间HINCRBY脚本
      */
     private static final String HINCRBY_DURATION_SCRIPT =
             "local value = redis.call('HINCRBY', KEYS[1], ARGV[1], ARGV[2]) " +
-                    "if redis.call('TTL', KEYS[1]) < tonumber(ARGV[3]) then " +
-                    "redis.call('EXPIRE', KEYS[1], ARGV[3]) end return value";
+                    "redis.call('EXPIRE', KEYS[1], ARGV[3]) return value";
 
     /**
      * Redis带过期时间HMSET脚本SHA

+ 2 - 4
framework-redis/src/main/java/com/chelvc/framework/redis/context/RedisUserDailyHashHolder.java

@@ -27,10 +27,8 @@ public final class RedisUserDailyHashHolder {
      * Redis用户每天系统使用时间戳刷新脚本
      */
     private static final RedisScript<Object> USING_REFRESH_SCRIPT = new DefaultRedisScript<>(
-            "local value = redis.call('HGET', KEYS[1], 'using') " +
-                    "redis.call('HSET', KEYS[1], 'using', ARGV[1]) " +
-                    "if redis.call('TTL', KEYS[1]) < 1 then redis.call('EXPIRE', KEYS[1], ARGV[2]) end " +
-                    "return value", Object.class
+            "local value = redis.call('HGET', KEYS[1], 'using') redis.call('HSET', KEYS[1], 'using', ARGV[1]) " +
+                    "redis.call('EXPIRE', KEYS[1], ARGV[2]) return value", Object.class
     );
 
     private RedisUserDailyHashHolder() {

+ 1 - 1
framework-security/src/main/java/com/chelvc/framework/security/interceptor/SecurityValidateInterceptor.java

@@ -197,7 +197,7 @@ public class SecurityValidateInterceptor implements HandlerInterceptor, WebMvcCo
             String payload = HttpUtils.serialize(request, true);
             String signature = request.getHeader(SecurityContextHolder.SIGNATURE);
             String ciphertext = SecurityContextHolder.getSecurityCipherHandler().sign(session, payload);
-            LoggingContextHolder.debug(log, signature, ciphertext, payload);
+            LoggingContextHolder.debug(log, request, signature, ciphertext, payload);
             if (!Objects.equals(ciphertext, signature)) {
                 throw new FrameworkException(HttpStatus.BAD_REQUEST.name(), null,
                         ApplicationContextHolder.getMessage("Signature.Invalid"));