MrShi
2 天以前 7ee466ebc953bb5640bcf42f2b8e2a87aa471c21
server/services/src/main/java/com/doumee/core/utils/Tencent/MapUtil.java
@@ -1,6 +1,124 @@
package com.doumee.core.utils.Tencent;/**
* Created by IntelliJ IDEA.
* @Author : Rk
* @create 2026/4/14 15:58
*/public class MapUtil {
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());
    }
}