content: package top.panll.assist.utils;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.data.redis.core.*;
  import org.springframework.stereotype.Component;
  import org.springframework.util.CollectionUtils;
  
  import java.util.*;
  import java.util.concurrent.TimeUnit;
  
  /**    
   * @Description:Redis工具类
   * @author: swwheihei
   * @date:   2020年5月6日 下午8:27:29     
   */
  @Component
  @SuppressWarnings(value = {"rawtypes", "unchecked"})
  public class RedisUtil {
  
  	@Autowired
      private RedisTemplate<Object, Object> redisTemplate;
  	
  	/**
       * 指定缓存失效时间
       * @param key 键
       * @param time 时间（秒）
       * @return true / false
       */
      public boolean expire(String key, long time) {
          try {
              if (time > 0) {
                  redisTemplate.expire(key, time, TimeUnit.SECONDS);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
  
      }
  
      /**
       * 根据 key 获取过期时间
       * @param key 键
       * @return
       */
      public long getExpire(String key) {
          return redisTemplate.getExpire(key, TimeUnit.SECONDS);
      }
  
      /**
       * 判断 key 是否存在
       * @param key 键
       * @return true / false
       */
      public boolean hasKey(String key) {
          try {
              return redisTemplate.hasKey(key);
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 删除缓存
       * @SuppressWarnings("unchecked") 忽略类型转换警告
       * @param key 键（一个或者多个）
       */
      public boolean del(String... key) {
      	try {
      		if (key != null && key.length > 0) {
                  if (key.length == 1) {
                      redisTemplate.delete(key[0]);
                  } else {
  //                    传入一个 Collection<String> 集合
                      redisTemplate.delete(CollectionUtils.arrayToList(key));
                  }
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
  //    ============================== String ==============================
  
      /**
       * 普通缓存获取
       * @param key 键
       * @return 值
       */
      public Object get(String key) {
          return key == null ? null : redisTemplate.opsForValue().get(key);
      }
  
      /**
       * 普通缓存放入
       * @param key 键
       * @param value 值
       * @return true / false
       */
      public boolean set(String key, Object value) {
          try {
              redisTemplate.opsForValue().set(key, value);
              return true;
          } catch (Exception e) {
  //            e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 普通缓存放入并设置时间
       * @param key 键
       * @param value 值
       * @param time 时间（秒），如果 time < 0 则设置无限时间
       * @return true / false
       */
      public boolean set(String key, Object value, long time) {
          try {
              if (time > 0) {
                  redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
              } else {
                  set(key, value);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 递增
       * @param key 键
       * @param delta 递增大小
       * @return
       */
      public long incr(String key, long delta) {
          if (delta < 0) {
              throw new RuntimeException("递增因子必须大于 0");
          }
          return redisTemplate.opsForValue().increment(key, delta);
      }
  
      /**
       * 递减
       * @param key 键
       * @param delta 递减大小
       * @return
       */
      public long decr(String key, long delta) {
          if (delta < 0) {
              throw new RuntimeException("递减因子必须大于 0");
          }
          return redisTemplate.opsForValue().increment(key, delta);
      }
  
  //    ============================== Map ==============================
  
      /**
       * HashGet
       * @param key 键（no null）
       * @param item 项（no null）
       * @return 值
       */
      public Object hget(String key, String item) {
          return redisTemplate.opsForHash().get(key, item);
      }
  
      /**
       * 获取 key 对应的 map
       * @param key 键（no null）
       * @return 对应的多个键值
       */
      public Map<Object, Object> hmget(String key) {
          return redisTemplate.opsForHash().entries(key);
      }
  
      /**
       * HashSet
       * @param key 键
       * @param map 值
       * @return true / false
       */
      public boolean hmset(String key, Map<Object, Object> map) {
          try {
              redisTemplate.opsForHash().putAll(key, map);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * HashSet 并设置时间
       * @param key 键
       * @param map 值
       * @param time 时间
       * @return true / false
       */
      public boolean hmset(String key, Map<Object, Object> map, long time) {
          try {
              redisTemplate.opsForHash().putAll(key, map);
              if (time > 0) {
                  expire(key, time);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 向一张 Hash表 中放入数据，如不存在则创建
       * @param key 键
       * @param item 项
       * @param value 值
       * @return true / false
       */
      public boolean hset(String key, String item, Object value) {
          try {
              redisTemplate.opsForHash().put(key, item, value);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 向一张 Hash表 中放入数据，并设置时间，如不存在则创建
       * @param key 键
       * @param item 项
       * @param value 值
       * @param time 时间（如果原来的 Hash表 设置了时间，这里会覆盖）
       * @return true / false
       */
      public boolean hset(String key, String item, Object value, long time) {
          try {
              redisTemplate.opsForHash().put(key, item, value);
              if (time > 0) {
                  expire(key, time);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 删除 Hash表 中的值
       * @param key 键
       * @param item 项（可以多个，no null）
       */
      public void hdel(String key, Object... item) {
          redisTemplate.opsForHash().delete(key, item);
      }
  
      /**
       * 判断 Hash表 中是否有该键的值
       * @param key 键（no null）
       * @param item 值（no null）
       * @return true / false
       */
      public boolean hHasKey(String key, String item) {
          return redisTemplate.opsForHash().hasKey(key, item);
      }
  
      /**
       * Hash递增，如果不存在则创建一个，并把新增的值返回
       * @param key 键
       * @param item 项
       * @param by 递增大小 > 0
       * @return
       */
      public Double hincr(String key, String item, Double by) {
          return redisTemplate.opsForHash().increment(key, item, by);
      }
  
      /**
       * Hash递减
       * @param key 键
       * @param item 项
       * @param by 递减大小
       * @return
       */
      public Double hdecr(String key, String item, Double by) {
          return redisTemplate.opsForHash().increment(key, item, -by);
      }
  
  //    ============================== Set ==============================
  
      /**
       * 根据 key 获取 set 中的所有值
       * @param key 键
       * @return 值
       */
      public Set<Object> sGet(String key) {
          try {
              return redisTemplate.opsForSet().members(key);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }
  
      /**
       * 从键为 key 的 set 中，根据 value 查询是否存在
       * @param key 键
       * @param value 值
       * @return true / false
       */
      public boolean sHasKey(String key, Object value) {
          try {
              return redisTemplate.opsForSet().isMember(key, value);
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 将数据放入 set缓存
       * @param key 键值
       * @param values 值（可以多个）
       * @return 成功个数
       */
      public long sSet(String key, Object... values) {
          try {
              return redisTemplate.opsForSet().add(key, values);
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  
      /**
       * 将数据放入 set缓存，并设置时间
       * @param key 键
       * @param time 时间
       * @param values 值（可以多个）
       * @return 成功放入个数
       */
      public long sSet(String key, long time, Object... values) {
          try {
              long count = redisTemplate.opsForSet().add(key, values);
              if (time > 0) {
                  expire(key, time);
              }
              return count;
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  
      /**
       * 获取 set缓存的长度
       * @param key 键
       * @return 长度
       */
      public long sGetSetSize(String key) {
          try {
              return redisTemplate.opsForSet().size(key);
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  
      /**
       * 移除 set缓存中，值为 value 的
       * @param key 键
       * @param values 值
       * @return 成功移除个数
       */
      public long setRemove(String key, Object... values) {
          try {
              return redisTemplate.opsForSet().remove(key, values);
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  //    ============================== ZSet ==============================
  
      /**
       * 添加一个元素, zset与set最大的区别就是每个元素都有一个score，因此有个排序的辅助功能;  zadd
       *
       * @param key
       * @param value
       * @param score
       */
      public void zAdd(Object key, Object value, double score) {
          redisTemplate.opsForZSet().add(key, value, score);
      }
  
      /**
       * 删除元素 zrem
       *
       * @param key
       * @param value
       */
      public void zRemove(Object key, Object value) {
          redisTemplate.opsForZSet().remove(key, value);
      }
  
      /**
       * score的增加or减少 zincrby
       *
       * @param key
       * @param value
       * @param score
       */
      public Double zIncrScore(Object key, Object value, double score) {
          return redisTemplate.opsForZSet().incrementScore(key, value, score);
      }
  
      /**
       * 查询value对应的score   zscore
       *
       * @param key
       * @param value
       * @return
       */
      public Double zScore(Object key, Object value) {
          return redisTemplate.opsForZSet().score(key, value);
      }
  
      /**
       * 判断value在zset中的排名  zrank
       *
       * @param key
       * @param value
       * @return
       */
      public Long zRank(Object key, Object value) {
          return redisTemplate.opsForZSet().rank(key, value);
      }
  
      /**
       * 返回集合的长度
       *
       * @param key
       * @return
       */
      public Long zSize(Object key) {
          return redisTemplate.opsForZSet().zCard(key);
      }
  
      /**
       * 查询集合中指定顺序的值， 0 -1 表示获取全部的集合内容  zrange
       *
       * 返回有序的集合，score小的在前面
       *
       * @param key
       * @param start
       * @param end
       * @return
       */
      public Set<Object> ZRange(Object key, int start, int end) {
          return redisTemplate.opsForZSet().range(key, start, end);
      }
      /**
       * 查询集合中指定顺序的值和score，0, -1 表示获取全部的集合内容
       *
       * @param key
       * @param start
       * @param end
       * @return
       */
      public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScore(Object key, int start, int end) {
          return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
      }
      /**
       * 查询集合中指定顺序的值  zrevrange
       *
       * 返回有序的集合中，score大的在前面
       *
       * @param key
       * @param start
       * @param end
       * @return
       */
      public Set<Object> zRevRange(Object key, int start, int end) {
          return redisTemplate.opsForZSet().reverseRange(key, start, end);
      }
      /**
       * 根据score的值，来获取满足条件的集合  zrangebyscore
       *
       * @param key
       * @param min
       * @param max
       * @return
       */
      public Set<Object> zSortRange(Object key, int min, int max) {
          return redisTemplate.opsForZSet().rangeByScore(key, min, max);
      }
  
  
  //    ============================== List ==============================
  
      /**
       * 获取 list缓存的内容
       * @param key 键
       * @param start 开始
       * @param end 结束（0 到 -1 代表所有值）
       * @return
       */
      public List<Object> lGet(String key, long start, long end) {
          try {
              return redisTemplate.opsForList().range(key, start, end);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }
  
      /**
       * 获取 list缓存的长度
       * @param key 键
       * @return 长度
       */
      public long lGetListSize(String key) {
          try {
              return redisTemplate.opsForList().size(key);
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  
      /**
       * 根据索引 index 获取键为 key 的 list 中的元素
       * @param key 键
       * @param index 索引
       *              当 index >= 0 时 {0:表头, 1:第二个元素}
       *              当 index < 0 时 {-1:表尾, -2:倒数第二个元素}
       * @return 值
       */
      public Object lGetIndex(String key, long index) {
          try {
              return redisTemplate.opsForList().index(key, index);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }
  
      /**
       * 将值 value 插入键为 key 的 list 中，如果 list 不存在则创建空 list
       * @param key 键
       * @param value 值
       * @return true / false
       */
      public boolean lSet(String key, Object value) {
          try {
              redisTemplate.opsForList().rightPush(key, value);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 将值 value 插入键为 key 的 list 中，并设置时间
       * @param key 键
       * @param value 值
       * @param time 时间
       * @return true / false
       */
      public boolean lSet(String key, Object value, long time) {
          try {
              redisTemplate.opsForList().rightPush(key, value);
              if (time > 0) {
                  expire(key, time);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 将 values 插入键为 key 的 list 中
       * @param key 键
       * @param values 值
       * @return true / false
       */
      public boolean lSetList(String key, List<Object> values) {
          try {
              redisTemplate.opsForList().rightPushAll(key, values);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 将 values 插入键为 key 的 list 中，并设置时间
       * @param key 键
       * @param values 值
       * @param time 时间
       * @return true / false
       */
      public boolean lSetList(String key, List<Object> values, long time) {
          try {
              redisTemplate.opsForList().rightPushAll(key, values);
              if (time > 0) {
                  expire(key, time);
              }
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 根据索引 index 修改键为 key 的值
       * @param key 键
       * @param index 索引
       * @param value 值
       * @return true / false
       */
      public boolean lUpdateIndex(String key, long index, Object value) {
          try {
              redisTemplate.opsForList().set(key, index, value);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              return false;
          }
      }
  
      /**
       * 在键为 key 的 list 中删除值为 value 的元素
       * @param key 键
       * @param count 如果 count == 0 则删除 list 中所有值为 value 的元素
       *              如果 count > 0 则删除 list 中最左边那个值为 value 的元素
       *              如果 count < 0 则删除 list 中最右边那个值为 value 的元素
       * @param value
       * @return
       */
      public long lRemove(String key, long count, Object value) {
          try {
              return redisTemplate.opsForList().remove(key, count, value);
          } catch (Exception e) {
              e.printStackTrace();
              return 0;
          }
      }
  
      /**
       * 模糊查询
       * @param key 键
       * @return true / false
       */
      public List<Object> keys(String key) {
          try {
              Set<Object> set = redisTemplate.keys(key);
              return new ArrayList<>(set);
          } catch (Exception e) {
              e.printStackTrace();
              return null;
          }
      }
  
  
      /**
       * 模糊查询
       * @param query 查询参数
       * @return
       */
  //    public List<Object> scan(String query) {
  //        List<Object> result = new ArrayList<>();
  //        try {
  //            Cursor<Map.Entry<Object,Object>> cursor = redisTemplate.opsForHash().scan("field",
  //                    ScanOptions.scanOptions().match(query).count(1000).build());
  //            while (cursor.hasNext()) {
  //                Map.Entry<Object,Object> entry = cursor.next();
  //                result.add(entry.getKey());
  //                Object key = entry.getKey();
  //                Object valueSet = entry.getValue();
  //            }
  //            //关闭cursor
  //            cursor.close();
  //        } catch (Exception e) {
  //            e.printStackTrace();
  //        }
  //        return result;
  //    }
  
      /**
       * 模糊查询
       * @param query 查询参数
       * @return
       */
      public List<Object> scan(String query) {
          Set<String> resultKeys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
              ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();
              Cursor<byte[]> scan = connection.scan(scanOptions);
              Set<String> keys = new HashSet<>();
              while (scan.hasNext()) {
                  byte[] next = scan.next();
                  keys.add(new String(next));
              }
              return keys;
          });
  
          return new ArrayList<>(resultKeys);
      }
  
  }
  