使用Redis实现附近的人的查询功能 - 例子记录
2022-08-30 本文已影响0人
右耳菌
1. 数据结构 - GEO
GEO 3.2版本开始对GEO(地理位置)的支持
使用场景:LBS应用开发
常用命令
-
GEOADD
增加地理位置的坐标,可以批量添加地理位置 -
GEODIST
获取两个地理位置的距离 -
GEOHASH
获取某个地理位置的geohash值 -
GEOPOS
获取指定位置的坐标,可以批量获取多个地理位置的坐标 -
GEORADIUS
根据给定地理位置坐标获取指定范围内的地理位置集合(注意:该命令的中心点由输入的经度和纬度决定) -
GEORADIUSBYMEMBER
根据给定成员的位置获取指定范围内的位置信息集合(注意:该命令的中心点是由给定的位置元素决定)
2. 例子
2.1 创建SpringBoot项目
- 修改 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 修改 application.properties
spring.redis.host=192.168.1.7
spring.redis.port=6379
2.2 创建AppConfig.java(spring配置类)
package cn.lazyfennec.redisnearbydemo.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/8/30 23:14
*/
@Configuration //
public class AppConfig {
@Value("${spring.redis.host}") // springel
private String host;
@Value("${spring.redis.port}")
int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(port);
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
redisConnectionFactory.afterPropertiesSet();
return redisConnectionFactory;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8); // key -- string
redisTemplate.setConnectionFactory(redisConnectionFactory); //
// redisTemplate.setValueSerializer();
// 必须执行这个函数,这个函数的作用是初始化参数和初识化工作
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
2.3 创建相关的service
- ILBSService
package cn.lazyfennec.redisnearbydemo.service;
import org.springframework.data.geo.Point;
public interface ILBSService {
void save(Point point, String userId);
Object near(Point point);
}
- LBSServiceImpl
package cn.lazyfennec.redisnearbydemo.service.impl;
import cn.lazyfennec.redisnearbydemo.service.ILBSService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/8/30 23:16
*/
@Service
public class LBSServiceImpl implements ILBSService {
private static final String GEO_KEY = "user_geo";
@Autowired
private RedisTemplate redisTemplate;
/**
* 上传位置
*/
public void save(Point point, String userId) {
redisTemplate.opsForGeo().add(GEO_KEY, new RedisGeoCommands.GeoLocation<>(userId, point));
}
/**
* 附近的人
*
* @param point 用户自己的位置
*/
public GeoResults<RedisGeoCommands.GeoLocation> near(Point point) {
// 半径 3000米
Distance distance = new Distance(3000, RedisGeoCommands.DistanceUnit.METERS);
Circle circle = new Circle(point, distance);
// 附近5个人 -- 业务需求
RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(5);
GeoResults<RedisGeoCommands.GeoLocation> geoResults = redisTemplate.opsForGeo().radius(GEO_KEY, circle, geoRadiusCommandArgs);
return geoResults;
}
}
2.4 创建LBSController
package cn.lazyfennec.redisnearbydemo.controller;
import cn.lazyfennec.redisnearbydemo.service.ILBSService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/8/30 23:14
*/
@RestController
public class LBSController {
@Autowired
ILBSService lbsService;
/**
* 上传位置
*
* @param userId 从登录信息获取。。此处示例作为参数
* @param latitude 纬度
* @param longitude 经度
*/
@RequestMapping("/geo/save")
public void save(String userId, String longitude, String latitude) {
Point point = new Point(Double.valueOf(longitude), Double.valueOf(latitude));
lbsService.save(point, userId);
}
@RequestMapping("/geo/near")
public Object near(String longitude, String latitude) {
Point point = new Point(Double.valueOf(longitude), Double.valueOf(latitude));
return lbsService.near(point);
}
}
2.5 创建 static/GEOTest.html
<!-- saved from url=(0022)http://127.0.0.1:8080/ -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>附近的人</title></head>
<body>
<script type="text/javascript">
// 1. 模拟保存用户位置
function save(userId, longitude, latitude) {
var ajax = new XMLHttpRequest();
ajax.open('get', '/geo/save?userId=' + userId + "&longitude=" + longitude + "&latitude=" + latitude);
ajax.send();
ajax.onreadystatechange = function () {
// 后台上报位置,无需任何返回
console.log(ajax.readyState + ">>>" + ajax.status);
}
}
// 2. 查询附近的人
function near(userId, longitude, latitude) {
var ajax = new XMLHttpRequest();
ajax.open('get', '/geo/near?userId=' + userId + "&longitude=" + longitude + "&latitude=" + latitude);
ajax.send();
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
var result = JSON.stringify(JSON.parse(ajax.responseText), null, 4); // 缩进4个空格 ;
var ta = document.getElementById('responseText');
ta.value = result;
}
}
}
</script>
<form onsubmit="return false;">
<h3>------经纬度:(120.197246,30.193334)-------</h3>
<input type="text" name="longitude" value="经度"/>
<input type="text" name="latitude" value="纬度"/>
<input type="text" name="userId" value="用户ID"/>
<input type="button" value="模拟用户"
onclick="save(this.form.userId.value,this.form.longitude.value, this.form.latitude.value)"/>
<input type="button" value="搜索附近的人"
onclick="near(this.form.userId.value,this.form.longitude.value, this.form.latitude.value)"/>
<h3>------3km 附近的人列表-------</h3>
<textarea id="responseText" style="width:500px;height:600px;"></textarea>
</form>
</body>
</html>