1. 程式人生 > >SpringBoot整合redis的LBS功能

SpringBoot整合redis的LBS功能

下面的程式碼實現了新增經緯度資料 和 搜尋經緯度資料的功能:

import java.util.List;

import com.longge.goods.dto.BuildingDto;
import com.longge.goods.dto.BuildingLbsDto;

/**
 * LBS相關的服務
 * @author yangzhilong
 *
 */
public interface LbsService {
    /**
     * 新增或者修改樓宇的經緯度
     * @param buildDto
     */
    void saveBuildingLonAndLat(BuildingDto buildDto);
    
    
/** * 查詢指定經緯度附近的樓宇 * @param lon 經度 * @param lat 緯度 * @param limit 記錄數 * @return */ List<BuildingLbsDto> listNearbyBuilding(double lon, double lat, int limit); }

 

  1 import java.util.ArrayList;
  2 import java.util.HashMap;
  3 import java.util.List;
4 import java.util.Map; 5 6 import javax.annotation.Resource; 7 8 import org.apache.commons.lang3.StringUtils; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.beans.factory.annotation.Value; 11 import org.springframework.data.geo.Circle;
12 import org.springframework.data.geo.Distance; 13 import org.springframework.data.geo.GeoResults; 14 import org.springframework.data.geo.Metrics; 15 import org.springframework.data.geo.Point; 16 import org.springframework.data.redis.connection.RedisGeoCommands; 17 import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; 18 import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; 19 import org.springframework.data.redis.core.GeoOperations; 20 import org.springframework.data.redis.core.StringRedisTemplate; 21 import org.springframework.stereotype.Service; 22 import org.springframework.util.CollectionUtils; 23 24 import com.alibaba.fastjson.JSONObject; 25 import com.longge.core.util.BeanMapper; 26 import com.longge.goods.api.BuildingService; 27 import com.longge.goods.api.LbsService; 28 import com.longge.goods.constants.BuildingConstant; 29 import com.longge.goods.dto.BuildingDto; 30 import com.longge.goods.dto.BuildingLbsDto; 31 import com.longge.goods.util.GoodsRedisKeyUtils; 32 33 import lombok.extern.slf4j.Slf4j; 34 35 @Service 36 @Slf4j 37 public class LbsServiceImpl implements LbsService { 38 @Autowired 39 private BuildingService buildingService; 40 // 搜尋範圍 41 @Value("${lbs.distance:3}") 42 private Double lbsDistance; 43 @Resource 44 private StringRedisTemplate redisTemplate; 45 46 @Override 47 public void saveBuildingLonAndLat(BuildingDto buildDto) { 48 log.info("開始處理樓宇的經緯度資料,樓宇:{}", JSONObject.toJSONString(buildDto)); 49 GeoOperations<String, String> ops = redisTemplate.opsForGeo(); 50 String member = String.valueOf(buildDto.getId()); 51 // 查詢樓宇的geo資料是否存在 52 List<String> list = ops.hash(GoodsRedisKeyUtils.getBuildingLbsKey(), member); 53 if (!CollectionUtils.isEmpty(list)) { 54 log.info("該樓宇資料存在,先進行刪除操作"); 55 // 存在,先刪除,後新增 56 ops.remove(GoodsRedisKeyUtils.getBuildingLbsKey(), member); 57 } 58 ops.add(GoodsRedisKeyUtils.getBuildingLbsKey(), 59 new RedisGeoCommands.GeoLocation<String>(member, new Point(buildDto.getLon(), buildDto.getLat()))); 60 log.info("樓宇經緯度資訊處理完成"); 61 } 62 63 @Override 64 public List<BuildingLbsDto> listNearbyBuilding(double lon, double lat, int limit) { 65 log.info("查詢LBS樓宇資訊,經度:{},緯度:{},條數:{}", lon, lat, limit); 66 GeoOperations<String, String> ops = redisTemplate.opsForGeo(); 67 68 // 獲取redis裡全域性的配置,實現引數動態化 69 String redisLbsDistance = (String)RedisCache.hGet("config:global", "lbsDistance"); 70 if(StringUtils.isNotBlank(redisLbsDistance)) { 71 lbsDistance = Double.valueOf(redisLbsDistance); 72 } 73 74 Point center = new Point(lon, lat); 75 Distance radius = new Distance(lbsDistance, Metrics.KILOMETERS); 76 Circle within = new Circle(center, radius); 77 // order by 距離 limit 20 ,同時返回距離中心點的距離 78 GeoRadiusCommandArgs args = GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(limit).sortAscending(); 79 80 GeoResults<GeoLocation<String>> result = ops.radius(GoodsRedisKeyUtils.getBuildingLbsKey(), within, args); 81 log.info("查詢redis後的經緯度資料:{}", JSONObject.toJSONString(result)); 82 if(null != result) { 83 Map<Long, Double> data = new HashMap<>(); 84 List<Long> buildings = new ArrayList<>(); 85 86 result.forEach(item -> { 87 data.put(Long.valueOf(item.getContent().getName()), item.getDistance().getValue()); 88 buildings.add(Long.valueOf(item.getContent().getName())); 89 }); 90 if(!CollectionUtils.isEmpty(buildings)) { 91 List<BuildingDto> buildingList = buildingService.getBuildList(buildings); 92 if(!CollectionUtils.isEmpty(buildingList)) { 93 List<BuildingLbsDto> resp = new ArrayList<>(); 94 buildingList.stream().forEach(item -> { 95 BuildingLbsDto dto = BeanMapper.map(item, BuildingLbsDto.class); 96 if(BuildingConstant.BuildingStatusEnum.OPENED.getValue() == dto.getStatus()) { 97 dto.setDistance(data.get(item.getId())); 98 resp.add(dto); 99 } 100 }); 101 log.info("查詢LBS樓宇資訊的結果:{}", JSONObject.toJSONString(resp)); 102 return resp; 103 } 104 } 105 } 106 log.warn("未查詢LBS樓宇資訊"); 107 return null; 108 } 109 }
import java.util.Date;

/**
 * 樓宇資訊dto
 *
 */
@Data
public class BuildingDto {
    private Long id;

    private Short status;
    /**
     * 緯度
     */
    private Double lat;
    /**
     * 經度
     */
    private Double lon;
}
import java.io.Serializable;

import lombok.Getter;
import lombok.Setter;

/**
 * 包含距離定位點距離的樓宇dto
 * @author yangzhilong
 *
 */
@Getter
@Setter
public class BuildingLbsDto extends BuildingDto implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 3224249189169148012L;
    // 距離,單位:千米
    private Double distance;
}