SpringBoot入門教程(五)Java基於MySQL實現附近的人

「附近的人」這個功能估計都不陌生,與之相似的功能最開始是在各大地圖應用上接觸過,好比搜附近的電影院,附近的超市等等。然而真正讓附近的人火遍大江南北的應該是微信"附近的人"這個功能,記得微信剛出的時候,坊間還有一句"寂寞女聊玩微信,寂寞男人搜附近"的說法。html

v準備工做

建立測試數據庫java

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);

測試數據中的經度和緯度能夠用高德地圖或者百度地圖提取。mysql

v附近的人

原理git

先算出某個座標位置周圍的矩形的四個點,而後使用經緯度去直接匹配數據庫中的記錄。github

思路redis

首先算出「給定座標附近1000米」這個範圍的座標範圍。 雖然它是個圓,但咱們能夠先求出該圓的外接正方形,而後拿正方形的經緯度範圍去搜索數據庫。圓形內爲要求的搜索範圍,方形內爲咱們能間接獲得的結果範圍。算法

SpringBoot入門教程(五)Java基於MySQL實現附近的人

先來求東西兩側的的範圍邊界。在haversin公式中令φ1 = φ2,可得spring

SpringBoot入門教程(五)Java基於MySQL實現附近的人

Java實現sql

/**
     * 查找附近的人
     * @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/
關於做者:專一於基礎平臺的項目開發。若有問題或建議,請多多賜教!
版權聲明:本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
特此聲明:全部評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:若是您以爲文章對您有幫助,能夠點擊文章右下角推薦一下。您的鼓勵是做者堅持原創和持續寫做的最大動力!

相關文章
相關標籤/搜索