本文目录导读:

在 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>
最佳实践建议
- API Key 安全:不要把 API Key 硬编码在代码中,使用环境变量或配置文件
- 错误处理:统一处理地图服务可能出现的异常
- 缓存策略:对地理编码等耗时操作进行缓存
- 限流控制:注意地图 API 的调用频率限制
- 测试:编写单元测试和集成测试
// 缓存示例
public function getGeocodeCached($address)
{
$cacheKey = 'geocode:' . md5($address);
return Cache::remember($cacheKey, 86400, function () use ($address) {
return $this->geocode($address);
});
}
选择地图服务时要考虑:
- 覆盖范围(国内/国外)
- 价格方案
- 调用限制
- 功能完整性
- 中文支持度
这样你就有了一个完整的 Laravel 地图服务解决方案,根据实际需求选择合适的提供商和集成方式即可。