MrShi
昨天 7ee466ebc953bb5640bcf42f2b8e2a87aa471c21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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());
    }
}