You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Laravel API实现附近地点展示功能

如何在Laravel 5.6中实现基于经纬度查找附近地点的REST API功能?

嘿,作为Laravel新手能写到这一步已经很棒啦!先给你点个赞~你的术语用得没问题,REST API的思路完全在线,咱们一步步来完善这个附近地点查询的功能。

首先,先确认你的parties表已经有存储经纬度的字段,比如lat(纬度)和lng(经度),字段类型建议用DECIMAL(10,8)和DECIMAL(11,8),这样精度足够日常使用。

接下来给你两种实现方案,你可以根据自己的数据库环境选择:

方案一:使用Haversine公式(兼容性强,适合所有数据库)

Haversine公式是计算球面两点距离的经典算法,不需要数据库支持空间扩展,非常适合新手快速实现。你可以把原来的代码补全成这样:

public function index(\Illuminate\Http\Request $request)
{
    // 按活动分类查询
    if ($request->has('party_category')) {
        $parties = Parties::where('party_category', $request->party_category)->get();
    }
    // 按经纬度查找附近地点
    elseif ($request->has('lat') && $request->has('lng')) {
        // 获取传入的经纬度
        $lat = $request->input('lat');
        $lng = $request->input('lng');
        // 设置搜索半径(单位:公里,这里设为10公里,你可以根据需求调整)
        $radius = 10;

        // 使用Haversine公式计算距离并筛选
        $parties = Parties::selectRaw("*, 
            (6371 * acos(cos(radians(?)) * cos(radians(lat)) * cos(radians(lng) - radians(?)) + sin(radians(?)) * sin(radians(lat)))) AS distance", 
            [$lat, $lng, $lat])
            ->having('distance', '<=', $radius)
            ->orderBy('distance')
            ->get();
    }
    // 默认返回所有活动
    else {
        $parties = Parties::all();
    }

    return response()->json($parties);
}

代码说明:

  • 6371是地球的平均半径(公里),如果要换成英里可以用3956
  • selectRaw里的SQL会计算每个活动到指定经纬度的距离,并给这个距离起别名distance
  • having用来筛选出距离在设定半径内的结果
  • orderBy('distance')可以让结果按从近到远排序

方案二:使用Laravel空间查询(更优雅,需数据库支持)

如果你的数据库是MySQL 5.7+或者PostgreSQL,建议把经纬度字段改成POINT类型(空间数据类型),这样可以用Laravel的空间查询功能,代码更简洁:

  1. 先修改数据库表,添加空间字段(或者修改原有字段):
ALTER TABLE parties ADD location POINT NOT NULL;
-- 或者替换原有lat和lng字段:
-- ALTER TABLE parties DROP COLUMN lat, DROP COLUMN lng;
-- ALTER TABLE parties ADD location POINT NOT NULL;

(注意:如果是新建表,迁移文件里可以用$table->point('location');)

  1. 然后在Parties模型里添加空间字段的配置:
protected $casts = [
    'location' => 'point',
];
  1. 最后修改控制器的查询代码:
public function index(\Illuminate\Http\Request $request)
{
    if ($request->has('party_category')) {
        $parties = Parties::where('party_category', $request->party_category)->get();
    }
    elseif ($request->has('lat') && $request->has('lng')) {
        $lat = $request->input('lat');
        $lng = $request->input('lng');
        $radius = 10; // 公里

        $parties = Parties::whereRaw('ST_Distance_Sphere(location, POINT(?, ?)) <= ? * 1000', [$lng, $lat, $radius])
            ->orderByRaw('ST_Distance_Sphere(location, POINT(?, ?))', [$lng, $lat])
            ->get();
    }
    else {
        $parties = Parties::all();
    }

    return response()->json($parties);
}

代码说明:

  • ST_Distance_Sphere是MySQL的空间函数,用来计算两点之间的球面距离(单位:米),所以要把公里转换成米(*1000)
  • 注意:POINT的参数顺序是经度在前,纬度在后,别搞反了!

额外建议:

  • 记得给经纬度字段添加索引,比如方案一给lat和lng加普通索引,方案二给location加空间索引,这样查询速度会快很多
  • 可以添加参数验证,比如用Laravel的$request->validate()来确保lat和lng是有效的数字,避免报错:
// 在方法开头添加
$request->validate([
    'lat' => 'required_with:lng|numeric|between:-90,90',
    'lng' => 'required_with:lat|numeric|between:-180,180',
    'party_category' => 'nullable|exists:parties,party_category',
]);

这样你的API就能同时支持按分类查询和按经纬度查附近地点啦,有问题随时调整~

内容的提问来源于stack exchange,提问作者Baran KARABOGA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:54:58