JAVA or MYSQL 获取附近 distance 千米的商户

目录

一、MYSQL - 推荐

二、JAVA


一、MYSQL - 推荐

entity

/**
 * 范围
 */
private double distance;

/**
 * 经度 - 数据库字段
 */
private double lng;

/**
 * 纬度 - 数据库字段
 */
private double lat;

controller 

public class Controller {

    /**
     * @Function: TODO
     * @description: 获取附近 distance 千米的店铺
     * @par: distance=2&lng=121.518563&lat=31.194161
     * @author: NingZe
     * @date: 2021/3/22 15:41
     * @params: [c] [distance 距离范围 单位km, lng 当前经度, lat 当前纬度]
     * @version: 02.06
     * @return: java.lang.String
     */
    @RequestMapping("findNearby")
    @ResponseBody
    public String findNearby(Merchant c) {
        return NzResultMap.build(d.findNearby(c));
    }

}

sql

# 计算[当前经纬度]与[指定经纬度]之间的距离,返回[x.xxx km]
CREATE FUNCTION `get_distance`(lng1 DOUBLE, lat1 DOUBLE, lng2 DOUBLE, lat2 DOUBLE) RETURNS double
BEGIN
	RETURN ROUND(6378.138 * 2 * 
					 ASIN(
						 SQRT(
							    POW(SIN((lat1 * PI() / 180 - lat2 * PI() / 180) / 2), 2) + 
							    COS(lat1 * PI() / 180) * 
							    COS(lat2 * PI() / 180) * 
							    POW(SIN((lng1 * PI() / 180 - lng2 * PI() / 180) / 2), 2)
							 )
						 ) * 1000
				) / 1000;
END;

# 查询 distance 范围内的店铺
SELECT 
 *, get_distance(${lng}, ${lat}, lng, lat) distance
FROM merchant
HAVING distance <= ${distance}
ORDER BY distance ASC;

二、JAVA

pom

<dependency>
    <groupId>com.spatial4j</groupId>
    <artifactId>spatial4j</artifactId>
    <version>0.5</version>
</dependency>

entity

/**
 * 范围
 */
private double distance;

/**
 * 经度 - 数据库字段
 */
private double lng;

/**
  * min 经度
  */
private double minlng;

/**
  * max 经度
  */
private double maxlng;

/**
 * 纬度 - 数据库字段
 */
private double lat;

/**
  * min 纬度
  */
private double minlat;

/**
  * max 纬度
  */
private double maxlat;

controller

import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Rectangle;
import java.util.List;
import java.util.stream.Collectors;

public class Controller {

   private SpatialContext spatialContext = SpatialContext.GEO;

    /**
     * @Function: TODO
     * @description: 获取附近 distance 千米的店铺
     * @par: distance=2&lng=121.518563&lat=31.194161
     * @author: NingZe
     * @date: 2021/3/22 15:41
     * @params: [c] [distance 距离范围 单位km, lng 当前经度, lat 当前纬度]
     * @version: 02.06
     * @return: java.lang.String
     */
    @RequestMapping("findNearby")
    @ResponseBody
    public String findNearby(Merchant c) {
        // 1.获取外接正方形
        Rectangle rectangle = getRectangle(c.getDistance(), c.getLng(), c.getLat());
        // 2.获取位置在正方形内的所有用户
        c.setMinlng(rectangle.getMinX());
        c.setMaxlng(rectangle.getMaxX());
        c.setMinlat(rectangle.getMinY());
        c.setMaxlat(rectangle.getMaxY());
        List<Map<String, Object>> nearbys = d.findNearby(c);
        // 3.保存距离 x km
        for (int i = 0; i < nearbys.size(); i++) {
            Map<String, Object> mi = nearbys.get(i);
            mi.put("distance", getDistance(parse(mi.get("lng")), parse(mi.get("lat")), c.getLng(), c.getLat()));
        }
        // 4.剔除半径超过指定距离的多余用户
        // nearbys = nearbys.stream().filter(a -> parse(a.get("distance")) <= c.getDistance()).collect(Collectors.toList());
        return NzResultMap.build(nearbys);
    }

    private Double parse(Object obj) {
        if (obj == null) {
            return 0.00;
        }
        return Double.parseDouble(String.valueOf(obj));
    }
    
    private Rectangle getRectangle(double distance, double lng, double lat) {
        return spatialContext.getDistCalc().calcBoxByDistFromPt(spatialContext.makePoint(lng, lat), distance * DistanceUtils.KM_TO_DEG, spatialContext, null);
    }

    private double getDistance(Double longitude, Double latitude, double userLng, double userLat) {
        return spatialContext.calcDistance(spatialContext.makePoint(userLng, userLat), spatialContext.makePoint(longitude, latitude)) * DistanceUtils.DEG_TO_KM;
    }

}

sql

SELECT 
 * 
FROM merchant
WHERE (lng BETWEEN ${minlng} AND ${maxlng}) AND (lat BETWEEN ${minlat} AND ${maxlat})

 

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值