dangsn
2024-06-07 7664ba49025a6c549885fc6019e4d3c1886f45a6
Source/plt-web/plt-web-parent/plt-web/src/main/java/com/vci/web/redis/RedisService.java
@@ -1,25 +1,28 @@
package com.vci.web.redis;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * spring redis 工具类
 *
 * @author wang1
 * @author dangsn
 **/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
@Slf4j
public class RedisService
{
    @Autowired(required = false)
@@ -31,8 +34,7 @@
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value)
    {
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }
@@ -44,8 +46,7 @@
     * @param timeout 时间
     * @param timeUnit 时间颗粒度
     */
    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
    {
    public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }
@@ -69,8 +70,7 @@
     * @param unit 时间单位
     * @return true=设置成功;false=设置失败
     */
    public boolean expire(final String key, final long timeout, final TimeUnit unit)
    {
    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }
@@ -91,8 +91,7 @@
     * @param key 键
     * @return true 存在 false不存在
     */
    public Boolean hasKey(String key)
    {
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }
@@ -102,8 +101,7 @@
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(final String key)
    {
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
@@ -111,7 +109,8 @@
    /**
     * 删除单个对象
     *
     * @param key
     * @param key 可以
     * @return  删除是否成功
     */
    public boolean deleteObject(final String key)
    {
@@ -122,7 +121,7 @@
     * 删除集合对象
     *
     * @param collection 多个对象
     * @return
     * @return 删除的个数
     */
    public long deleteObject(final Collection collection)
    {
@@ -130,50 +129,14 @@
    }
    /**
     * list的长度
     *
     * @param key 缓存的键值
     * @return 缓存的对象
     */
    public <T> Long listSize(final String key)
    {
        return redisTemplate.opsForList().size(key);
    }
    /**
     * 从左边取出一个list元素
     *
     * @param key 缓存的键值
     * @return 缓存的对象
     */
    public <T> Object leftPop(final String key)
    {
        return redisTemplate.opsForList().leftPop(key);
    }
    /**
     * 从右边缓存List数据
     * 缓存List数据
     *
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> long setCacheList(final String key, final List<T> dataList)
    {
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }
    /**
     * 删除list中元素value
     * @param key
     * @param value
     * @param <T>
     * @return
     */
    public <T> long deleteCacheListByKeyAndValue(final String key, final T value)
    {
        Long count = redisTemplate.opsForList().remove(key,0,value);
        return count == null ? 0 : count;
    }
@@ -188,8 +151,6 @@
        return redisTemplate.opsForList().range(key, 0, -1);
    }
    /**
     * 缓存Set
     *
@@ -197,36 +158,21 @@
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
    {
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext())
        {
            setOperation.add(it.next());
        }
        String i = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<Datas>\n" +
                "\t<Data code=\"A1100012\" deptLevel=\"开发部门#测试部门\">\n" +
                "\t\t<prop sName=\"供应商名称\" tName =\"供应商名称1\" >\n" +
                "\t\t\t北京宏博远达科技有限公司2\n" +
                "\t\t</prop>\n" +
                "\t\t<prop sName=\"户头\" tName =\"户头1\">\n" +
                "\t\t\t1111100012\n" +
                "\t\t</prop>\n" +
                "\t\t<prop sName=\"联系人\" tName=\"联系人1\">\n" +
                "\t\t\t谢军2\n" +
                "\t\t</prop>\n" +
                "\t</Data>\n" +
                "</Datas>";
        return setOperation;
    }
    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     * @param key key
     * @return 集合的内容
     */
    public <T> Set<T> getCacheSet(final String key)
    {
@@ -236,11 +182,10 @@
    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     * @param key key
     * @param dataMap 数据映射
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
    {
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
@@ -249,8 +194,8 @@
    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     * @param key key
     * @return 映射
     */
    public <T> Map<String, T> getCacheMap(final String key)
    {
@@ -264,8 +209,7 @@
     * @param hKey Hash键
     * @param value 值
     */
    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
    {
    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        redisTemplate.opsForHash().put(key, hKey, value);
    }
@@ -276,8 +220,7 @@
     * @param hKey Hash键
     * @return Hash中的对象
     */
    public <T> T getCacheMapValue(final String key, final String hKey)
    {
    public <T> T getCacheMapValue(final String key, final String hKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hKey);
    }
@@ -289,19 +232,243 @@
     * @param hKeys Hash键集合
     * @return Hash对象集合
     */
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
    {
    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
        return redisTemplate.opsForHash().multiGet(key, hKeys);
    }
    /**
     * 获得缓存的基本对象列表
     *
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(final String pattern)
    {
    public Collection<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }
    /**
     * 设置分布式锁
     * @param key 锁的key
     * @param value 值
     * @return true表示存在,false表示不存在
     */
    public synchronized Boolean setNX(final String key, final String value) throws Exception{
        Object obj = null;
        try {
            obj = redisTemplate.execute((RedisCallback<Object>) connection -> {
                StringRedisSerializer serializer = new StringRedisSerializer();
                Boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value));
                connection.close();
                return success;
            });
        } catch (Exception e) {
            log.error("setNX redis error, key : {} - {}", key,e);
            throw e;
        }
        return obj != null ? (Boolean) obj : false;
    }
    /**
     * 设置分布式锁,超时间单位秒
     * @param key 锁的key
     * @param value 值
     * @param timeOut 超时时间
     * @return true表示存在,false表示不存在
     */
    public synchronized Boolean setNX(final String key, final String value,long timeOut) throws Exception {
        boolean b = this.setNX(key,value);
        redisTemplate.expire(key,timeOut,TimeUnit.SECONDS);
        return b;
    }
    /**
     * 删除锁
     * @param key 锁的key
     */
    public void unlock(final String key) {
        redisTemplate.delete(key);
    }
    /**
     * 自减 大于等于0
     * @param key 锁的key
     * @return Boolean
     */
    public Boolean decrement(final String key) {
        return redisTemplate.opsForValue().decrement(key) >= 0;
    }
    public Boolean decrement(final String key, long count) {
        return redisTemplate.opsForValue().decrement(key,count) >= 0;
    }
    /**
     * 自减
     * @param key 锁的key
     * @return Boolean
     */
    public Long decrementLong(final String key) {
        return redisTemplate.opsForValue().decrement(key);
    }
    /**
     * 自增
     * @param key 锁的key
     * @return Boolean
     */
    public Long increment(final String key) {
        return redisTemplate.opsForValue().increment(key);
    }
    public Long increment(final String key, long count) {
        return redisTemplate.opsForValue().increment(key,count);
    }
    /**
     * 前缀匹配删除
     * @param keyPrefix key前缀
     */
    public Boolean deleteByPrefix(final String keyPrefix) {
        List<String> list = new LinkedList<>();
        ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build();
        RedisSerializer<String> redisSerializer = redisTemplate.getKeySerializer();
        Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redis -> new ConvertingCursor<>(redis.scan(build), redisSerializer::deserialize));
        if (cursor != null){
            try {
                while ( cursor.hasNext()) {
                    list.add(cursor.next().toString());
                }
                try {
                    cursor.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error("redis中的Cursor关闭失败!");
                }
            } finally {
                try {
                    cursor.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            Long delete = redisTemplate.delete(list);
            log.info("删除菜单key: "+delete+"个。\n 详情:"+list.toString());
            return delete > 0L;
        }
        return false;
    }
    /**
     * 前缀匹配
     * @param keyPrefix key前缀
     *
     */
    public <T> List<T> findKeysByPrefix(final String keyPrefix) {
        List<T> list = new ArrayList<>();
        ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build();
        RedisSerializer<String> redisSerializer = redisTemplate.getKeySerializer();
        Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redis -> new ConvertingCursor<>(redis.scan(build), redisSerializer::deserialize));
        if (cursor != null){
            try {
                while (cursor.hasNext()) {
                    list.add(getCacheObject(cursor.next().toString()));
                }
                try {
                    cursor.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } finally {
                try {
                    cursor.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return list;
        }
        return new ArrayList<>();
    }
    /**
     * 基于Lua脚本实现原子查询并删除
     * @param key
     * @return
     */
    public Boolean deleteLuaByKey(String key) {
        String str2 = "if redis.call('EXISTS', KEYS[1]) == 1 then redis.call('DEL', KEYS[1]) return 1 else return 0 end";
        RedisScript<Boolean> redisScript = new DefaultRedisScript<>(str2,Boolean.class);
        Boolean execute = (Boolean) redisTemplate.execute(redisScript, Collections.singletonList(key));
        return execute;
    }
    /**
     * GEO 添加数据(经纬度)
     * @param key
     * @return
     */
    public <T extends Point> void addGEO(String key, Map<String,T> map) {
        redisTemplate.opsForGeo().add(key,map);
    }
    /**
     * GEO 添加数据(经纬度)
     * @param key
     * @return
     */
    public <T extends Point> void addGEO(String key, Point point, String member) {
        redisTemplate.opsForGeo().add(key,point,member);
    }
    public <T extends Point> void removeGEO(String key,String... member) {
        redisTemplate.opsForGeo().remove(key,member);
    }
    /**
     * GEO 查询距离
     * @param point 需要查询的地址
     * @param key 城市
     * @param members 节点
     * @return map(商铺,距离)
     */
    public  Map<String,String> distanceGEO(Point point,String key, List<String> members) {
        GeoOperations geo = redisTemplate.opsForGeo();
        long l = System.currentTimeMillis();
        String member = "geo"+l;
        addGEO(key,point,member);
        Map<String,String> map = new HashMap<>();
        members.forEach(e->{
            Distance distance = geo.distance(key, member, e, Metrics.KILOMETERS);
            map.put(e,String.valueOf(distance.getValue()));
        });
        removeGEO(key,key,member);
        return map;
    }
    /**
     * 获取List集合操作
     * @return 操作
     */
    public ListOperations opsForList(){
        return this.redisTemplate.opsForList();
    }
    /**
     * 获取Set集合操作
     * @return 操作
     */
    public SetOperations opsForSet(){
        return this.redisTemplate.opsForSet();
    }
    /**
     * 获取hash操作
     * @return 操作
     */
    public HashOperations opsForHash(){
        return this.redisTemplate.opsForHash();
    }
}