package com.doumee.core.utils.Tencent;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.doumee.core.utils.Http;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
|
import java.io.IOException;
|
import java.net.URLEncoder;
|
import java.util.Arrays;
|
import java.util.List;
|
import java.util.stream.Collectors;
|
|
/**
|
* 腾讯地图工具类
|
*
|
* @Author : Rk
|
* @create 2026/4/14 15:58
|
*/
|
@Slf4j
|
@Component
|
public class MapUtil {
|
|
private static String tencentKey;
|
|
/** 距离矩阵API */
|
public static final String MATRIX_URL = "https://apis.map.qq.com/ws/distance/v1/matrix";
|
|
/** 支持的模式 */
|
private static final List<String> SUPPORTED_MODES = Arrays.asList("driving", "bicycling");
|
|
@Value("${tencent_key}")
|
public void setTencentKey(String tencentKey) {
|
MapUtil.tencentKey = tencentKey;
|
}
|
|
/**
|
* 批量距离矩阵计算
|
*
|
* @param mode 模式:driving(驾车)、bicycling(自行车)
|
* @param fromPoints 起点列表,格式:lat,lng(最多10个)
|
* @param toPoints 终点列表,格式:lat,lng(最多20个)
|
* @return result.rows 矩阵数据,每个元素包含 distance(米) 和 duration(秒)
|
*/
|
public static JSONObject distanceMatrix(String mode, List<String> fromPoints, List<String> toPoints) {
|
if (!SUPPORTED_MODES.contains(mode)) {
|
throw new IllegalArgumentException("不支持的模式: " + mode + ",仅支持: " + SUPPORTED_MODES);
|
}
|
if (fromPoints == null || fromPoints.isEmpty() || toPoints == null || toPoints.isEmpty()) {
|
throw new IllegalArgumentException("起点和终点列表不能为空");
|
}
|
|
String from = String.join(";", fromPoints);
|
String to = String.join(";", toPoints);
|
|
try {
|
String url = MATRIX_URL
|
+ "?key=" + tencentKey
|
+ "&mode=" + mode
|
+ "&from=" + URLEncoder.encode(from, "UTF-8")
|
+ "&to=" + URLEncoder.encode(to, "UTF-8");
|
|
log.info("腾讯地图矩阵API请求: mode={}, from={}, to={}", mode, from, to);
|
|
JSONObject json = new Http().build(url)
|
.setConnectTimeout(5000)
|
.setReadTimeout(10000)
|
.get()
|
.toJSONObject();
|
|
log.info("腾讯地图矩阵API响应: {}", json);
|
|
if (json.getIntValue("status") != 0) {
|
throw new RuntimeException("腾讯地图矩阵API调用失败: " + json.getString("message"));
|
}
|
|
return json.getJSONObject("result");
|
} catch (IOException e) {
|
log.error("腾讯地图矩阵API调用异常", e);
|
throw new RuntimeException("腾讯地图矩阵API调用异常", e);
|
}
|
}
|
|
/**
|
* 单对距离计算(便捷方法)
|
*
|
* @param mode 模式:driving(驾车)、bicycling(自行车)
|
* @param from 起点格式:lat,lng
|
* @param to 终点格式:lat,lng
|
* @return 第一个元素的 distance(米) 和 duration(秒)
|
*/
|
public static JSONObject distanceSingle(String mode, String from, String to) {
|
JSONObject result = distanceMatrix(mode,
|
Arrays.asList(from),
|
Arrays.asList(to));
|
JSONArray rows = result.getJSONArray("rows");
|
if (rows != null && !rows.isEmpty()) {
|
JSONArray elements = rows.getJSONObject(0).getJSONArray("elements");
|
if (elements != null && !elements.isEmpty()) {
|
return elements.getJSONObject(0);
|
}
|
}
|
return new JSONObject();
|
}
|
|
/**
|
* 多起点到单终点(便捷方法)
|
* 返回每个起点到终点的距离和耗时,顺序与fromPoints对应
|
*
|
* @param mode 模式
|
* @param fromPoints 起点列表
|
* @param to 单个终点
|
* @return 距离耗时列表,顺序与fromPoints对应
|
*/
|
public static List<JSONObject> distanceToOne(String mode, List<String> fromPoints, String to) {
|
JSONObject result = distanceMatrix(mode, fromPoints, Arrays.asList(to));
|
JSONArray rows = result.getJSONArray("rows");
|
return rows == null ? Arrays.asList() : rows.stream()
|
.map(row -> ((JSONObject) row).getJSONArray("elements").getJSONObject(0))
|
.collect(Collectors.toList());
|
}
|
}
|