欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot(五)Java基于MySQL实现附近的人

程序员文章站 2022-03-26 09:34:26
“附近的人”这个功能估计都不陌生,与之类似的功能最开始是在各大地图应用上接触过,比如搜附近的电影院,附近的超市等等。然而真正让附近的人火遍大江南北的应该是微信"附近的人"这个功能,记得微信刚出的时候,坊间还有一句"寂寞女聊玩微信,寂寞男人搜附近"的说法。 ......

“附近的人”这个功能估计都不陌生,与之类似的功能最开始是在各大地图应用上接触过,比如搜附近的电影院,附近的超市等等。然而真正让附近的人火遍大江南北的应该是微信"附近的人"这个功能,记得微信刚出的时候,坊间还有一句"寂寞女聊玩微信,寂寞男人搜附近"的说法。

v准备工作

创建测试数据库

create table `userposition` (
    `id` int(10) unsigned not null auto_increment,
    `city` varchar(20) not null,
    `position` varchar(128) not null,
    `longitude` decimal(18,15) not null,
    `latitude` decimal(18,15) not null,
    primary key (`id`)
)engine=innodb auto_increment=1 default charset=utf8;
insert into `userposition` values(1,'北京市','回龙观新村中区', 116.310771,40.06263);
insert into `userposition` values(2,'北京市','金域华府', 116.310127,40.064379);
insert into `userposition` values(3,'北京市','融泽嘉园中区', 116.311962,40.064822);
insert into `userposition` values(4,'北京市','回龙观新村东区', 116.312541,40.063246);
insert into `userposition` values(5,'北京市','上地东里', 116.314168,40.033075);

测试数据中的经度和纬度可以用或者提取。

v附近的人

原理

先算出某个坐标位置周围的矩形的四个点,然后使用经纬度去直接匹配数据库中的记录。

思路

首先算出“给定坐标附近1000米”这个范围的坐标范围。 虽然它是个圆,但我们可以先求出该圆的外接正方形,然后拿正方形的经纬度范围去搜索数据库。圆形内为要求的搜索范围,方形内为我们能间接得到的结果范围。

SpringBoot(五)Java基于MySQL实现附近的人

先来求东西两侧的的范围边界。在haversin公式中令φ1 = φ2,可得

SpringBoot(五)Java基于MySQL实现附近的人

java实现

/**
     * 查找附近的人
     * @param radii 半径距离(单位km)
     * @param lon 经度
     * @param lat 纬度
     * @return
     */
    @getmapping("/nearby")
    public list<userposition> getvicinity(double radii, double lon, double lat){
        double r = 6371;//地球半径千米
        double dis = radii;
        double dlng =  2*math.asin(math.sin(dis/(2*r))/math.cos(lat*math.pi/180));
        dlng = dlng*180/math.pi;//角度转为弧度
        double dlat = dis/r;
        dlat = dlat*180/math.pi;
        double minlat =lat-dlat;
        double maxlat = lat+dlat;
        double minlng = lon -dlng;
        double maxlng = lon + dlng;

        return userservice.getvicinity(bigdecimal.valueof(minlng), bigdecimal.valueof(maxlng), bigdecimal.valueof(minlat), bigdecimal.valueof(maxlat));
    }

mybatis

<select id="getvicinity" resultmap="baseresultmap">
    select
    <include refid="base_column_list" />
    from userposition
    where longitude &gt;= #{minlng} and longitude &lt;= #{maxlng} and latitude &gt;= #{minlat} and latitude &lt;= #{maxlat}
  </select>
list<userposition> getvicinity(@param("minlng") bigdecimal minlng,
                                  @param("maxlng") bigdecimal maxlng,
                                  @param("minlat") bigdecimal minlat,
                                  @param("maxlat") bigdecimal maxlat);

测试效果

在地图中找到回龙新村的经纬度,然后测试。

SpringBoot(五)Java基于MySQL实现附近的人

SpringBoot(五)Java基于MySQL实现附近的人

v按距离远近排序

java代码

 /**
     * 附近的人排序
     * @param lon 经度
     * @param lat 纬度
     * @return
     */
    @getmapping("/nearbysort")
    public list<userposition> getvicinitysort(double lon, double lat){

        return userservice.getvicinitysort(bigdecimal.valueof(lon), bigdecimal.valueof(lat));
    }

mybatis代码

<select id="getvicinitysort" resultmap="baseresultmap">
    select id, city, position, longitude,latitude,
        (power(mod(abs(longitude - #{longitude}),360),2) + power(abs(latitude - #{latitude}),2)) as distance
        from `userposition`
        order by distance limit 20
  </select>
list<userposition> getvicinitysort(@param("longitude") bigdecimal longitude,
                                   @param("latitude") bigdecimal latitude);

测试效果

SpringBoot(五)Java基于MySQL实现附近的人

补充,如果需要按距离排序,并返回距离的字段。可以按如下方式实现。

select
    *,
    round(
        6378.138 * 2 * asin(
            sqrt(
                pow(
                    sin(
                        (
                            $latitude * pi() / 180 - latitude * pi() / 180
                        ) / 2
                    ),
                    2
                ) + cos($latitude * pi() / 180) * cos(latitude * pi() / 180) * pow(
                    sin(
                        (
                            $longitude * pi() / 180 - longitude * pi() / 180
                        ) / 2
                    ),
                    2
                )
            )
        ) * 1000
    ) as distance
from
    userposition
order by
    distance asc

v博客总结

如果数据量大的话,还可以考虑基于redis实现附近的人。

其他参考资料:

  • 根据一个给定经纬度的点,进行附近500米地点查询–合理利用算法__算法
  • mysql 下 计算 两点 经纬度 之间的距离
  • mysql创建一个function用来计算经纬度距离


作  者:
出  处:
关于作者:专注于基础平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【】一下。您的鼓励是作者坚持原创和持续写作的最大动力!