• 【redis】SpringBoot整合+geo地理位置应用


    Jedis和lettuce区别:

    ·Jedis:

    直接连接的Redis Server,如果在多线程环境下是非线程安全的。每个线程都去拿自己的 Jedis 实例,当连接数量增多时,资源消耗阶梯式增大,连接成本就较高了。

    解决安全的问题,可以用线程池。

    ·lettuce:

    基于Netty的,Netty 是一个多线程、事件驱动的 I/O 框架。连接实例可以在多个线程间共享,当多线程使用同一连接实例时,是线程安全的。

    所以,一个多线程的应用可以使用同一个连接实例,而不用担心并发线程的数量。当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

    通过异步的方式可以让我们更好的利用系统资源,而不用浪费线程等待网络或磁盘I/O。所以 Lettuce 可以帮助我们充分利用异步的优势。

    整合步骤:

    1.pom

            
            
                org.springframework.boot
                spring-boot-starter-data-redis
            

    2.配置

    配置文件:

    1. server:
    2. port: 5555
    3. spring:
    4. redis:
    5. database: 1
    6. host: 127.0.0.1
    7. port: 6379
    8. # password: #用的本地的redis数据库 所以不用密码
    9. lettuce:
    10. pool:
    11. max-active: 8 #连接池最大连接数(使用负值表示没有限制)
    12. max-idle: 5 #连接池中的最大空闲连接
    13. min-idle: 0 #连接池中的最小空闲连接
    14. max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
    15. timeout: 10000ms #连接超时时间(毫秒)

    fbe13c5424723ee6338609af2537336f.png

    做成service或者util都可以

    RedisConfig:

    1. package com.example.redistest.util;
    2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
    3. import com.fasterxml.jackson.annotation.PropertyAccessor;
    4. import com.fasterxml.jackson.databind.ObjectMapper;
    5. import org.springframework.beans.factory.annotation.Value;
    6. import org.springframework.context.annotation.Bean;
    7. import org.springframework.context.annotation.Configuration;
    8. import org.springframework.data.redis.connection.RedisPassword;
    9. import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    10. import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    11. import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    12. import org.springframework.data.redis.core.RedisTemplate;
    13. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    14. import org.springframework.data.redis.serializer.StringRedisSerializer;
    15. /**
    16. * @Author lie
    17. * @Description
    18. */
    19. @Configuration
    20. public class RedisConfig {
    21. @Value("${spring.redis.database}")
    22. private int database;
    23. @Value("${spring.redis.host}")
    24. private String host;
    25. @Value("${spring.redis.port}")
    26. private int port;
    27. // @Value("${spring.redis.password}") //因为连接的是本地redis,没设置密码,所以不用
    28. // private String password;
    29. @Bean
    30. public LettuceConnectionFactory redisConnectionFactory() {
    31. RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    32. redisStandaloneConfiguration.setDatabase(database);
    33. redisStandaloneConfiguration.setHostName(host);
    34. redisStandaloneConfiguration.setPort(port);
    35. // redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
    36. LettuceClientConfiguration.LettuceClientConfigurationBuilder lettuceClientConfigurationBuilder = LettuceClientConfiguration.builder();
    37. LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration,
    38. lettuceClientConfigurationBuilder.build());
    39. return lettuceConnectionFactory;
    40. }
    41. @Bean
    42. public RedisTemplate redisTemplate() {
    43. RedisTemplate redisTemplate = new RedisTemplate<>();
    44. redisTemplate.setConnectionFactory(redisConnectionFactory());
    45. //---------转换json--start-------//
    46. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    47. ObjectMapper om = new ObjectMapper();
    48. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    49. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    50. jackson2JsonRedisSerializer.setObjectMapper(om);
    51. //--------转换json--end-----//
    52. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    53. redisTemplate.setKeySerializer(stringRedisSerializer);
    54. redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    55. redisTemplate.setHashKeySerializer(stringRedisSerializer);
    56. redisTemplate.setHashValueSerializer(stringRedisSerializer);
    57. redisTemplate.afterPropertiesSet();
    58. return redisTemplate;
    59. }
    60. }

    RedisTemplate:(基本类型+geo)

    1. package com.example.redistest.service.impl;
    2. import com.example.redistest.service.RedisService;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.data.redis.core.RedisTemplate;
    5. import org.springframework.data.redis.core.ZSetOperations;
    6. import org.springframework.stereotype.Service;
    7. import java.util.List;
    8. import java.util.Map;
    9. import java.util.Set;
    10. import java.util.concurrent.TimeUnit;
    11. /**
    12. * redis操作实现类
    13. */
    14. @Service
    15. public class RedisServiceImpl implements RedisService {
    16. @Autowired
    17. private RedisTemplate redisTemplate;
    18. @Override
    19. public void set(String key, Object value, long time) {
    20. redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
    21. }
    22. @Override
    23. public void set(String key, Object value) {
    24. redisTemplate.opsForValue().set(key, value);
    25. }
    26. @Override
    27. public Object get(String key) {
    28. return redisTemplate.opsForValue().get(key);
    29. }
    30. @Override
    31. public Boolean del(String key) {
    32. return redisTemplate.delete(key);
    33. }
    34. @Override
    35. public Long del(List keys) {
    36. return redisTemplate.delete(keys);
    37. }
    38. @Override
    39. public Boolean expire(String key, long time) {
    40. return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    41. }
    42. @Override
    43. public Long getExpire(String key) {
    44. return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    45. }
    46. @Override
    47. public Boolean hasKey(String key) {
    48. return redisTemplate.hasKey(key);
    49. }
    50. @Override
    51. public Long incr(String key, long delta) {
    52. return redisTemplate.opsForValue().increment(key, delta);
    53. }
    54. @Override
    55. public Long decr(String key, long delta) {
    56. return redisTemplate.opsForValue().increment(key, -delta);
    57. }
    58. @Override
    59. public Object hGet(String key, String hashKey) {
    60. return redisTemplate.opsForHash().get(key, hashKey);
    61. }
    62. @Override
    63. public Boolean hSet(String key, String hashKey, Object value, long time) {
    64. redisTemplate.opsForHash().put(key, hashKey, value);
    65. return expire(key, time);
    66. }
    67. @Override
    68. public void hSet(String key, String hashKey, Object value) {
    69. redisTemplate.opsForHash().put(key, hashKey, value);
    70. }
    71. @Override
    72. public Map hGetAll(String key) {
    73. return redisTemplate.opsForHash().entries(key);
    74. }
    75. @Override
    76. public List hVals(String key) {
    77. return redisTemplate.opsForHash().values(key);
    78. }
    79. @Override
    80. public Boolean hSetAll(String key, Map map, long time) {
    81. redisTemplate.opsForHash().putAll(key, map);
    82. return expire(key, time);
    83. }
    84. @Override
    85. public void hSetAll(String key, Map map) {
    86. redisTemplate.opsForHash().putAll(key, map);
    87. }
    88. @Override
    89. public void hDel(String key, Object... hashKey) {
    90. redisTemplate.opsForHash().delete(key, hashKey);
    91. }
    92. @Override
    93. public Boolean hHasKey(String key, String hashKey) {
    94. return redisTemplate.opsForHash().hasKey(key, hashKey);
    95. }
    96. @Override
    97. public Long hIncr(String key, String hashKey, Long delta) {
    98. return redisTemplate.opsForHash().increment(key, hashKey, delta);
    99. }
    100. @Override
    101. public Long hDecr(String key, String hashKey, Long delta) {
    102. return redisTemplate.opsForHash().increment(key, hashKey, -delta);
    103. }
    104. @Override
    105. public Set sMembers(String key) {
    106. return redisTemplate.opsForSet().members(key);
    107. }
    108. // @Override
    109. // public Long sAdd(String key, Object... values) {
    110. // return redisTemplate.opsForSet().add(key, values);
    111. // }
    112. @Override
    113. public Long sAdd(String key, long time, Object... values) {
    114. Long count = redisTemplate.opsForSet().add(key, values);
    115. expire(key, time);
    116. return count;
    117. }
    118. @Override
    119. public Boolean sIsMember(String key, Object value) {
    120. return redisTemplate.opsForSet().isMember(key, value);
    121. }
    122. @Override
    123. public Long sSize(String key) {
    124. return redisTemplate.opsForSet().size(key);
    125. }
    126. @Override
    127. public Long sRemove(String key, Object... values) {
    128. return redisTemplate.opsForSet().remove(key, values);
    129. }
    130. @Override
    131. public List lRange(String key, long start, long end) {
    132. return redisTemplate.opsForList().range(key, start, end);
    133. }
    134. @Override
    135. public Long lSize(String key) {
    136. return redisTemplate.opsForList().size(key);
    137. }
    138. @Override
    139. public Object lIndex(String key, long index) {
    140. return redisTemplate.opsForList().index(key, index);
    141. }
    142. @Override
    143. public Long lPush(String key, Object value) {
    144. return redisTemplate.opsForList().rightPush(key, value);
    145. }
    146. @Override
    147. public Long lPush(String key, Object value, long time) {
    148. Long index = redisTemplate.opsForList().rightPush(key, value);
    149. expire(key, time);
    150. return index;
    151. }
    152. @Override
    153. public Long lPushAll(String key, Object... values) {
    154. return redisTemplate.opsForList().rightPushAll(key, values);
    155. }
    156. @Override
    157. public Long lPushAll(String key, Long time, Object... values) {
    158. Long count = redisTemplate.opsForList().rightPushAll(key, values);
    159. expire(key, time);
    160. return count;
    161. }
    162. @Override
    163. public Long lRemove(String key, long count, Object value) {
    164. return redisTemplate.opsForList().remove(key, count, value);
    165. }
    166. @Override
    167. public Set keys() {
    168. return this.redisTemplate.keys("*");
    169. }
    170. /**
    171. * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能; zadd
    172. *
    173. * @param key
    174. * @param value
    175. * @param score
    176. */
    177. @Override
    178. public void zadd(String key, Object value, double score) {
    179. redisTemplate.opsForZSet().add(key, value, score);
    180. }
    181. /**
    182. * 删除元素 zrem
    183. * @param key
    184. * @param value
    185. */
    186. @Override
    187. public void zdel(String key, Object value) {
    188. redisTemplate.opsForZSet().remove(key, value);
    189. }
    190. /**
    191. * score的增加or减少 zincrby
    192. * @param key
    193. * @param value
    194. * @param score
    195. */
    196. @Override
    197. public Double incrScore(String key, Object value, double score) {
    198. return redisTemplate.opsForZSet().incrementScore(key, value, score);
    199. }
    200. /**
    201. * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容
    202. * @param key
    203. * @param start
    204. * @param end
    205. * @return
    206. */
    207. @Override
    208. public Set> rangeWithScore(String key, long start, long end) {
    209. return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    210. }
    211. /**
    212. * 获取对象个数
    213. * @param key
    214. * @return
    215. */
    216. @Override
    217. public Object hLen(String key) {
    218. return redisTemplate.opsForHash().size(key);
    219. }
    220. }
      1. package com.example.redistest.util;
      2. import org.springframework.beans.factory.annotation.Autowired;
      3. import org.springframework.data.geo.GeoResult;
      4. import org.springframework.data.geo.Metrics;
      5. import org.springframework.data.geo.Point;
      6. import org.springframework.data.geo.Circle;
      7. import org.springframework.data.geo.Distance;
      8. import org.springframework.data.geo.GeoResults;
      9. import org.springframework.data.redis.connection.RedisGeoCommands;
      10. import org.springframework.data.redis.core.RedisTemplate;
      11. import org.springframework.stereotype.Component;
      12. import java.util.List;
      13. /**
      14. * @Author lie
      15. * @Description
      16. */
      17. @Component
      18. public class GeoHashUtil {
      19. @Autowired(required = false)
      20. private RedisTemplate redisTemplate;
      21. /**
      22. * 添加节点及位置信息
      23. * @param geoKey 位置集合
      24. * @param pointName 位置点标识
      25. * @param longitude 经度
      26. * @param latitude 纬度
      27. */
      28. public Long geoAdd(String geoKey, double longitude, double latitude, String pointName){
      29. Point point = new Point(longitude, latitude);
      30. return redisTemplate.opsForGeo().add(geoKey, point, pointName);
      31. }
      32. /**
      33. * 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素,并给出所有位置元素与中心的平均距离
      34. * @param geoKey key
      35. * @param longitude 经度
      36. * @param latitude 维度
      37. * @param radius 距离
      38. * @param metricUnit 距离单位,例如 Metrics.KILOMETERS
      39. * @param limit 人数
      40. */
      41. public List>> findRadius(String geoKey
      42. , double longitude, double latitude, double radius, Metrics metricUnit, int limit){
      43. // 设置检索范围
      44. Point point = new Point(longitude, latitude);
      45. Circle circle = new Circle(point, new Distance(radius, metricUnit));
      46. // 定义返回结果参数,如果不指定默认只返回content即保存的member信息
      47. RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
      48. .newGeoRadiusArgs().includeDistance().includeCoordinates()
      49. .sortAscending()
      50. .limit(limit);
      51. GeoResults> results = redisTemplate.opsForGeo().radius(geoKey, circle, args);
      52. List>> list = results.getContent();
      53. return list;
      54. }
      55. /**
      56. * 计算指定key下两个成员点之间的距离
      57. * @param geoKey key
      58. * @param member1 位置1
      59. * @param member2 位置2
      60. * @param unit 单位
      61. */
      62. public Distance calDistance(String geoKey, String member1, String member2
      63. , RedisGeoCommands.DistanceUnit unit){
      64. Distance distance = redisTemplate.opsForGeo()
      65. .distance(geoKey, member1, member2, unit);
      66. return distance;
      67. }
      68. /**
      69. * 根据成员点名称查询位置信息
      70. * @param geoKey geo key
      71. * @param members 名称数组
      72. */
      73. public List geoPosition(String geoKey, String[] members){
      74. List points = redisTemplate.opsForGeo().position(geoKey, members);
      75. return points;
      76. }
      77. /**
      78. * 以给定的城市为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素,并给出所有位置元素与中心的平均距离。
      79. * @param key redis的key
      80. * @param name 名称
      81. * @param distance 距离
      82. * @param count 人数
      83. */
      84. public GeoResults> geoNearByPlace(String key, String name, Integer distance, Integer count) {
      85. //params: 距离量, 距离单位
      86. Distance distances = new Distance(distance, Metrics.KILOMETERS);
      87. RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(count);
      88. //params: key, 地方名称, Circle, GeoRadiusCommandArgs
      89. GeoResults> results = redisTemplate.opsForGeo().radius(key, name, distances, args);
      90. return results;
      91. }
      92. /**
      93. * 返回一个或多个位置元素的 Geohash 表示
      94. * @param key redis的key
      95. * @param members 名称的数组
      96. */
      97. public List geoHash(String key, String[] members) {
      98. //params: key, 地方名称...
      99. List results = redisTemplate.opsForGeo().hash(key, members);
      100. return results;
      101. }
      102. }

      3.引入工具类或者service调用方法使用即可(下面做的例子)

      impl:

      1. package com.example.redistest.test.service.impl;
      2. import com.example.redistest.service.RedisService;
      3. import com.example.redistest.test.service.StockService;
      4. import com.example.redistest.util.GeoHashUtil;
      5. import lombok.extern.slf4j.Slf4j;
      6. import org.springframework.beans.factory.annotation.Autowired;
      7. import org.springframework.data.geo.GeoResults;
      8. import org.springframework.data.geo.Point;
      9. import org.springframework.data.redis.connection.RedisGeoCommands;
      10. import org.springframework.stereotype.Service;
      11. import java.util.List;
      12. /**
      13. * @Author lie
      14. * @Description
      15. */
      16. @Service
      17. @Slf4j
      18. public class StockServiceImpl implements StockService {
      19. @Autowired(required = false)
      20. private RedisService redisService;
      21. @Autowired
      22. private GeoHashUtil geoHashUtil;
      23. /**
      24. * 加库存
      25. * @param stockNum
      26. * @return
      27. */
      28. @Override
      29. public String addStock(Integer stockNum) {
      30. Long decr = redisService.incr("stock:37", stockNum);
      31. log.info(String.valueOf(decr));
      32. return redisService.get("stock:37").toString();
      33. }
      34. /**
      35. * 减库存
      36. * @param stockNum
      37. * @return
      38. */
      39. @Override
      40. public String subtractStock(Integer stockNum) {
      41. Long decr = redisService.decr("stock:37", stockNum);
      42. log.info(String.valueOf(decr));
      43. return redisService.get("stock:37").toString();
      44. }
      45. /**
      46. * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
      47. * @param key redis的key
      48. * @param longitude 经度
      49. * @param latitude 纬度
      50. * @param name 名称
      51. */
      52. @Override
      53. public Long addGeo(String key, double longitude, double latitude, String name) {
      54. return geoHashUtil.geoAdd(key,longitude,latitude,name);
      55. }
      56. /**
      57. * 从key里返回所有给定位置元素的位置(经度和纬度)。
      58. * @param key redis的key
      59. * @param nameList geo位置成员的名字,可以是多个,用逗号分割
      60. */
      61. @Override
      62. public List queryGeo(String key, String nameList) {
      63. String[] split = nameList.split(",");
      64. // List cityNames = new ArrayList<>(Arrays.asList(split));
      65. List points = geoHashUtil.geoPosition(key, split);
      66. return points;
      67. }
      68. /**
      69. * 以给定的城市为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素,并给出所有位置元素与中心的平均距离。
      70. * @param key key
      71. * @param pointName 中心地点名
      72. * @param distance 距离
      73. * @param count 数量
      74. */
      75. @Override
      76. public GeoResults> locationInfo(String key,String pointName, Integer distance, Integer count) {
      77. GeoResults> geoResults = geoHashUtil.geoNearByPlace(key, pointName, distance, count);
      78. return geoResults;
      79. }
      80. }

      controller:

      1. package com.example.redistest.test.controller;
      2. import com.example.redistest.test.service.StockService;
      3. import org.springframework.beans.factory.annotation.Autowired;
      4. import org.springframework.data.geo.GeoResults;
      5. import org.springframework.data.geo.Point;
      6. import org.springframework.data.redis.connection.RedisGeoCommands;
      7. import org.springframework.web.bind.annotation.GetMapping;
      8. import org.springframework.web.bind.annotation.RequestMapping;
      9. import org.springframework.web.bind.annotation.RestController;
      10. import java.util.List;
      11. /**
      12. * @Author lie
      13. * @Description 测试redis
      14. */
      15. @RestController
      16. @RequestMapping("RedisTestController")
      17. public class RedisTestController {
      18. @Autowired
      19. private StockService stockService;
      20. /**
      21. * 增加库存
      22. * @param stockNum
      23. * @return 增加后的库存
      24. */
      25. @GetMapping("addStock")
      26. public String addStock(Integer stockNum){
      27. return stockService.addStock(stockNum);
      28. }
      29. /**
      30. * 减少库存
      31. * @param stockNum
      32. * @return 增加后的库存
      33. */
      34. @GetMapping("subtractStock")
      35. public String subtractStock(Integer stockNum){
      36. return stockService.subtractStock(stockNum);
      37. }
      38. /**
      39. * 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。
      40. * @param key redis的key
      41. * @param longitude 经度
      42. * @param latitude 纬度
      43. * @param name 名称
      44. */
      45. @GetMapping("addGeo")
      46. public Long addGeo(String key, double longitude, double latitude, String name){
      47. return stockService.addGeo(key,longitude,latitude,name);
      48. }
      49. /**
      50. * 从key里返回所有给定位置元素的位置(经度和纬度)。
      51. * @param key redis的key
      52. * @param nameList geo位置成员的名字,可以是多个,用逗号分割
      53. */
      54. @GetMapping("queryGeo")
      55. public List queryGeo(String key, String nameList){
      56. return stockService.queryGeo(key,nameList);
      57. }
      58. /**
      59. * 以给定的城市为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素,并给出所有位置元素与中心的平均距离。
      60. * @param key key
      61. * @param pointName 中心地点名
      62. * @param distance 距离
      63. * @param count 数量
      64. */
      65. @GetMapping("locationInfo")
      66. public GeoResults> locationInfo(String key, String pointName, Integer distance, Integer count){
      67. return stockService.locationInfo(key,pointName,distance,count);
      68. }
      69. }

      启动服务,看结果:

      ·库存增加1000(查看redis结果一致)

      ·库存减少200(查看redis结果一致)

      ·添加位置北京、上海、广州(查看redis结果一致)

      ·查看经纬度(多个地点)

      ·查看已北京为中心10000km以内的3个最近的地点,同时返回距离、经纬度、地点名称

    221. 相关阅读:
      基于微信小程序的高校就业招聘系统设计与实现(源码+lw+部署文档+讲解等)
      基于CefSharp和XPath的C#爬虫
      【Golang开发面经】B站(两轮技术面)
      Java入门第113课——使用Iterator的remove方法移除元素
      神经网络基础
      从零开始的力扣刷题记录-第八十八天
      what is gopls
      golang 工程组件:grpc-gateway 环境安装+默认网关测试
      InnoDB主键和二级索引树、回表
      【R语言与统计】SEM结构方程、生物群落、多元统计分析、回归及混合效应模型、贝叶斯、极值统计学、meta分析、copula、分位数回归、文献计量学
    222. 原文地址:https://blog.csdn.net/Mouth_OF_Lie/article/details/126604762