场景:当时我们项目用的是spring-data-jpa, 用hql实现的话,实在是不知道怎么搞,所以想出这么个方法。这样做的就是避免直接在数据查询语句中去计算该点附近多少公里范围内的点,将sql语句的实现转成了代码实现。
第一步:根据给定某点经纬度,给定距离数,计算出该点附近相应距离范围的所有的点
/**
* 查找附近的门店
* @param longitude 经度
* @param latitude 纬度
* @param distince 距离 (千米)
* @return List 符合距离范围的所有的点
* @Data 2018.10.26
*/
public List<PickStoreOfflineModel> findNearbyStore(BigDecimal longitude, BigDecimal latitude, Integer distince) {
String[] split = getNearbyByLongitudeAndLatitudeAndDistince(longitude, latitude, distince).split("-");
BigDecimal minlng = new BigDecimal(split[0]);
BigDecimal maxlng = new BigDecimal(split[1]);
BigDecimal minlat = new BigDecimal(split[2]);
BigDecimal maxlat = new BigDecimal(split[3]);
return pickStoreOfflineDao.findNearbyStore(minlng, maxlng, minlat, maxlat);
}
/**
*
* @Description 计算给定经纬度附近相应公里数的经纬度范围
* @param longitude 经度
* @param latitude 纬度
* @param distince 距离(千米)
* @return String 格式:经度最小值-经度最大值-纬度最小值-纬度最大值
* @Data 2018.10.26
**/
public static String getNearbyByLongitudeAndLatitudeAndDistince(BigDecimal longitude, BigDecimal latitude, Integer distince) {
double r = 6371.393; // 地球半径千米
double lng = longitude.doubleValue();
double lat = latitude.doubleValue();
double dlng = 2 * Math.asin(Math.sin(distince / (2 * r)) / Math.cos(lat * Math.PI / 180));
dlng = dlng * 180 / Math.PI;// 角度转为弧度
double dlat = distince / r;
dlat = dlat * 180 / Math.PI;
double minlat = lat - dlat;
double maxlat = lat + dlat;
double minlng = lng - dlng;
double maxlng = lng + dlng;
return minlng + "-" + maxlng + "-" + minlat + "-" + maxlat;
}
第二步:根据第一步查出来的所有点,依次取出其经纬度和给定地点的经纬度计算距离,并存储到实体类(该距离字段表中不存),只是起一个中间计算的作用。
最后利用Collectionss.sort()方法排序,根据距离排。
/**
* @Description 计算距离远近并按照距离排序
* @param longitude 经度
* @param latitude 纬度
* @param nearbyStoreList 附近门店
* @return 按照距离由近到远排序之后List
*/
public List<PickStoreOfflineDto> getNearbyStoreByDistinceAsc(BigDecimal longitude, BigDecimal latitude, List<PickStoreOfflineModel> nearbyStoreList) {
List<PickStoreOfflineDto> list = new ArrayList<>();
nearbyStoreList.forEach(pickStoreOfflineModel -> {
PickStoreOfflineDto pickStoreOfflineDto = new PickStoreOfflineDto();
BeanUtils.copyProperties(pickStoreOfflineModel, pickStoreOfflineDto);
Double distince = getDistince(longitude, latitude,
pickStoreOfflineModel.getLongitude(), pickStoreOfflineModel.getLatitude());
pickStoreOfflineDto.setDistince(distince.longValue());
list.add(pickStoreOfflineDto);
});
Collections.sort(list, Comparator.comparing(PickStoreOfflineDto::getDistince));
return list;
}
/**
* @Description 根据经纬度获取两点之间的距离
* @param longitude1 地点1经度
* @param latitude1 地点1纬度
* @param longitude2 地点2经度
* @param latitude2 地点2纬度
* @return 距离:单位 米
*/
public static Double getDistince(BigDecimal longitude1, BigDecimal latitude1, BigDecimal longitude2, BigDecimal latitude2) {
double r = 6371.393; // 地球半径千米
double lat1 = latitude1.doubleValue();
double lng1 = longitude1.doubleValue();
double lat2 = latitude2.doubleValue();
double lng2 = longitude2.doubleValue();
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 - radLat2;
double b = rad(lng1) - rad(lng2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
s = s * r;
s = Math.round(s * 1000);
return s;
}
private static Double rad(double d) {
return d * Math.PI / 180.0;
}
好了 就是这样子,反正我是实现了,老大也认可了。o(╥﹏╥)o
有用的到的小伙伴可以参考下,也可以留言交流下。