PHP项目Laravel地图服务如何调用

wen PHP项目 5

本文目录导读:

PHP项目Laravel地图服务如何调用

  1. 通用地图服务提供商
  2. 使用地图前端SDK
  3. 完整的服务类示例
  4. 配置管理
  5. 控制器使用示例
  6. 前端 Vue 组件示例
  7. 最佳实践建议

在 Laravel 中调用地图服务通常涉及以下几种主流方案,我来为你详细介绍:

通用地图服务提供商

Google Maps

// 安装扩展包
composer require google/maps-services
// 创建服务类
namespace App\Services;
use GoogleMaps;
class GoogleMapService
{
    protected $client;
    public function __construct()
    {
        $this->client = new \GoogleMaps\GoogleMaps(config('services.google.maps_key'));
    }
    // 地理编码
    public function geocode($address)
    {
        $response = $this->client->geocode($address);
        return $response['results'][0]['geometry']['location'];
    }
    // 计算距离
    public function distance($origin, $destination)
    {
        $response = $this->client->directions($origin, $destination);
        return $response['routes'][0]['legs'][0]['distance']['value'];
    }
}

高德地图(国内常用)

namespace App\Services;
use Illuminate\Support\Facades\Http;
class AmapService
{
    protected $key;
    protected $baseUrl = 'https://restapi.amap.com/v3';
    public function __construct()
    {
        $this->key = config('services.amap.key');
    }
    // 地理编码
    public function geocode($address)
    {
        $response = Http::get($this->baseUrl . '/geocode/geo', [
            'address' => $address,
            'key' => $this->key
        ]);
        return $response->json();
    }
    // POI搜索
    public function searchPoi($keyword, $city = '')
    {
        $response = Http::get($this->baseUrl . '/place/text', [
            'keywords' => $keyword,
            'city' => $city,
            'key' => $this->key
        ]);
        return $response->json();
    }
}

使用地图前端SDK

在 Blade 模板中集成

{{-- resources/views/map.blade.php --}}
<!DOCTYPE html>
<html>
<head>
    <script src="https://maps.googleapis.com/maps/api/js?key={{ config('services.google.maps_key') }}"></script>
</head>
<body>
    <div id="map" style="height: 400px;"></div>
    <script>
        function initMap() {
            var map = new google.maps.Map(document.getElementById('map'), {
                center: {lat: -34.397, lng: 150.644},
                zoom: 8
            });
            // 添加标记
            var marker = new google.maps.Marker({
                position: {lat: -34.397, lng: 150.644},
                map: map,
                title: 'Hello World!'
            });
        }
    </script>
    <script>
        // 将数据传递给前端
        const mapData = @json($locations);
        console.log(mapData);
    </script>
</body>
</html>

完整的服务类示例

<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use App\Exceptions\MapServiceException;
class MapService
{
    protected $provider;
    protected $config;
    public function __construct($provider = 'amap')
    {
        $this->provider = $provider;
        $this->config = config("maps.{$provider}");
    }
    /**
     * 地理编码:地址转坐标
     */
    public function geocode($address)
    {
        try {
            $response = Http::get($this->config['api_url'] . '/geocode/geo', [
                'address' => $address,
                'key' => $this->config['key']
            ]);
            if ($response->successful()) {
                $data = $response->json();
                if ($data['status'] == '1' && !empty($data['geocodes'])) {
                    $location = explode(',', $data['geocodes'][0]['location']);
                    return [
                        'lng' => floatval($location[0]),
                        'lat' => floatval($location[1]),
                        'formatted_address' => $data['geocodes'][0]['formatted_address']
                    ];
                }
                throw new MapServiceException('地理编码失败');
            }
            throw new MapServiceException('API请求失败');
        } catch (\Exception $e) {
            \Log::error('地图服务错误', [
                'message' => $e->getMessage(),
                'address' => $address
            ]);
            throw new MapServiceException($e->getMessage());
        }
    }
    /**
     * 逆地理编码:坐标转地址
     */
    public function reverseGeocode($lng, $lat)
    {
        // 实现代码...
    }
    /**
     * 路径规划
     */
    public function drivingRoute($from, $to)
    {
        try {
            $response = Http::get($this->config['api_url'] . '/direction/driving', [
                'origin' => implode(',', $from),
                'destination' => implode(',', $to),
                'key' => $this->config['key']
            ]);
            return $response->json();
        } catch (\Exception $e) {
            throw new MapServiceException('路径规划失败');
        }
    }
}

配置管理

// config/maps.php
return [
    'amap' => [
        'name' => '高德地图',
        'key' => env('AMAP_MAP_KEY', ''),
        'secret' => env('AMAP_MAP_SECRET', ''),
        'api_url' => 'https://restapi.amap.com/v3',
        'js_url' => 'https://webapi.amap.com/maps',
        'web_key' => env('AMAP_WEB_KEY', '')
    ],
    'google' => [
        'name' => 'Google Maps',
        'key' => env('GOOGLE_MAPS_KEY', ''),
        'api_url' => 'https://maps.googleapis.com/maps/api',
        'js_url' => 'https://maps.googleapis.com/maps/api/js'
    ],
    'baidu' => [
        'name' => '百度地图',
        'key' => env('BAIDU_MAP_KEY', ''),
        'api_url' => 'https://api.map.baidu.com',
        'js_url' => 'https://api.map.baidu.com/api'
    ]
];
// .env 文件
AMAP_MAP_KEY=your_amap_key_here
GOOGLE_MAPS_KEY=your_google_key_here
BAIDU_MAP_KEY=your_baidu_key_here

控制器使用示例

<?php
namespace App\Http\Controllers;
use App\Services\MapService;
use Illuminate\Http\Request;
class LocationController extends Controller
{
    protected $mapService;
    public function __construct(MapService $mapService)
    {
        $this->mapService = $mapService;
    }
    // 获取门店位置
    public function storeLocations()
    {
        $stores = Store::select('name', 'address', 'lat', 'lng')->get();
        foreach ($stores as $store) {
            $store->distance = $this->mapService->drivingRoute(
                ['lng' => request('lng'), 'lat' => request('lat')],
                ['lng' => $store->lng, 'lat' => $store->lat]
            );
        }
        return response()->json($stores);
    }
    // 地址搜索
    public function searchAddress(Request $request)
    {
        $validated = $request->validate([
            'keyword' => 'required|string|max:255'
        ]);
        try {
            $result = $this->mapService->geocode($validated['keyword']);
            return response()->json($result);
        } catch (MapServiceException $e) {
            return response()->json([
                'error' => $e->getMessage()
            ], 422);
        }
    }
}

前端 Vue 组件示例

<template>
  <div>
    <div ref="mapContainer" class="map-container"></div>
  </div>
</template>
<script>
export default {
  name: 'MapComponent',
  props: {
    locations: {
      type: Array,
      default: () => []
    },
    center: {
      type: Object,
      default: () => ({ lng: 116.397428, lat: 39.90923 })
    }
  },
  mounted() {
    this.initMap();
  },
  methods: {
    initMap() {
      // 加载地图
      if (window.AMap) {
        this.createMap();
      } else {
        this.loadScript()
          .then(() => this.createMap())
          .catch(err => console.error('地图加载失败:', err));
      }
    },
    createMap() {
      this.map = new AMap.Map(this.$refs.mapContainer, {
        zoom: 11,
        center: [this.center.lng, this.center.lat]
      });
      this.addMarkers(this.locations);
    },
    addMarkers(locations) {
      locations.forEach(location => {
        const marker = new AMap.Marker({
          position: [location.lng, location.lat],
          title: location.name
        });
        marker.setMap(this.map);
      });
    },
    loadScript() {
      return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = `https://webapi.amap.com/maps?v=1.4.15&key=${process.env.VUE_APP_AMAP_KEY}`;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
      });
    }
  }
}
</script>
<style scoped>
.map-container {
  width: 100%;
  height: 400px;
}
</style>

最佳实践建议

  1. API Key 安全:不要把 API Key 硬编码在代码中,使用环境变量或配置文件
  2. 错误处理:统一处理地图服务可能出现的异常
  3. 缓存策略:对地理编码等耗时操作进行缓存
  4. 限流控制:注意地图 API 的调用频率限制
  5. 测试:编写单元测试和集成测试
// 缓存示例
public function getGeocodeCached($address)
{
    $cacheKey = 'geocode:' . md5($address);
    return Cache::remember($cacheKey, 86400, function () use ($address) {
        return $this->geocode($address);
    });
}

选择地图服务时要考虑:

  • 覆盖范围(国内/国外)
  • 价格方案
  • 调用限制
  • 功能完整性
  • 中文支持度

这样你就有了一个完整的 Laravel 地图服务解决方案,根据实际需求选择合适的提供商和集成方式即可。

抱歉,评论功能暂时关闭!