前言
简单记录一下使用Redis的GEO命令,SpringDataRedis提供了十分简单的地理位置定位的功能,实现查找附近用户的功能。
一、Redis的GEO命令之GEOADD、GEORADIUS命令
1.GEOADD 命令
(1)用法:GEOADD key [longitude][ latitude ][member]
(2)作用:用于存储地理位置信息,以便进行地理位置搜索和距离计算等操作。
(3)返回值:成功添加的成员数量。
(4)示例:
redis > GEOADD cities 116.4074 39.9042 Beijing
redis > GEOADD cities NX 121.4737 31.2304 Shanghai
(5)可选参数:
- NX:只在 key 不存在时才执行操作。
- XX:只在 key 存在时才执行操作。
- CH:修改成功的成员数量将被返回
2.GEORADIUS 命令
(1)用法:GEORADIUS key longitude latitude radius
(2)作用:用于查询指定地理位置附近的其他地理位置的命令。
(3)返回值:返回成员列表。
(4)示例:
redis > GEORADIUS User-Location 116.4074 39.9042 100 km
二、示例代码
1.控制层
(1)UserController.java
/**
* 更新用户位置信息
* {
* "longitude": 113.936099,
* "latitude": 22.542364
* }
*/
@PostMapping("updateUserLocation")
@ResponseBody
@CrossOrigin
public <T> T updateUserLocation(@RequestBody HashMap<String, Object> data) {
return userService.updateUserLocation(data);
}
/**
* 更新用户位置信息
* {
* "longitude": 113.936099,
* "latitude": 22.542364,
* "radius": 10
* }
*/
@PostMapping("nearby")
@ResponseBody
@CrossOrigin
public <T> T nearby(@RequestBody HashMap<String, Object> data) {
return userService.nearby(data);
}
2.接口层
(1)IUserService.java
<T> T updateUserLocation(HashMap<String, Object> data);
<T> T nearby(HashMap<String, Object> data);
3.实现层
(1)UserServiceImpl.java
@Override
public <T> T updateUserLocation(HashMap<String, Object> data) {
HashMap<String, Object> responseObj = new HashMap<>();
// 获取登录用户
UserDTO userDTO = RequestHolder.getUser();
// 获取经纬度
Double longitude = (Double) data.get("longitude"); // 经度
Double latitude = (Double) data.get("latitude"); // 维度
String USER_LOCATION_KEY = "User-Location";
String phone = userDTO.getPhone();
stringRedisTemplate.opsForGeo().add(USER_LOCATION_KEY, new Point(longitude, latitude), phone);
responseObj.put("code", 200);
responseObj.put("success", true);
responseObj.put("msg", "更新完成");
return (T) responseObj;
}
@Override
public <T> T nearby(HashMap<String, Object> data) {
HashMap<String, Object> responseObj = new HashMap<>();
// 获取登录用户
UserDTO userDTO = RequestHolder.getUser();
// 获取经纬度,以及半径
Double longitude = (Double) data.get("longitude"); // 经度
Double latitude = (Double) data.get("latitude"); // 维度
Integer radius = (Integer) data.get("radius"); // 半径
String USER_LOCATION_KEY = "User-Location";
String phone = userDTO.getPhone();
Distance distance = new Distance(radius, Metrics.KILOMETERS); // 距离,单位为千米
Circle circle = new Circle(new Point(longitude, latitude), distance); // 圆心
// 使用Redis的地理位置操作对象,在指定范围内查询附近的用户位置信息
GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = stringRedisTemplate.opsForGeo().radius(USER_LOCATION_KEY, circle);
List<Object> nearbyUsers = new ArrayList<>();
for (GeoResult<RedisGeoCommands.GeoLocation<String>> geoResult : geoResults.getContent()) {
Object memberId = geoResult.getContent().getName();
// 排除查询用户本身
if (!memberId.equals(phone)) {
nearbyUsers.add(memberId);
}
}
responseObj.put("code", 200);
responseObj.put("success", true);
responseObj.put("msg", "更新完成");
responseObj.put("data", nearbyUsers);
return (T) responseObj;
}