在现代Web应用中,基于位置的服务(LBS)变得越来越重要。本文将介绍如何使用SpringBoot框架结合高德地图API,实现基于用户当前位置的10个点位最短路径规划功能。这个功能可以广泛应用于物流配送、旅游路线规划等场景。
首先需要访问高德开放平台注册账号并创建应用,获取API Key。
使用Spring Initializr创建一个新的SpringBoot项目,添加以下依赖:
xml<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
</dependencies>
在application.properties
中添加配置:
propertiesamap.key=你的高德API Key amap.direction.url=https://restapi.amap.com/v3/direction/driving
javaimport lombok.Data;
@Data
public class Location {
private Double longitude; // 经度
private Double latitude;// 纬度
}
@Data
public class RouteRequest {
private Location origin;// 起点
private List<Location> waypoints; // 途经点(最多10个)
private Location destination;// 终点
}
@Data
public class RouteResponse {
private String status;// 请求状态
private String info;// 返回信息
private String route;// 规划路径
private Integer distance;// 路径距离(米)
private Integer duration;// 预计时间(秒)
}
javaimport org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
@Service
public class AmapService {
@Value("${amap.key}")
private String apiKey;
@Value("${amap.direction.url}")
private String directionUrl;
private final ObjectMapper objectMapper = new ObjectMapper();
public RouteResponse calculateShortestRoute(RouteRequest request) throws Exception {
// 构建途经点字符串
String waypoints = request.getWaypoints().stream()
.limit(10) // 限制最多10个途经点
.map(loc -> loc.getLongitude() + "," + loc.getLatitude())
.collect(Collectors.joining("|"));
// 构建请求URL
String url = String.format("%s?key=%s&origin=%s,%s&destination=%s,%s&waypoints=%s",
directionUrl,
apiKey,
request.getOrigin().getLongitude(),
request.getOrigin().getLatitude(),
request.getDestination().getLongitude(),
request.getDestination().getLatitude(),
waypoints);
// 发送HTTP请求
try (CloseableHttpClient client = HttpClients.createDefault()) {
HttpGet httpGet = new HttpGet(url);
String response = EntityUtils.toString(client.execute(httpGet).getEntity());
// 解析响应
return parseResponse(response);
}
}
private RouteResponse parseResponse(String json) throws Exception {
// 这里简化处理,实际应根据高德API返回的JSON结构进行完整解析
Map<String, Object> map = objectMapper.readValue(json, Map.class);
RouteResponse response = new RouteResponse();
response.setStatus(map.get("status").toString());
response.setInfo(map.get("info").toString());
if ("1".equals(response.getStatus())) {
Map<String, Object> route = (Map<String, Object>)
((List<Object>) map.get("route")).get(0);
Map<String, Object> path = (Map<String, Object>)
((List<Object>) route.get("paths")).get(0);
response.setRoute(path.get("steps").toString());
response.setDistance(Integer.parseInt(path.get("distance").toString()));
response.setDuration(Integer.parseInt(path.get("duration").toString()));
}
return response;
}
}
javaimport org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
@RestController
@RequestMapping("/api/route")
public class RouteController {
@Autowired
private AmapService amapService;
@PostMapping("/shortest")
public RouteResponse getShortestRoute(@RequestBody RouteRequest request) {
try {
return amapService.calculateShortestRoute(request);
} catch (Exception e) {
RouteResponse response = new RouteResponse();
response.setStatus("0");
response.setInfo("路径规划失败: " + e.getMessage());
return response;
}
}
}
html<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>最短路径规划</title>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>最短路径规划</h1>
<button onclick="getCurrentLocation()">获取当前位置并规划路线</button>
<div id="result"></div>
<script>
function getCurrentLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
const currentLoc = {
longitude: position.coords.longitude,
latitude: position.coords.latitude
};
planRoute(currentLoc);
},
error => {
alert('获取位置失败: ' + error.message);
}
);
} else {
alert('您的浏览器不支持地理位置功能');
}
}
function planRoute(currentLoc) {
// 模拟10个途经点(实际应用中可以从数据库获取)
const waypoints = [
{longitude: 116.481028, latitude: 39.989643},
{longitude: 116.434436, latitude: 39.90816},
{longitude: 116.416351, latitude: 39.981597},
{longitude: 116.340581, latitude: 39.940474},
{longitude: 116.399028, latitude: 39.915149},
{longitude: 116.374302, latitude: 39.978858},
{longitude: 116.387271, latitude: 39.939577},
{longitude: 116.425002, latitude: 39.914171},
{longitude: 116.353165, latitude: 39.966896},
{longitude: 116.412222, latitude: 39.957408}
];
// 设置终点(这里设为最后一个途经点)
const destination = waypoints[waypoints.length - 1];
const request = {
origin: currentLoc,
waypoints: waypoints,
destination: destination
};
axios.post('/api/route/shortest', request)
.then(response => {
const result = response.data;
let html = `<h2>规划结果</h2>`;
if (result.status === '1') {
html += `<p>距离: ${result.distance}米</p>`;
html += `<p>预计时间: ${Math.round(result.duration/60)}分钟</p>`;
html += `<p>路线详情: ${result.route}</p>`;
} else {
html += `<p style="color:red">${result.info}</p>`;
}
document.getElementById('result').innerHTML = html;
})
.catch(error => {
document.getElementById('result').innerHTML =
`<p style="color:red">请求失败: ${error.message}</p>`;
});
}
</script>
</body>
</html>
为了更直观地显示路线,可以在前端集成高德地图JavaScript API:
html<div id="map-container" style="width: 800px; height: 600px;"></div>
<script src="https://webapi.amap.com/maps?v=2.0&key=你的高德JS API Key"></script>
<script>
let map;
function initMap() {
map = new AMap.Map('map-container', {
zoom: 12,
center: [116.397428, 39.90923]
});
}
// 在planRoute函数中添加地图显示
function planRoute(currentLoc) {
// ...之前的代码...
axios.post('/api/route/shortest', request)
.then(response => {
const result = response.data;
// ...之前的显示代码...
if (result.status === '1') {
// 清除旧路线
map.clearMap();
// 添加起点标记
new AMap.Marker({
position: [currentLoc.longitude, currentLoc.latitude],
map: map,
title: '起点'
});
// 添加途经点标记
waypoints.forEach((point, index) => {
new AMap.Marker({
position: [point.longitude, point.latitude],
map: map,
title: `途经点${index + 1}`
});
});
// 添加终点标记
new AMap.Marker({
position: [destination.longitude, destination.latitude],
map: map,
title: '终点'
});
// 绘制路线(简化处理,实际应使用返回的路线坐标)
const path = [
[currentLoc.longitude, currentLoc.latitude],
...waypoints.map(p => [p.longitude, p.latitude]),
[destination.longitude, destination.latitude]
];
new AMap.Polyline({
path: path,
isOutline: true,
outlineColor: '#ffeeff',
borderWeight: 1,
strokeColor: '#3366FF',
strokeOpacity: 1,
strokeWeight: 6,
lineJoin: 'round',
map: map
});
// 调整视野显示所有标记
map.setFitView();
}
})
// ...错误处理...
}
// 初始化地图
initMap();
</script>
本文介绍了如何使用SpringBoot结合高德地图API实现基于当前位置的10个点位最短路径规划功能。关键点包括:
实际应用中,你可能还需要考虑:
如果想自定义算法实现最短路径规划,使用Dijkstra算法实现
希望本文能为你实现基于位置的服务提供有价值的参考。