zoukankan      html  css  js  c++  java
  • SpringBoot入门教程(五)Java基于MySQL实现附近的人

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

    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实现附近的人。Redis GEO地理位置信息,查看附近的人

    v源码地址

    https://github.com/toutouge/javademosecond/tree/master/hellospringboot

    其他参考资料:


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

  • 相关阅读:
    mysql 查询当月天数
    mybatis <collection>标签 类型为string时无法获取重复数据错误
    eclipse 关闭validating
    YAGNI 声明
    tomcat 异常
    svn 用cmd命令行启动服务
    linux 命令
    windows10安装liux系统
    一带一路是个啥?
    串口通信协议
  • 原文地址:https://www.cnblogs.com/toutou/p/9771386.html
Copyright © 2011-2022 走看看