最近給andorid作後臺查詢數據功能,有一個需求是模仿微信的查找附近人功能。 數據庫中存儲每一個用戶的經緯度信息及用戶信息,經過當前用戶傳遞過來的經緯度查詢這個用戶半徑N千米之內的用戶信息。 html
數據庫表結構:java
表信息android
表名 Mobile_Usergit
mu_id 自增,主鍵sql
mu_u_id 用戶表的ID 外鍵數據庫
mu_longitud 精度json
mu_latitude 緯度 (還有其餘的一些信息,這裏就列舉4個字段足矣)數組
首先須要一個方法,是把傳遞過來的經緯度按照半徑N千米擴散,找出距離中心經緯度N千米的上下左右經緯度值。效果如圖微信
隨手畫的 勿噴
框架
以中心生成經緯度時 正上方和正下方的精度是不變的,只有緯度變化。 生成左右時道理同樣,只有精度變化,緯度是不變的。
因此只須要生成上下的緯度,左右的精度就能夠了。
參考了網上的文章,http://digdeeply.info/archives/06152067.html 這篇文章是用PHP實現的經緯度查詢。修改爲java的 代碼以下
/** * 生成以中心點爲中心的四方形經緯度 * * @param lat 緯度 * @param lon 精度 * @param raidus 半徑(以米爲單位) * @return */ public static double[] getAround(double lat, double lon, int raidus) { Double latitude = lat; Double longitude = lon; Double degree = (24901 * 1609) / 360.0; double raidusMile = raidus; Double dpmLat = 1 / degree; Double radiusLat = dpmLat * raidusMile; Double minLat = latitude - radiusLat; Double maxLat = latitude + radiusLat; Double mpdLng = degree * Math.cos(latitude * (Math.PI / 180)); Double dpmLng = 1 / mpdLng; Double radiusLng = dpmLng * raidusMile; Double minLng = longitude - radiusLng; Double maxLng = longitude + radiusLng; return new double[] { minLat, minLng, maxLat, maxLng }; }
這樣四周的經緯度都已經生成了。
下一步是查詢數據庫中和四周經緯度匹配的數據。 若是數據量很大的話會很耗時間,並且會很消耗流量。因此須要用到分頁查詢
代碼以下
select * from mobile_user where mu_latitude <> 0 and mu_longitud > #left_lat# and mu_longitud < #right_lat# and mu_latitude > #down_lon# and mu_latitude < #top_lon# and mu_u_id <> #uid# order by ACOS(SIN((#lat# * 3.1415) / 180 ) * SIN((mu_latitude * 3.1415) / 180 ) +COS((#lat# * 3.1415) / 180 ) * COS((mu_latitude * 3.1415) / 180 ) *COS((#lon# * 3.1415) / 180 - (mu_longitud * 3.1415) / 180 ) ) * 6380 asc limit #start#,#end#
我用的是ibatis框架,sql裏以#開始並結束的 是我傳遞過來的參數。 sql語句計算了每條數據和中心經緯度的距離而且以最近進行排序。 sql語句是根據下面的方法演變而來
方法是計算兩個經緯度之間的直線距離。
/** * 計算中心經緯度與目標經緯度的距離(米) * * @param centerLon * 中心精度 * @param centerLan * 中心緯度 * @param targetLon * 須要計算的精度 * @param targetLan * 須要計算的緯度 * @return 米 */ private static double distance(double centerLon, double centerLat, double targetLon, double targetLat) { double jl_jd = 102834.74258026089786013677476285;// 每經度單位米; double jl_wd = 111712.69150641055729984301412873;// 每緯度單位米; double b = Math.abs((centerLat - targetLat) * jl_jd); double a = Math.abs((centerLon - targetLon) * jl_wd); return Math.sqrt((a * a + b * b)); }
這樣既實現了分頁處理,又實現了每條數據的經緯度與中心經緯度的直線距離(以米爲單位)。
最後就是組成json數組返回給android使用了。
作個筆記,歡迎補充。
思考:
數據量大了,須要按照經緯度進行分表
鑑於一些網站採集本blog的文章, 本站原創。 http://blog.csdn.net/qq7342272 轉載請註明出處。