diff --git a/.gitignore b/.gitignore index 32858aa..fa3193d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +*.iml +.idea/spring-data-redis-tools.iml diff --git a/README.md b/README.md index b78706b..634eda5 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,109 @@ # spring-data-redis-tools -spring data redis 封装工具类 +- RedisTemplate封装工具类 `redisTools` +- 可视化分布式ID生成器 `distributedId` (eg:JD202501010001) +- 可靠分布式锁工具类 `distributedLock`(lua脚本实现原子性解决断电问题、valueId避免错误释放问题) +- [Redis技术总结思维导图](#user-content-redis技术总结) *** ## Maven -```html - - redis.clients - jedis - 2.6.2 - - - org.springframework.data - spring-data-redis - 1.5.1.RELEASE - +```xml + + org.springframework.boot + spring-boot-starter-data-redis + ``` -## applicationContext.xml -```html - - - - - - - - - - - +## RedisConfiguration +```java +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import redis.clients.jedis.JedisPoolConfig; + +/** + * @author wellJay + */ +@Configuration +@EnableCaching +public class RedisConfiguration { + //过期时间一天 + private static final int DEFAULT_EXPIRE_TIME = 3600 * 24; + + //从配置文件读取redis参数 + @Autowired + private CloudConfigProperties cloudConfigProperties; + + /** + * jedisPoolConfig config + */ + @Bean + public JedisPoolConfig jedisPoolConfig() { + JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); + jedisPoolConfig.setMaxIdle(cloudConfigProperties.getRedis().getMaxIdle()); + jedisPoolConfig.setMinIdle(cloudConfigProperties.getRedis().getMinIdle()); + jedisPoolConfig.setTestOnBorrow(cloudConfigProperties.getRedis().getTestOnBorrow()); + jedisPoolConfig.setTestOnReturn(cloudConfigProperties.getRedis().getTestOnReturn()); + return jedisPoolConfig; + } + + /** + * JedisConnectionFactory + */ + @Bean + public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) { + JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); + jedisConnectionFactory.setHostName(cloudConfigProperties.getRedis().getHost()); + jedisConnectionFactory.setPort(cloudConfigProperties.getRedis().getPort()); + jedisConnectionFactory.setPassword(cloudConfigProperties.getRedis().getPassword()); + jedisConnectionFactory.setTimeout(cloudConfigProperties.getRedis().getTimeout()); + jedisConnectionFactory.setUsePool(true); + jedisConnectionFactory.setPoolConfig(jedisPoolConfig); + return jedisConnectionFactory; + } + + /** + * RedisTemplate + * 从执行时间上来看,JdkSerializationRedisSerializer是最高效的(毕竟是JDK原生的),但是是序列化的结果字符串是最长的。 + * JSON由于其数据格式的紧凑性,序列化的长度是最小的,时间比前者要多一些。 + * 所以个人的选择是倾向使用JacksonJsonRedisSerializer作为POJO的序列器。 + */ + @Bean + public RedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate(); + redisTemplate.setConnectionFactory(jedisConnectionFactory); + redisTemplate.setDefaultSerializer(new StringRedisSerializer()); + //设置普通value序列化方式 + redisTemplate.setValueSerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer()); + return redisTemplate; + } + + @Bean + public CacheManager cacheManager(RedisTemplate redisTemplate) { + RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate); + redisCacheManager.setDefaultExpiration(DEFAULT_EXPIRE_TIME); + return redisCacheManager; + } +} ``` + +## How To Use +1、注入util方式,适用于复杂的业务处理 +```java +@Autowired +private RedisCacheUtil redisCacheUtil; +``` +2、Spring注解方式适用于简单的数据缓存 +```java +@Cacheable(value = Constants.RedisKey.XXX_KEY) +``` +## Redis技术总结 +![](Redis技术总结.png) + + + diff --git "a/Redis\346\212\200\346\234\257\346\200\273\347\273\223.png" "b/Redis\346\212\200\346\234\257\346\200\273\347\273\223.png" new file mode 100644 index 0000000..114d8d9 Binary files /dev/null and "b/Redis\346\212\200\346\234\257\346\200\273\347\273\223.png" differ diff --git a/distributedId/OrderNumberGenerate.java b/distributedId/OrderNumberGenerate.java new file mode 100644 index 0000000..c2df8fb --- /dev/null +++ b/distributedId/OrderNumberGenerate.java @@ -0,0 +1,50 @@ +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by WenJie on 2015/11/3. + * 可视化分布式唯一订单号生成器 20151103001 + */ +@Component +public class OrderNumberGenerate { + + public static final String FROMAT_STR = "yyyyMMddHHmm"; + private static StringRedisTemplate staticTemplate; + + @Autowired + public static void setStaticTemplate(StringRedisTemplate staticTemplate) { + OrderNumberGenerate.staticTemplate = staticTemplate; + } + + private OrderNumberGenerate() { + } + + /** + * 生成订单编号 + * date存redis,只要date变化则直接increment=1,否则就是并发冲突直接increment++保证分布式唯一id + * + * public static final String FLOWER_ORDER_NUMBER_INCR = "order_number_incr"; + * public static final String FLOWER_ORDER_NUMBER_DATE = "order_number_date"; + * + * @return + */ + public static synchronized String getOrderNo() { + String str = new SimpleDateFormat(FROMAT_STR).format(new Date()); + String date = staticTemplate.opsForValue().get(CacheKey.FLOWER_ORDER_NUMBER_DATE); + if (date == null || !date.equals(str)) { + //保存时间 + staticTemplate.opsForValue().set(CacheKey.FLOWER_ORDER_NUMBER_DATE, str); + //缓存清除 + staticTemplate.delete(CacheKey.FLOWER_ORDER_NUMBER_INCR); + } + //缓存++ + Long incrementValue = staticTemplate.opsForValue().increment(CacheKey.FLOWER_ORDER_NUMBER_INCR, 1); + long orderNo = Long.parseLong(date) * 10000; + orderNo += incrementValue; + return orderNo + ""; + } +} diff --git a/distributedLock/README.md b/distributedLock/README.md new file mode 100644 index 0000000..4005d8d --- /dev/null +++ b/distributedLock/README.md @@ -0,0 +1,6 @@ +- `RedisLockTool.tryGetDistributedLock();` GET LOCK key = caller className&method value = Current Thread Id +- `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId);` GET LOCK +- `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond);` +- `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond, Long loopTimes, Long sleepInterval);` + +redis集群情况下推荐[RedLock](https://github.com/redisson/redisson) diff --git a/distributedLock/RedisLockTool.java b/distributedLock/RedisLockTool.java new file mode 100644 index 0000000..4bf8f47 --- /dev/null +++ b/distributedLock/RedisLockTool.java @@ -0,0 +1,137 @@ +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.concurrent.TimeUnit; +/** + * @author wenjie + * @date 2018/5/7 0007 16:44 + */ +@Component +public final class RedisLockTool { + + private static final Long SUCCESS = 1L; + public static final String LOCK_SCRIPT_STR = "if redis.call('set',KEYS[1],ARGV[1],'EX',ARGV[2],'NX') then return 1 else return 0 end"; + public static final String UNLOCK_SCRIPT_STR = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; + + //default value + public static final Integer DEFAULT_EXPIRE_SECOND = 60; + public static final Long DEFAULT_LOOP_TIMES = 10L; + public static final Long DEFAULT_SLEEP_INTERVAL = 500L; + public static final String PACKAGE_NAME_SPLIT_STR = "\\."; + public static final String CLASS_AND_METHOD_CONCAT_STR = "->"; + + private static RedisTemplate redisTemplate; + + @Autowired + public void init(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + /** + * 得到分布式锁 + * 默认key:调用者类名 + * + * @return + * @throws InterruptedException + */ + public static boolean tryGetDistributedLock() { + String callerKey = getCurrentThreadCaller(); + String requestId = String.valueOf(Thread.currentThread().getId()); + return tryGetDistributedLock(callerKey, requestId); + } + + /** + * @param lockKey 锁名称 + * @param requestId 随机请求id + * @return + * @throws InterruptedException + */ + public static boolean tryGetDistributedLock(String lockKey, String requestId) { + return tryGetDistributedLock(lockKey, requestId, DEFAULT_EXPIRE_SECOND); + } + + /** + * @param lockKey key + * @param requestId 随机请求id + * @param expireSecond 超时秒 + * @return + * @throws InterruptedException + */ + public static boolean tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond) { + return tryGetDistributedLock(lockKey, requestId, expireSecond, DEFAULT_LOOP_TIMES, DEFAULT_SLEEP_INTERVAL); + } + + + /** + * 加锁 + * + * @param lockKey key + * @param requestId 随机请求id + * @param expireSecond 超时秒 + * @param loopTimes 循环次数 + * @param sleepInterval 等待间隔(毫秒) + * @return + */ + public static boolean tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond, Long loopTimes, Long sleepInterval) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(LOCK_SCRIPT_STR, Long.class); + while (loopTimes-- >= 0) { + Object result = redisTemplate.execute(redisScript, Lists.newArrayList(lockKey), requestId, String.valueOf(expireSecond)); + if (SUCCESS.equals(result)) { + return true; + } + try { + TimeUnit.MILLISECONDS.sleep(sleepInterval); + } catch (InterruptedException e) { + e.printStackTrace(); + } + continue; + } + return false; + } + + + /** + * 释放锁 + * + * @return + */ + public static boolean releaseDistributedLock() { + String callerKey = getCurrentThreadCaller(); + String requestId = String.valueOf(Thread.currentThread().getId()); + return releaseDistributedLock(callerKey, requestId); + } + + /** + * 释放锁 + * + * @param lockKey key + * @param requestId 加锁的请求id + * @return + */ + public static boolean releaseDistributedLock(String lockKey, String requestId) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT_STR, Long.class); + Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId); + if (SUCCESS.equals(result)) { + return true; + } + return false; + } + + private static String getSimpleClassName(String className) { + String[] splits = className.split(PACKAGE_NAME_SPLIT_STR); + return splits[splits.length - 1]; + } + + /** + * Get caller + * + * @return + */ + private static String getCurrentThreadCaller() { + StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[3]; + return getSimpleClassName(stackTraceElement.getClassName()) + CLASS_AND_METHOD_CONCAT_STR + stackTraceElement.getMethodName(); + } +} diff --git a/distributedLock/Test.java b/distributedLock/Test.java new file mode 100644 index 0000000..2fe2c3c --- /dev/null +++ b/distributedLock/Test.java @@ -0,0 +1,60 @@ +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Application.class) +public class ApplicationTests { + + @Test + public void distributedLock() throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(10); + + for (int i = 0; i < 10; i++) { + Thread thread = new Thread(new Tester(), "Thread-" + i); + countDownLatch.countDown(); + thread.start(); + } + + countDownLatch.await(); + + System.out.println("down"); + + Thread.sleep(Integer.MAX_VALUE); + } + + class Tester implements Runnable { + + public static final int RANDOM_NUMBER_RANGE = 3; + + @Override + public void run() { + //获取锁, key:caller className&method value:Current Thread Id + //也可以传参 key value 可选[expireSecond loopTimes sleepInterval] + boolean result = RedisLockTool.tryGetDistributedLock(); + if (result) { + System.out.println(Thread.currentThread().getName() + ": get lock"); + } else { + System.err.println(Thread.currentThread().getName() + ": get lock timeout"); + } + + //if get the lock + if (result) { + try { + TimeUnit.SECONDS.sleep(new Random().nextInt(RANDOM_NUMBER_RANGE)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + RedisLockTool.releaseDistributedLock(); + System.out.println(Thread.currentThread().getName() + ": release lock"); + } + } + } +} + diff --git a/impl/RedisDaoTool.java b/impl/RedisDaoTool.java deleted file mode 100644 index a7c7fea..0000000 --- a/impl/RedisDaoTool.java +++ /dev/null @@ -1,386 +0,0 @@ -package com.brandbigdata.rep.redis.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.springframework.dao.DataAccessException; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.stereotype.Repository; - -import com.brandbigdata.rep.redis.inter.AbstractBaseRedisDao; - -/** - * @author Wen Jie - * - */ -@Repository -public class StringRedisDao extends AbstractBaseRedisDao { - - // ----------------------------------------Object---------------------------------------- - /** - * 设置对象 - * - * @param key - * @param object - * @param timeout - * @param 对象class - * @return - * @throws Exception - */ - public boolean addObject(final String key, final Object object, final Long timeout, Class clazz) throws BbdException { - redisTemplate.opsForValue().set(key, clazz.cast(object)); - return true; - } - - /** - * 获得对象 - * - * @param key - * @return - */ - public Object getObject(final String key) { - return redisTemplate.opsForValue().get(key); - } - - // ---------------------------------------String----------------------------------------- - - /** - * 新增String ----setNX 不存在则增加 ------------------------------ - * - * @param key - * 键 - * @param value - * 值 - * @param timout - * 超时(秒) - * @return true 操作成功,false 已存在值 - */ - public boolean addString(final String key, final String value, final Long timeout) { - boolean result = redisTemplate.execute(new RedisCallback() { - public Boolean doInRedis(RedisConnection connection) throws DataAccessException { - Boolean result = connection.setNX(key.getBytes(), value.getBytes()); - if (result == false) - return result; - if (timeout != null && timeout > 0) - connection.expire(key.getBytes(), timeout); - return result; - } - }); - return result; - } - - /** - * 批量新增String---setNx 不存在则增加 - * - * @param keyValueList - * 键值对的map - * @param timeout - * 超时处理 - * @return - */ - public boolean addString(final Map keyValueList, final Long timeout) { - boolean result = redisTemplate.execute(new RedisCallback() { - public Boolean doInRedis(RedisConnection connection) throws DataAccessException { - for (String key : keyValueList.keySet()) { - connection.setNX(key.getBytes(), keyValueList.get(key).getBytes()); - if (timeout != null && timeout > 0) - connection.expire(key.getBytes(), timeout); - } - return true; - } - }, false, true); - return result; - } - - /** - * 通过key获取单个 - * - * @param key - * @return - */ - public String getString(final String key) { - String value = redisTemplate.execute(new RedisCallback() { - public String doInRedis(RedisConnection connection) throws DataAccessException { - byte[] result = connection.get(key.getBytes()); - if(result != null && result.length > 0) - return new String(result); - return null; - } - }); - return value; - } - - /** - * 修改 String - * - * @param key - * @param value - * @return - */ - /* - 重新Set等于Update - public boolean updateString(final String key, final String value) { - if (getString(key) == null) { - throw new NullPointerException("数据行不存在, key = " + key); - } - boolean result = redisTemplate.execute(new RedisCallback() { - public Boolean doInRedis(RedisConnection connection) throws DataAccessException { - connection.set(key.getBytes(), value.getBytes()); - return true; - } - }); - return result; - } - / - - // ---------------------------------------List----------------------------------------- - /** - * 新增Hash ----setNX 不存在则增加 ------------------------------ - * - * @param key - * 键 - * @param value - * 值 - * @param timout - * 超时(秒) - * @return true 操作成功,false 已存在值 - */ - public boolean addHash(final String key, final String field, final String value, final Long timeout) { - boolean result = redisTemplate.execute(new RedisCallback() { - public Boolean doInRedis(RedisConnection connection) throws DataAccessException { - Boolean result = connection.hSetNX(key.getBytes(), field.getBytes(), value.getBytes()); - if (result == false) - return result; - if (timeout != null && timeout > 0) - connection.expire(key.getBytes(), timeout); - return result; - } - }); - return result; - } - - /** - * 批量新增Hash ----setNX 不存在则增加 ------------------------------ - * - * @param key - * 键 - * @param value - * 值 - * @param timout - * 超时(秒) - * @return true 操作成功,false 已存在值 - */ - public boolean addHash(final String key, final Map fieldValueList, final Long timeout) { - boolean result = redisTemplate.execute(new RedisCallback() { - public Boolean doInRedis(RedisConnection connection) throws DataAccessException { - for (String hashKey : fieldValueList.keySet()) { - connection.hSetNX(key.getBytes(), hashKey.getBytes(), fieldValueList.get(hashKey).getBytes()); - if (timeout != null && timeout > 0) - connection.expire(key.getBytes(), timeout); - } - return true; - } - }); - return result; - } - - /** - * 通过key获取单个 - * - * @param key - * @return - */ - public Object getHashField(final String key, final String field) { - String value = redisTemplate.execute(new RedisCallback() { - public String doInRedis(RedisConnection connection) throws DataAccessException { - return new String(connection.hGet(key.getBytes(), field.getBytes())); - } - }); - return value; - } - - /** - * 通过key获取整个Hash - * - * @param key - * @return - */ - public Map getHashAll(final String key, final String field) { - Map value = redisTemplate.execute(new RedisCallback>() { - public Map doInRedis(RedisConnection connection) throws DataAccessException { - return connection.hGetAll(key.getBytes()); - } - }); - return value; - } - - //---------------------------------------------------通用删除------------------------------------------------- - /** - * 删除单个 - * - * @param key - */ - public void delete(final String key) { - redisTemplate.execute(new RedisCallback() { - public Long doInRedis(RedisConnection connection) throws DataAccessException { - return connection.del(key.getBytes()); - } - }); - } - - - //----------------------------------------------------队列操作-------------------------------------------------- - /** - * 压栈 - * - * @param key - * @param value - * @return - */ - public Long push(String key, String value) { - return redisTemplate.opsForList().leftPush(key, value); - } - - /** - * 出栈 - * - * @param key - * @return - */ - public String pop(String key) { - return (String) redisTemplate.opsForList().leftPop(key); - } - - /** - * 入队 - * - * @param key - * @param value - * @return - */ - public Long in(String key, String value) { - return redisTemplate.opsForList().rightPush(key, value); - } - - /** - * 出队 - * - * @param key - * @return - */ - public String out(String key) { - return (String) redisTemplate.opsForList().leftPop(key); - } - - /** - * 栈/队列长 - * - * @param key - * @return - */ - public Long length(String key) { - return redisTemplate.opsForList().size(key); - } - - /** - * 范围检索 - * - * @param key - * @param start - * @param end - * @return - */ - public List range(String key, int start, int end) { - return redisTemplate.opsForList().range(key, start, end); - } - - /** - * 移除 - * - * @param key - * @param i - * @param value - */ - public void remove(String key, long i, String value) { - redisTemplate.opsForList().remove(key, i, value); - } - - /** - * 检索 - * - * @param key - * @param index - * @return - */ - public String index(String key, long index) { - return (String) redisTemplate.opsForList().index(key, index); - } - - /** - * 置值 - * - * @param key - * @param index - * @param value - */ - public void set(String key, long index, String value) { - redisTemplate.opsForList().set(key, index, value); - } - - /** - * 裁剪 - * - * @param key - * @param start - * @param end - */ - public void trim(String key, long start, int end) { - redisTemplate.opsForList().trim(key, start, end); - } - - //---------------------------------------------------SET----------------------------------------------- - /** - * 新增Set ----setNX 不存在则增加 ------------------------------ - * - * @param key - * 键 - * @param value - * 值 - * @param timout - * 超时(秒) - * @return true 操作成功,false 已存在值 - */ - public Long addSet(final String key, final String value, final Long timeout) { - Long result = redisTemplate.execute(new RedisCallback() { - public Long doInRedis(RedisConnection connection) throws DataAccessException { - Long result = connection.sAdd(key.getBytes(), value.getBytes()); - if (result == 0) - return result; - if (timeout != null && timeout > 0) - connection.expire(key.getBytes(), timeout); - return result; - } - }); - return result; - } - - - /** - * 通过key获取单个Set - * - * @param key - * @return - */ - public Set getSet(final String key) { - Set value = redisTemplate.execute(new RedisCallback>() { - public Set doInRedis(RedisConnection connection) throws DataAccessException { - return connection.sMembers(key.getBytes()); - } - }); - return value; - } - -} diff --git a/inter/AbstractBaseRedisDao.java b/inter/AbstractBaseRedisDao.java deleted file mode 100644 index af8a759..0000000 --- a/inter/AbstractBaseRedisDao.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.brandbigdata.rep.redis.inter; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.RedisSerializer; - -public abstract class AbstractBaseRedisDao { - @Autowired - protected RedisTemplate redisTemplate; - - /** - * 设置redisTemplate - * @param redisTemplate the redisTemplate to set - */ - public void setRedisTemplate(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - /** - * 获取 String RedisSerializer - *
------------------------------
- */ - protected RedisSerializer getStringSerializer() { - return redisTemplate.getStringSerializer(); - } - -} diff --git a/redisTools/GeoRadiusDto.java b/redisTools/GeoRadiusDto.java new file mode 100644 index 0000000..9194ab3 --- /dev/null +++ b/redisTools/GeoRadiusDto.java @@ -0,0 +1,35 @@ +/** + * 地理位置相关dto + */ +public class GeoRadiusDto { + + private String member; + + private Double x; + + private Double y; + + public String getMember() { + return member; + } + + public void setMember(String member) { + this.member = member; + } + + public Double getX() { + return x; + } + + public void setX(Double x) { + this.x = x; + } + + public Double getY() { + return y; + } + + public void setY(Double y) { + this.y = y; + } +} diff --git a/redisTools/RedisCacheUtil.java b/redisTools/RedisCacheUtil.java new file mode 100644 index 0000000..d28b28c --- /dev/null +++ b/redisTools/RedisCacheUtil.java @@ -0,0 +1,352 @@ +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author wenjie + * @create 2017-06-15 19:09 + **/ +@Component +public class RedisCacheUtil { + + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @return 缓存的对象 + */ + public ValueOperations setCacheObject(String key, T value) { + ValueOperations operation = redisTemplate.opsForValue(); + operation.set(key, value); + return operation; + } + + public ValueOperations setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) { + ValueOperations operation = redisTemplate.opsForValue(); + operation.set(key, value, timeout, timeUnit); + return operation; + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(String key) { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public void deleteObject(String key) { + redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection + */ + public void deleteObject(Collection collection) { + redisTemplate.delete(collection); + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public ListOperations setCacheList(String key, List dataList) { + ListOperations listOperation = redisTemplate.opsForList(); + if (null != dataList) { + int size = dataList.size(); + for (int i = 0; i < size; i++) { + listOperation.leftPush(key, dataList.get(i)); + } + } + return listOperation; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(String key) { + List dataList = new ArrayList(); + ListOperations listOperation = redisTemplate.opsForList(); + Long size = listOperation.size(key); + + for (int i = 0; i < size; i++) { + dataList.add(listOperation.index(key, i)); + } + return dataList; + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet(String key, Set dataSet) { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(String key) { + Set dataSet = new HashSet(); + BoundSetOperations operation = redisTemplate.boundSetOps(key); + Long size = operation.size(); + for (int i = 0; i < size; i++) { + dataSet.add(operation.pop()); + } + return dataSet; + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + * @return + */ + public HashOperations setCacheMap(String key, Map dataMap) { + + HashOperations hashOperations = redisTemplate.opsForHash(); + if (null != dataMap) { + for (Map.Entry entry : dataMap.entrySet()) { + hashOperations.put(key, entry.getKey(), entry.getValue()); + } + } + return hashOperations; + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(String key) { + Map map = redisTemplate.opsForHash().entries(key); + return map; + } + + + /** + * 缓存Map + * + * @param key + * @param dataMap + * @return + */ + public HashOperations setCacheIntegerMap(String key, Map dataMap) { + HashOperations hashOperations = redisTemplate.opsForHash(); + if (null != dataMap) { + for (Map.Entry entry : dataMap.entrySet()) { + hashOperations.put(key, entry.getKey(), entry.getValue()); + } + } + return hashOperations; + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheIntegerMap(String key) { + Map map = redisTemplate.opsForHash().entries(key); + return map; + } + + + //=====================GEO地理位置相关===================== + + /** + * 增加定位点 + * + * @param x + * @param y + * @param member + * @param time + * @return + */ + public boolean addGeo(double x, double y, String member, long time) { + String key = GEO_KEY; + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + geoOps.add(key, new Point(x, y), member); + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + } catch (Throwable t) { + t.printStackTrace(); + log.error("缓存[" + key + "]" + "失败, point[" + x + "," + + y + "], member[" + member + "]" + ", error[" + t + "]"); + } + return true; + } + + + /** + * 删除定位点 + * + * @param members + * @return + */ + public boolean removeGeo(String... members) { + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + geoOps.remove(GEO_KEY, members); + } catch (Throwable t) { + log.error("移除[" + GEO_KEY + "]" + "失败" + ", error[" + t + "]"); + } + return true; + } + + + /** + * 计算定位距离 + * + * @param member1 + * @param member2 + * @return + */ + public Distance distanceGeo(String member1, String member2) { + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + return geoOps.geoDist(GEO_KEY, member1, member2); + } catch (Throwable t) { + log.error("计算距离[" + GEO_KEY + "]" + "失败, member[" + member1 + "," + member2 + "], error[" + t + "]"); + } + return null; + } + + /** + * 获取坐标 + * + * @param members + * @return + */ + public List getGeo(String... members) { + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + return geoOps.position(GEO_KEY, members); + } catch (Throwable t) { + log.error("获取坐标[" + GEO_KEY + "]" + "失败]" + ", error[" + t + "]"); + } + return null; + } + + /** + * 基于某个坐标的附近的东西 + * + * @param x + * @param y + * @param distance + * @param direction + */ + public List raduisGeo(double x, double y, double distance, Sort.Direction direction) { + List radiusDtos = new ArrayList<>(); + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + + //设置geo查询参数 + RedisGeoCommands.GeoRadiusCommandArgs geoRadiusArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs(); + geoRadiusArgs = geoRadiusArgs.includeCoordinates().includeDistance();//查询返回结果包括距离和坐标 + if (Sort.Direction.ASC.equals(direction)) {//按查询出的坐标距离中心坐标的距离进行排序 + geoRadiusArgs.sortAscending(); + } else if (Sort.Direction.DESC.equals(direction)) { + geoRadiusArgs.sortDescending(); + } + GeoResults> geoResults = geoOps.radius(GEO_KEY, new Circle(new Point(x, y), new Distance(distance, RedisGeoCommands.DistanceUnit.METERS)), geoRadiusArgs); + + List>> geoResultList = geoResults.getContent(); + for (GeoResult> geoResult : geoResultList) { + String name = geoResult.getContent().getName(); + Point point = geoResult.getContent().getPoint(); + GeoRadiusDto radiusDto = new GeoRadiusDto(); + radiusDto.setMember(name); + radiusDto.setX(point.getX()); + radiusDto.setY(point.getY()); + radiusDtos.add(radiusDto); + } + } catch (Throwable t) { + + } + return radiusDtos; + } + + + /** + * 基于某个key的附近的东西 + * + * @param member + * @param distance + * @param direction + */ + public List raduisGeo(String member, double distance, Sort.Direction direction) { + List radiusDtos = new ArrayList<>(); + try { + GeoOperations geoOps = redisTemplate.opsForGeo(); + + //设置geo查询参数 + RedisGeoCommands.GeoRadiusCommandArgs geoRadiusArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs(); + geoRadiusArgs = geoRadiusArgs.includeCoordinates().includeDistance();//查询返回结果包括距离和坐标 + if (Sort.Direction.ASC.equals(direction)) {//按查询出的坐标距离中心坐标的距离进行排序 + geoRadiusArgs.sortAscending(); + } else if (Sort.Direction.DESC.equals(direction)) { + geoRadiusArgs.sortDescending(); + } + GeoResults> geoResults = geoOps.radius(GEO_KEY, member, new Distance(distance, RedisGeoCommands.DistanceUnit.METERS), geoRadiusArgs); + + List>> geoResultList = geoResults.getContent(); + for (GeoResult> geoResult : geoResultList) { + String name = geoResult.getContent().getName(); + //结果集排除自己 + if (!name.equals(member)) { + Point point = geoResult.getContent().getPoint(); + GeoRadiusDto radiusDto = new GeoRadiusDto(); + radiusDto.setMember(name); + radiusDto.setX(point.getX()); + radiusDto.setY(point.getY()); + radiusDtos.add(radiusDto); + } + } + } catch (Throwable t) { + + } + return radiusDtos; + } + + +} diff --git a/testController/SystemController.java b/testController/SystemController.java deleted file mode 100644 index 86160a8..0000000 --- a/testController/SystemController.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.brandbigdata.rep.business.action; - -import javax.annotation.Resource; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -import com.brandbigdata.daemon.Rlinks; -import com.brandbigdata.rep.redis.impl.StringRedisDao; -import com.brandbigdata.utils.DateUtil; - -@Controller -@RequestMapping("system") -public class SystemController extends SuperController { - - @Resource - private StringRedisDao redis; - - @RequestMapping("test") - public String test(){ - //redis对象储存方法 - Rlinks rlinks = new Rlinks(); - rlinks.setLine("456"); - try { - redis.addObject("test", rlinks, DateUtil.getSecondFromDay(7), Rlinks.class); - } catch (Exception e) { - //log.error(e.getMessage()); - } - Rlinks r1 = (Rlinks)redis.getObject("test"); - System.out.println(r1.getLine()); - - return "system/files/addrenwu"; - } -} \ No newline at end of file