简介
业务中常有需求是计算经纬度之间的距离,redis
是使用较多的缓存中间件,正好有关于geo
位置计算的api
,可以直接拿来用.
redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
redis:
host: xxx.xxx.xxx.xxx
port: 36379
password: xxx
database: 0
jedis:
pool:
max-idle: 10
max-wait: 3000
max-active: 50
min-idle: 5
timeout: 30000
demo展示
直接上demo代码
package com.felix.spring_cloud_one.service;
import com.felix.spring_cloud_one.params.SaveGeoPointVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
public class RedisGeoService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
public Object saveGeoPoint(List<SaveGeoPointVO> vos) {
String city = vos.get(0).getCity();
Map<String, Point> map;
map = vos.stream().collect(Collectors.toMap(SaveGeoPointVO::getName, it -> new Point(it.getLgt(), it.getLat())));
Long add = stringRedisTemplate.opsForGeo().add(city, map);
return add;
}
public Object getGeoPoint(SaveGeoPointVO vo) {
List<Point> position = getGeoPoint(vo.getCity(), vo.getName());
return position;
}
/**
* [
* {
* "x": 120.11999756097794,
* "y": 41.079998971862615
* }
* ]
* @param city
* @param members
* @return
*/
//查找指定key的经纬度信息,可以指定多个member,批量返回
private List<Point> getGeoPoint(String city, String ... members) {
List<Point> position = stringRedisTemplate.opsForGeo()
.position(
city,
members
);
return position;
}
/**
* {
* "value": 925.2986,
* "metric": "KILOMETERS"
* }
*/
//获取一个key下的2个位置点的距离
public Distance getDistance(String city, String members1, String members2, Metric metric){
if(Objects.isNull(metric)){
metric = Metrics.KILOMETERS;
}
Distance distance = stringRedisTemplate.opsForGeo().distance(city, members1, members2, metric);
return distance;
}
//redis命令:georadius key 116.405285 39.904989 100 km WITHDIST WITHCOORD ASC
//根据给定的经纬度返回半径范围内不超过指定距离的元素
public Object nearByXY(String city, Circle circle, long count){
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
//包含距离
.includeDistance()
//包含经纬度
.includeCoordinates()
//升序
.sortAscending()
.limit(count);
GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(city, circle, args);
return radius;
}
/**
* {
* "averageDistance": {
* "value": 193.9615,
* "metric": "KILOMETERS"
* },
* "content": [
* {
* "content": {
* "name": "2",
* "point": {
* "x": 120.11999756097794,
* "y": 41.079998971862615
* }
* },
* "distance": {
* "value": 120.5517,
* "metric": "KILOMETERS"
* }
* },
* {
* "content": {
* "name": "3",
* "point": {
* "x": 117.12000042200089,
* "y": 39.080000053576654
* }
* },
* "distance": {
* "value": 267.3713,
* "metric": "KILOMETERS"
* }
* }
* ]
* }
*/
public Object nearByXY(String city, Double lng, Double lat, double distanceNum, long count){
Point point = new Point(lng, lat);
Distance distance = new Distance(distanceNum, Metrics.KILOMETERS);
Circle circle = new Circle(point, distance);
Object result = nearByXY(city, circle, count);
return result;
}
//删除
//GEO数据本质上是放到一个zset集合里了
//删除可以用 ZREM key member
public Boolean deleteByMembers(String city, String... members){
Long remove = stringRedisTemplate.opsForGeo().remove(city, members);
return remove.intValue() == members.length;
}
}