├── .gitignore
├── LICENSE
├── README.md
├── Redis技术总结.png
├── distributedId
└── OrderNumberGenerate.java
├── distributedLock
├── README.md
├── RedisLockTool.java
└── Test.java
└── redisTools
├── GeoRadiusDto.java
└── RedisCacheUtil.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 | *.iml
14 | .idea/spring-data-redis-tools.iml
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spring-data-redis-tools
2 | - RedisTemplate封装工具类 `redisTools`
3 | - 可视化分布式ID生成器 `distributedId` (eg:JD202501010001)
4 | - 可靠分布式锁工具类 `distributedLock`(lua脚本实现原子性解决断电问题、valueId避免错误释放问题)
5 | - [Redis技术总结思维导图](#user-content-redis技术总结)
6 | ***
7 | ## Maven
8 | ```xml
9 |
10 | org.springframework.boot
11 | spring-boot-starter-data-redis
12 |
13 | ```
14 | ## RedisConfiguration
15 | ```java
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.cache.CacheManager;
18 | import org.springframework.cache.annotation.EnableCaching;
19 | import org.springframework.context.annotation.Bean;
20 | import org.springframework.context.annotation.Configuration;
21 | import org.springframework.data.redis.cache.RedisCacheManager;
22 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
23 | import org.springframework.data.redis.core.RedisTemplate;
24 | import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
25 | import org.springframework.data.redis.serializer.StringRedisSerializer;
26 | import redis.clients.jedis.JedisPoolConfig;
27 |
28 | /**
29 | * @author wellJay
30 | */
31 | @Configuration
32 | @EnableCaching
33 | public class RedisConfiguration {
34 | //过期时间一天
35 | private static final int DEFAULT_EXPIRE_TIME = 3600 * 24;
36 |
37 | //从配置文件读取redis参数
38 | @Autowired
39 | private CloudConfigProperties cloudConfigProperties;
40 |
41 | /**
42 | * jedisPoolConfig config
43 | */
44 | @Bean
45 | public JedisPoolConfig jedisPoolConfig() {
46 | JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
47 | jedisPoolConfig.setMaxIdle(cloudConfigProperties.getRedis().getMaxIdle());
48 | jedisPoolConfig.setMinIdle(cloudConfigProperties.getRedis().getMinIdle());
49 | jedisPoolConfig.setTestOnBorrow(cloudConfigProperties.getRedis().getTestOnBorrow());
50 | jedisPoolConfig.setTestOnReturn(cloudConfigProperties.getRedis().getTestOnReturn());
51 | return jedisPoolConfig;
52 | }
53 |
54 | /**
55 | * JedisConnectionFactory
56 | */
57 | @Bean
58 | public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
59 | JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
60 | jedisConnectionFactory.setHostName(cloudConfigProperties.getRedis().getHost());
61 | jedisConnectionFactory.setPort(cloudConfigProperties.getRedis().getPort());
62 | jedisConnectionFactory.setPassword(cloudConfigProperties.getRedis().getPassword());
63 | jedisConnectionFactory.setTimeout(cloudConfigProperties.getRedis().getTimeout());
64 | jedisConnectionFactory.setUsePool(true);
65 | jedisConnectionFactory.setPoolConfig(jedisPoolConfig);
66 | return jedisConnectionFactory;
67 | }
68 |
69 | /**
70 | * RedisTemplate
71 | * 从执行时间上来看,JdkSerializationRedisSerializer是最高效的(毕竟是JDK原生的),但是是序列化的结果字符串是最长的。
72 | * JSON由于其数据格式的紧凑性,序列化的长度是最小的,时间比前者要多一些。
73 | * 所以个人的选择是倾向使用JacksonJsonRedisSerializer作为POJO的序列器。
74 | */
75 | @Bean
76 | public RedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
77 | RedisTemplate, ?> redisTemplate = new RedisTemplate();
78 | redisTemplate.setConnectionFactory(jedisConnectionFactory);
79 | redisTemplate.setDefaultSerializer(new StringRedisSerializer());
80 | //设置普通value序列化方式
81 | redisTemplate.setValueSerializer(new StringRedisSerializer());
82 | redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
83 | return redisTemplate;
84 | }
85 |
86 | @Bean
87 | public CacheManager cacheManager(RedisTemplate redisTemplate) {
88 | RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
89 | redisCacheManager.setDefaultExpiration(DEFAULT_EXPIRE_TIME);
90 | return redisCacheManager;
91 | }
92 | }
93 | ```
94 |
95 | ## How To Use
96 | 1、注入util方式,适用于复杂的业务处理
97 | ```java
98 | @Autowired
99 | private RedisCacheUtil redisCacheUtil;
100 | ```
101 | 2、Spring注解方式适用于简单的数据缓存
102 | ```java
103 | @Cacheable(value = Constants.RedisKey.XXX_KEY)
104 | ```
105 | ## Redis技术总结
106 | 
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/Redis技术总结.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WellJay/spring-data-redis-tools/001a6dcadb58cf914cfc9a082c6f1e5a999ce536/Redis技术总结.png
--------------------------------------------------------------------------------
/distributedId/OrderNumberGenerate.java:
--------------------------------------------------------------------------------
1 | import org.springframework.beans.factory.annotation.Autowired;
2 | import org.springframework.data.redis.core.StringRedisTemplate;
3 | import org.springframework.stereotype.Component;
4 |
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 |
8 | /**
9 | * Created by WenJie on 2015/11/3.
10 | * 可视化分布式唯一订单号生成器 20151103001
11 | */
12 | @Component
13 | public class OrderNumberGenerate {
14 |
15 | public static final String FROMAT_STR = "yyyyMMddHHmm";
16 | private static StringRedisTemplate staticTemplate;
17 |
18 | @Autowired
19 | public static void setStaticTemplate(StringRedisTemplate staticTemplate) {
20 | OrderNumberGenerate.staticTemplate = staticTemplate;
21 | }
22 |
23 | private OrderNumberGenerate() {
24 | }
25 |
26 | /**
27 | * 生成订单编号
28 | * date存redis,只要date变化则直接increment=1,否则就是并发冲突直接increment++保证分布式唯一id
29 | *
30 | * public static final String FLOWER_ORDER_NUMBER_INCR = "order_number_incr";
31 | * public static final String FLOWER_ORDER_NUMBER_DATE = "order_number_date";
32 | *
33 | * @return
34 | */
35 | public static synchronized String getOrderNo() {
36 | String str = new SimpleDateFormat(FROMAT_STR).format(new Date());
37 | String date = staticTemplate.opsForValue().get(CacheKey.FLOWER_ORDER_NUMBER_DATE);
38 | if (date == null || !date.equals(str)) {
39 | //保存时间
40 | staticTemplate.opsForValue().set(CacheKey.FLOWER_ORDER_NUMBER_DATE, str);
41 | //缓存清除
42 | staticTemplate.delete(CacheKey.FLOWER_ORDER_NUMBER_INCR);
43 | }
44 | //缓存++
45 | Long incrementValue = staticTemplate.opsForValue().increment(CacheKey.FLOWER_ORDER_NUMBER_INCR, 1);
46 | long orderNo = Long.parseLong(date) * 10000;
47 | orderNo += incrementValue;
48 | return orderNo + "";
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/distributedLock/README.md:
--------------------------------------------------------------------------------
1 | - `RedisLockTool.tryGetDistributedLock();` GET LOCK key = caller className&method value = Current Thread Id
2 | - `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId);` GET LOCK
3 | - `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond);`
4 | - `RedisLockTool.tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond, Long loopTimes, Long sleepInterval);`
5 |
6 | redis集群情况下推荐[RedLock](https://github.com/redisson/redisson)
7 |
--------------------------------------------------------------------------------
/distributedLock/RedisLockTool.java:
--------------------------------------------------------------------------------
1 | import org.springframework.beans.factory.annotation.Autowired;
2 | import org.springframework.data.redis.core.RedisTemplate;
3 | import org.springframework.data.redis.core.script.DefaultRedisScript;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.util.Collections;
7 | import java.util.concurrent.TimeUnit;
8 | /**
9 | * @author wenjie
10 | * @date 2018/5/7 0007 16:44
11 | */
12 | @Component
13 | public final class RedisLockTool {
14 |
15 | private static final Long SUCCESS = 1L;
16 | 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";
17 | 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";
18 |
19 | //default value
20 | public static final Integer DEFAULT_EXPIRE_SECOND = 60;
21 | public static final Long DEFAULT_LOOP_TIMES = 10L;
22 | public static final Long DEFAULT_SLEEP_INTERVAL = 500L;
23 | public static final String PACKAGE_NAME_SPLIT_STR = "\\.";
24 | public static final String CLASS_AND_METHOD_CONCAT_STR = "->";
25 |
26 | private static RedisTemplate redisTemplate;
27 |
28 | @Autowired
29 | public void init(RedisTemplate redisTemplate) {
30 | this.redisTemplate = redisTemplate;
31 | }
32 |
33 | /**
34 | * 得到分布式锁
35 | * 默认key:调用者类名
36 | *
37 | * @return
38 | * @throws InterruptedException
39 | */
40 | public static boolean tryGetDistributedLock() {
41 | String callerKey = getCurrentThreadCaller();
42 | String requestId = String.valueOf(Thread.currentThread().getId());
43 | return tryGetDistributedLock(callerKey, requestId);
44 | }
45 |
46 | /**
47 | * @param lockKey 锁名称
48 | * @param requestId 随机请求id
49 | * @return
50 | * @throws InterruptedException
51 | */
52 | public static boolean tryGetDistributedLock(String lockKey, String requestId) {
53 | return tryGetDistributedLock(lockKey, requestId, DEFAULT_EXPIRE_SECOND);
54 | }
55 |
56 | /**
57 | * @param lockKey key
58 | * @param requestId 随机请求id
59 | * @param expireSecond 超时秒
60 | * @return
61 | * @throws InterruptedException
62 | */
63 | public static boolean tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond) {
64 | return tryGetDistributedLock(lockKey, requestId, expireSecond, DEFAULT_LOOP_TIMES, DEFAULT_SLEEP_INTERVAL);
65 | }
66 |
67 |
68 | /**
69 | * 加锁
70 | *
71 | * @param lockKey key
72 | * @param requestId 随机请求id
73 | * @param expireSecond 超时秒
74 | * @param loopTimes 循环次数
75 | * @param sleepInterval 等待间隔(毫秒)
76 | * @return
77 | */
78 | public static boolean tryGetDistributedLock(String lockKey, String requestId, Integer expireSecond, Long loopTimes, Long sleepInterval) {
79 | DefaultRedisScript redisScript = new DefaultRedisScript<>(LOCK_SCRIPT_STR, Long.class);
80 | while (loopTimes-- >= 0) {
81 | Object result = redisTemplate.execute(redisScript, Lists.newArrayList(lockKey), requestId, String.valueOf(expireSecond));
82 | if (SUCCESS.equals(result)) {
83 | return true;
84 | }
85 | try {
86 | TimeUnit.MILLISECONDS.sleep(sleepInterval);
87 | } catch (InterruptedException e) {
88 | e.printStackTrace();
89 | }
90 | continue;
91 | }
92 | return false;
93 | }
94 |
95 |
96 | /**
97 | * 释放锁
98 | *
99 | * @return
100 | */
101 | public static boolean releaseDistributedLock() {
102 | String callerKey = getCurrentThreadCaller();
103 | String requestId = String.valueOf(Thread.currentThread().getId());
104 | return releaseDistributedLock(callerKey, requestId);
105 | }
106 |
107 | /**
108 | * 释放锁
109 | *
110 | * @param lockKey key
111 | * @param requestId 加锁的请求id
112 | * @return
113 | */
114 | public static boolean releaseDistributedLock(String lockKey, String requestId) {
115 | DefaultRedisScript redisScript = new DefaultRedisScript<>(UNLOCK_SCRIPT_STR, Long.class);
116 | Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId);
117 | if (SUCCESS.equals(result)) {
118 | return true;
119 | }
120 | return false;
121 | }
122 |
123 | private static String getSimpleClassName(String className) {
124 | String[] splits = className.split(PACKAGE_NAME_SPLIT_STR);
125 | return splits[splits.length - 1];
126 | }
127 |
128 | /**
129 | * Get caller
130 | *
131 | * @return
132 | */
133 | private static String getCurrentThreadCaller() {
134 | StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[3];
135 | return getSimpleClassName(stackTraceElement.getClassName()) + CLASS_AND_METHOD_CONCAT_STR + stackTraceElement.getMethodName();
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/distributedLock/Test.java:
--------------------------------------------------------------------------------
1 | import org.junit.Test;
2 | import org.junit.runner.RunWith;
3 | import org.springframework.boot.test.context.SpringBootTest;
4 | import org.springframework.test.context.junit4.SpringRunner;
5 |
6 | import java.util.Random;
7 | import java.util.UUID;
8 | import java.util.concurrent.CountDownLatch;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | @RunWith(SpringRunner.class)
12 | @SpringBootTest(classes = Application.class)
13 | public class ApplicationTests {
14 |
15 | @Test
16 | public void distributedLock() throws InterruptedException {
17 | CountDownLatch countDownLatch = new CountDownLatch(10);
18 |
19 | for (int i = 0; i < 10; i++) {
20 | Thread thread = new Thread(new Tester(), "Thread-" + i);
21 | countDownLatch.countDown();
22 | thread.start();
23 | }
24 |
25 | countDownLatch.await();
26 |
27 | System.out.println("down");
28 |
29 | Thread.sleep(Integer.MAX_VALUE);
30 | }
31 |
32 | class Tester implements Runnable {
33 |
34 | public static final int RANDOM_NUMBER_RANGE = 3;
35 |
36 | @Override
37 | public void run() {
38 | //获取锁, key:caller className&method value:Current Thread Id
39 | //也可以传参 key value 可选[expireSecond loopTimes sleepInterval]
40 | boolean result = RedisLockTool.tryGetDistributedLock();
41 | if (result) {
42 | System.out.println(Thread.currentThread().getName() + ": get lock");
43 | } else {
44 | System.err.println(Thread.currentThread().getName() + ": get lock timeout");
45 | }
46 |
47 | //if get the lock
48 | if (result) {
49 | try {
50 | TimeUnit.SECONDS.sleep(new Random().nextInt(RANDOM_NUMBER_RANGE));
51 | } catch (InterruptedException e) {
52 | e.printStackTrace();
53 | }
54 | RedisLockTool.releaseDistributedLock();
55 | System.out.println(Thread.currentThread().getName() + ": release lock");
56 | }
57 | }
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/redisTools/GeoRadiusDto.java:
--------------------------------------------------------------------------------
1 | /**
2 | * 地理位置相关dto
3 | */
4 | public class GeoRadiusDto {
5 |
6 | private String member;
7 |
8 | private Double x;
9 |
10 | private Double y;
11 |
12 | public String getMember() {
13 | return member;
14 | }
15 |
16 | public void setMember(String member) {
17 | this.member = member;
18 | }
19 |
20 | public Double getX() {
21 | return x;
22 | }
23 |
24 | public void setX(Double x) {
25 | this.x = x;
26 | }
27 |
28 | public Double getY() {
29 | return y;
30 | }
31 |
32 | public void setY(Double y) {
33 | this.y = y;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/redisTools/RedisCacheUtil.java:
--------------------------------------------------------------------------------
1 | import org.springframework.beans.factory.annotation.Autowired;
2 | import org.springframework.data.redis.core.*;
3 | import org.springframework.stereotype.Component;
4 |
5 | import java.util.*;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | /**
9 | * @author wenjie
10 | * @create 2017-06-15 19:09
11 | **/
12 | @Component
13 | public class RedisCacheUtil {
14 |
15 | @Autowired
16 | public RedisTemplate redisTemplate;
17 |
18 | /**
19 | * 缓存基本的对象,Integer、String、实体类等
20 | *
21 | * @param key 缓存的键值
22 | * @param value 缓存的值
23 | * @return 缓存的对象
24 | */
25 | public ValueOperations setCacheObject(String key, T value) {
26 | ValueOperations operation = redisTemplate.opsForValue();
27 | operation.set(key, value);
28 | return operation;
29 | }
30 |
31 | public ValueOperations setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) {
32 | ValueOperations operation = redisTemplate.opsForValue();
33 | operation.set(key, value, timeout, timeUnit);
34 | return operation;
35 | }
36 |
37 | /**
38 | * 获得缓存的基本对象。
39 | *
40 | * @param key 缓存键值
41 | * @return 缓存键值对应的数据
42 | */
43 | public T getCacheObject(String key) {
44 | ValueOperations operation = redisTemplate.opsForValue();
45 | return operation.get(key);
46 | }
47 |
48 | /**
49 | * 删除单个对象
50 | *
51 | * @param key
52 | */
53 | public void deleteObject(String key) {
54 | redisTemplate.delete(key);
55 | }
56 |
57 | /**
58 | * 删除集合对象
59 | *
60 | * @param collection
61 | */
62 | public void deleteObject(Collection collection) {
63 | redisTemplate.delete(collection);
64 | }
65 |
66 | /**
67 | * 缓存List数据
68 | *
69 | * @param key 缓存的键值
70 | * @param dataList 待缓存的List数据
71 | * @return 缓存的对象
72 | */
73 | public ListOperations setCacheList(String key, List dataList) {
74 | ListOperations listOperation = redisTemplate.opsForList();
75 | if (null != dataList) {
76 | int size = dataList.size();
77 | for (int i = 0; i < size; i++) {
78 | listOperation.leftPush(key, dataList.get(i));
79 | }
80 | }
81 | return listOperation;
82 | }
83 |
84 | /**
85 | * 获得缓存的list对象
86 | *
87 | * @param key 缓存的键值
88 | * @return 缓存键值对应的数据
89 | */
90 | public List getCacheList(String key) {
91 | List dataList = new ArrayList();
92 | ListOperations listOperation = redisTemplate.opsForList();
93 | Long size = listOperation.size(key);
94 |
95 | for (int i = 0; i < size; i++) {
96 | dataList.add(listOperation.index(key, i));
97 | }
98 | return dataList;
99 | }
100 |
101 | /**
102 | * 缓存Set
103 | *
104 | * @param key 缓存键值
105 | * @param dataSet 缓存的数据
106 | * @return 缓存数据的对象
107 | */
108 | public BoundSetOperations setCacheSet(String key, Set dataSet) {
109 | BoundSetOperations setOperation = redisTemplate.boundSetOps(key);
110 | Iterator it = dataSet.iterator();
111 | while (it.hasNext()) {
112 | setOperation.add(it.next());
113 | }
114 | return setOperation;
115 | }
116 |
117 | /**
118 | * 获得缓存的set
119 | *
120 | * @param key
121 | * @return
122 | */
123 | public Set getCacheSet(String key) {
124 | Set dataSet = new HashSet();
125 | BoundSetOperations operation = redisTemplate.boundSetOps(key);
126 | Long size = operation.size();
127 | for (int i = 0; i < size; i++) {
128 | dataSet.add(operation.pop());
129 | }
130 | return dataSet;
131 | }
132 |
133 | /**
134 | * 缓存Map
135 | *
136 | * @param key
137 | * @param dataMap
138 | * @return
139 | */
140 | public HashOperations setCacheMap(String key, Map dataMap) {
141 |
142 | HashOperations hashOperations = redisTemplate.opsForHash();
143 | if (null != dataMap) {
144 | for (Map.Entry entry : dataMap.entrySet()) {
145 | hashOperations.put(key, entry.getKey(), entry.getValue());
146 | }
147 | }
148 | return hashOperations;
149 | }
150 |
151 | /**
152 | * 获得缓存的Map
153 | *
154 | * @param key
155 | * @return
156 | */
157 | public Map getCacheMap(String key) {
158 | Map map = redisTemplate.opsForHash().entries(key);
159 | return map;
160 | }
161 |
162 |
163 | /**
164 | * 缓存Map
165 | *
166 | * @param key
167 | * @param dataMap
168 | * @return
169 | */
170 | public HashOperations setCacheIntegerMap(String key, Map dataMap) {
171 | HashOperations hashOperations = redisTemplate.opsForHash();
172 | if (null != dataMap) {
173 | for (Map.Entry entry : dataMap.entrySet()) {
174 | hashOperations.put(key, entry.getKey(), entry.getValue());
175 | }
176 | }
177 | return hashOperations;
178 | }
179 |
180 | /**
181 | * 获得缓存的Map
182 | *
183 | * @param key
184 | * @return
185 | */
186 | public Map getCacheIntegerMap(String key) {
187 | Map map = redisTemplate.opsForHash().entries(key);
188 | return map;
189 | }
190 |
191 |
192 | //=====================GEO地理位置相关=====================
193 |
194 | /**
195 | * 增加定位点
196 | *
197 | * @param x
198 | * @param y
199 | * @param member
200 | * @param time
201 | * @return
202 | */
203 | public boolean addGeo(double x, double y, String member, long time) {
204 | String key = GEO_KEY;
205 | try {
206 | GeoOperations geoOps = redisTemplate.opsForGeo();
207 | geoOps.add(key, new Point(x, y), member);
208 | if (time > 0) {
209 | redisTemplate.expire(key, time, TimeUnit.SECONDS);
210 | }
211 | } catch (Throwable t) {
212 | t.printStackTrace();
213 | log.error("缓存[" + key + "]" + "失败, point[" + x + "," +
214 | y + "], member[" + member + "]" + ", error[" + t + "]");
215 | }
216 | return true;
217 | }
218 |
219 |
220 | /**
221 | * 删除定位点
222 | *
223 | * @param members
224 | * @return
225 | */
226 | public boolean removeGeo(String... members) {
227 | try {
228 | GeoOperations geoOps = redisTemplate.opsForGeo();
229 | geoOps.remove(GEO_KEY, members);
230 | } catch (Throwable t) {
231 | log.error("移除[" + GEO_KEY + "]" + "失败" + ", error[" + t + "]");
232 | }
233 | return true;
234 | }
235 |
236 |
237 | /**
238 | * 计算定位距离
239 | *
240 | * @param member1
241 | * @param member2
242 | * @return
243 | */
244 | public Distance distanceGeo(String member1, String member2) {
245 | try {
246 | GeoOperations geoOps = redisTemplate.opsForGeo();
247 | return geoOps.geoDist(GEO_KEY, member1, member2);
248 | } catch (Throwable t) {
249 | log.error("计算距离[" + GEO_KEY + "]" + "失败, member[" + member1 + "," + member2 + "], error[" + t + "]");
250 | }
251 | return null;
252 | }
253 |
254 | /**
255 | * 获取坐标
256 | *
257 | * @param members
258 | * @return
259 | */
260 | public List getGeo(String... members) {
261 | try {
262 | GeoOperations geoOps = redisTemplate.opsForGeo();
263 | return geoOps.position(GEO_KEY, members);
264 | } catch (Throwable t) {
265 | log.error("获取坐标[" + GEO_KEY + "]" + "失败]" + ", error[" + t + "]");
266 | }
267 | return null;
268 | }
269 |
270 | /**
271 | * 基于某个坐标的附近的东西
272 | *
273 | * @param x
274 | * @param y
275 | * @param distance
276 | * @param direction
277 | */
278 | public List raduisGeo(double x, double y, double distance, Sort.Direction direction) {
279 | List radiusDtos = new ArrayList<>();
280 | try {
281 | GeoOperations geoOps = redisTemplate.opsForGeo();
282 |
283 | //设置geo查询参数
284 | RedisGeoCommands.GeoRadiusCommandArgs geoRadiusArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
285 | geoRadiusArgs = geoRadiusArgs.includeCoordinates().includeDistance();//查询返回结果包括距离和坐标
286 | if (Sort.Direction.ASC.equals(direction)) {//按查询出的坐标距离中心坐标的距离进行排序
287 | geoRadiusArgs.sortAscending();
288 | } else if (Sort.Direction.DESC.equals(direction)) {
289 | geoRadiusArgs.sortDescending();
290 | }
291 | GeoResults> geoResults = geoOps.radius(GEO_KEY, new Circle(new Point(x, y), new Distance(distance, RedisGeoCommands.DistanceUnit.METERS)), geoRadiusArgs);
292 |
293 | List>> geoResultList = geoResults.getContent();
294 | for (GeoResult> geoResult : geoResultList) {
295 | String name = geoResult.getContent().getName();
296 | Point point = geoResult.getContent().getPoint();
297 | GeoRadiusDto radiusDto = new GeoRadiusDto();
298 | radiusDto.setMember(name);
299 | radiusDto.setX(point.getX());
300 | radiusDto.setY(point.getY());
301 | radiusDtos.add(radiusDto);
302 | }
303 | } catch (Throwable t) {
304 |
305 | }
306 | return radiusDtos;
307 | }
308 |
309 |
310 | /**
311 | * 基于某个key的附近的东西
312 | *
313 | * @param member
314 | * @param distance
315 | * @param direction
316 | */
317 | public List raduisGeo(String member, double distance, Sort.Direction direction) {
318 | List radiusDtos = new ArrayList<>();
319 | try {
320 | GeoOperations geoOps = redisTemplate.opsForGeo();
321 |
322 | //设置geo查询参数
323 | RedisGeoCommands.GeoRadiusCommandArgs geoRadiusArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
324 | geoRadiusArgs = geoRadiusArgs.includeCoordinates().includeDistance();//查询返回结果包括距离和坐标
325 | if (Sort.Direction.ASC.equals(direction)) {//按查询出的坐标距离中心坐标的距离进行排序
326 | geoRadiusArgs.sortAscending();
327 | } else if (Sort.Direction.DESC.equals(direction)) {
328 | geoRadiusArgs.sortDescending();
329 | }
330 | GeoResults> geoResults = geoOps.radius(GEO_KEY, member, new Distance(distance, RedisGeoCommands.DistanceUnit.METERS), geoRadiusArgs);
331 |
332 | List>> geoResultList = geoResults.getContent();
333 | for (GeoResult> geoResult : geoResultList) {
334 | String name = geoResult.getContent().getName();
335 | //结果集排除自己
336 | if (!name.equals(member)) {
337 | Point point = geoResult.getContent().getPoint();
338 | GeoRadiusDto radiusDto = new GeoRadiusDto();
339 | radiusDto.setMember(name);
340 | radiusDto.setX(point.getX());
341 | radiusDto.setY(point.getY());
342 | radiusDtos.add(radiusDto);
343 | }
344 | }
345 | } catch (Throwable t) {
346 |
347 | }
348 | return radiusDtos;
349 | }
350 |
351 |
352 | }
353 |
--------------------------------------------------------------------------------