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);
測試資料中的經度和緯度可以用 ofollow,noindex">高德地圖 或者 百度地圖 提取。
v 附近的人
原理
先算出某個座標位置周圍的矩形的四個點,然後使用經緯度去直接匹配資料庫中的記錄。
思路
首先算出“給定座標附近1000米”這個範圍的座標範圍。 雖然它是個圓,但我們可以先求出該圓的外接正方形,然後拿正方形的經緯度範圍去搜索資料庫。圓形內為要求的搜尋範圍,方形內為我們能間接得到的結果範圍。
先來求東西兩側的的範圍邊界。在haversin公式中令φ1 = φ2,可得
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 >= #{minlng} and longitude <= #{maxlng} and latitude >= #{minlat} and latitude <= #{maxlat} </select>
List<UserPosition> getvicinity(@Param("minlng") BigDecimal minlng, @Param("maxlng") BigDecimal maxlng, @Param("minlat") BigDecimal minlat, @Param("maxlat") BigDecimal maxlat);
測試效果
在地圖中找到回龍新村的經緯度,然後測試。
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);
測試效果
補充,如果需要按距離排序,並返回距離的欄位。可以按如下方式實現。
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米地點查詢–合理利用演算法__演算法 https://yq.aliyun.com/ziliao/230566
- mysql 下 計算 兩點 經緯度 之間的距離 https://www.cnblogs.com/sandea/p/4673297.html
- MYSQL建立一個function用來計算經緯度距離 http://xigua366.iteye.com/blog/2242818
作者: 請叫我頭頭哥
出處: http://www.cnblogs.com/toutou/
關於作者:專注於基礎平臺的專案開發。如有問題或建議,請多多賜教!
版權宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!