SwiftUI请求添加约束 Vapor后端实现10000米内Per数据过滤
实现方案
优先选择服务端过滤逻辑,避免全量拉取数据造成的带宽浪费、性能损耗,仅返回符合距离要求的数据。
1. 改造iOS端请求,传递当前坐标
将本地存储的经纬度作为查询参数传递给服务端,修改后的getlocation代码如下:
func getlocation(){ let mylatitude = UserDefaults.standard.double(forKey:"mylatitude") let mylongitude = UserDefaults.standard.double(forKey: "mylongitude") // 拼接查询参数 guard let url = URL(string: "http://127.0.0.1:8080/pers?lat=\(mylatitude)&lon=\(mylongitude)") else { fatalError("URL is not defined!") } var request = URLRequest(url: url) request.httpMethod = "GET" URLSession.shared.dataTask(with: request) { (data, response, error) in do{ if let data = data { // 服务端已经返回过滤后的结果,直接使用即可 let result = try JSONDecoder().decode([Per].self, from: data) DispatchQueue.main.async { self.per = result } }else{ print("no data") } }catch(let error){ print("error: ", error.localizedDescription) } }.resume() }
2. 改造Vapor服务端逻辑
你使用的是PostgreSQL数据库,推荐安装postgis扩展实现高效的地理位置距离计算,也可以用球面距离公式实现过滤。
2.1 前置准备(可选,推荐)
给PostgreSQL对应数据库安装postgis扩展,执行SQL:
CREATE EXTENSION postgis;
2.2 修改Controller逻辑
修改InformationController的getall方法,接收坐标参数、做距离过滤:
import Foundation import Vapor import Fluent final class InformationController{ func getall (_ req: Request) throws -> EventLoopFuture<[Pers]>{ // 接收请求传递的经纬度参数 let userLat = try req.query.get(Double.self, at: "lat") let userLon = try req.query.get(Double.self, at: "lon") let maxDistance: Double = 10000 // 10000米 // 用PostGIS的ST_DistanceSphere计算球面距离,单位为米 return Pers.query(on: req.db) .filter( .sql(raw: "ST_DistanceSphere(ST_MakePoint(經度, 緯度), ST_MakePoint(\(userLon), \(userLat))) < \(maxDistance)") ) .all() } }
如果你不想安装postgis,也可以用Haversine公式实现距离计算,把上面的filter替换为:
.filter(.sql(raw: "6371000 * acos(cos(radians(\(userLat))) * cos(radians(緯度)) * cos(radians(經度) - radians(\(userLon))) + sin(radians(\(userLat))) * sin(radians(緯度))) < \(maxDistance)"))
2.3 路由无需修改
原有路由逻辑保持不变即可正常接收查询参数。
内容的提问来源于stack exchange,提问作者蔡濡安
相关产品推荐
相关产品推荐

