1. 背景

在做水利、防汛、应急管理、智能交通等系统时,经常会涉及 路径规划 的需求。比如:

  • 村庄转移到安置点的最优路线

  • 防汛物资的运输路线

  • 应急抢险人员的行进路线

天地图官方提供了 驾车/步行路径规划 API,返回的是 XML 格式数据。但直接解析 XML 比较麻烦,所以我写了一个 Java 工具类 TiandituRouteUtils,帮大家快速获取推荐路线。


2. 天地图 API 简介
  • 接口地址:http://api.tianditu.gov.cn/drive

  • 请求方式:GET

  • 参数:

    • postStr: JSON 格式字符串,包含 orig(起点经纬度)、dest(终点经纬度)、style(路线类型)

    • tk: 天地图开发者密钥

返回结果是 XML 格式,需要自己解析。


3. 工具类封装

我把请求和解析过程都封装到了 TiandituRouteUtils,直接调用即可拿到 List<RoutePoint> 对象,包含经纬度、道路名称、导航提示等信息。

package com.zhy.common.utils.map;

import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 天地图驾车路线规划工具类
 * 可根据起点和终点经纬度,获取推荐路线点位
 *
 * @author GaXer
 * @since 2025/09/24
 */
@Slf4j
public class TiandituRouteUtils {

    /** 天地图驾车规划接口地址 */
    private static final String ROUTE_URI = "http://api.tianditu.gov.cn/drive";

    /**
     * 路径规划
     * @param origLon 起点经度
     * @param origLat 起点纬度
     * @param destLon 终点经度
     * @param destLat 终点纬度
     * @param driveKey 天地图Key
     * @param style 路径类型(0:最快,1:最短,2:避开高速,3:步行)
     * @return 推荐路线点位列表
     */
    public static List<RoutePoint> getRecommendRoute(double origLon, double origLat,
                                                     double destLon, double destLat,
                                                     String driveKey, String style) {
        List<RoutePoint> routeList = new ArrayList<>();
        try {
            // 构建请求参数
            String postStr = String.format("{\"orig\":\"%f,%f\",\"dest\":\"%f,%f\",\"style\":\"%s\"}",
                    origLon, origLat, destLon, destLat, style);

            try (HttpResponse response = HttpUtil.createGet(ROUTE_URI)
                    .form("postStr", postStr)
                    .form("type", "search")
                    .form("tk", driveKey)
                    .execute()) {

                if (!response.isOk()) {
                    log.error("请求天地图失败,响应: {}", response.body());
                    return routeList;
                }
                String responseBody = response.body();
                routeList = parseRouteList(responseBody);
            }
        } catch (Exception e) {
            log.error("获取推荐路线失败", e);
        }
        return routeList;
    }

    /** 解析XML成路线点 */
    private static List<RoutePoint> parseRouteList(String responseBody) throws Exception {
        List<RoutePoint> routeList = new ArrayList<>();
        try (ByteArrayInputStream inputStream =
                     new ByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8))) {

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(inputStream);
            document.getDocumentElement().normalize();

            NodeList routesList = document.getElementsByTagName("routes");
            if (routesList.getLength() > 0) {
                Element routesElement = (Element) routesList.item(0);
                NodeList items = routesElement.getElementsByTagName("item");

                for (int idx = 0; idx < items.getLength(); idx++) {
                    Element item = (Element) items.item(idx);
                    RoutePoint routePoint = new RoutePoint();
                    routePoint.setId(IdUtil.getSnowflakeNextId());
                    routePoint.setGuide(getElementText(item, "strguide"));
                    routePoint.setStreetName(getElementText(item, "streetName"));

                    String[] latLon = getElementText(item, "turnlatlon").split(",");
                    routePoint.setLongitude(Double.parseDouble(latLon[0]));
                    routePoint.setLatitude(Double.parseDouble(latLon[1]));
                    routePoint.setSort(idx);

                    routeList.add(routePoint);
                }
            }
        }
        return routeList;
    }

    /** 获取某个XML子元素的文本内容 */
    private static String getElementText(Element parent, String tagName) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        return (nodeList.getLength() > 0) ? nodeList.item(0).getTextContent().trim() : "";
    }

    /**
     * 打印XML节点信息(调试用)
     * @param element XML元素
     */
    public static void parseElement(Element element) {
        System.out.print("<" + element.getTagName());
        NamedNodeMap attris = element.getAttributes();
        for (int i = 0; i < attris.getLength(); i++) {
            Attr attr = (Attr) attris.item(i);
            System.out.print(" " + attr.getName() + "=\"" + attr.getValue() + "\"");
        }
        System.out.println(">");

        NodeList nodeList = element.getChildNodes();
        for (int temp = 0; temp < nodeList.getLength(); temp++) {
            Node childNode = nodeList.item(temp);
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                if (childNode.hasChildNodes()) {
                    parseElement((Element) childNode);
                } else if (childNode.getNodeType() != Node.COMMENT_NODE) {
                    System.out.print(childNode.getTextContent());
                }
            }
        }
        System.out.println("</" + element.getTagName() + ">");
    }


    /** 路线点对象 */
    @Data
    public static class RoutePoint {
        private Long id;
        private double longitude;
        private double latitude;
        private int sort;
        private String guide;
        private String streetName;
    }
}

使用示例

public class Demo {
    public static void main(String[] args) {
        String key = "你的天地图key";
        List<TiandituRouteUtils.RoutePoint> route =
                TiandituRouteUtils.getRecommendRoute(
                        113.665412, 34.757975, // 起点:郑州
                        114.305393, 30.593099, // 终点:武汉
                        key,
                        "0" // 最快路线
                );

        route.forEach(r -> System.out.printf("%d: %s (%f,%f)%n",
                r.getSort(), r.getGuide(), r.getLongitude(), r.getLatitude()));
    }
}
5. 应用场景
  • 防汛指挥系统:村庄转移路线

  • 农业水利平台:灌溉工程的巡查路径规划

  • 智慧交通:车辆行驶推荐路线


6. 总结

通过这个工具类,我们可以:

  • 免去手写 XML 解析的痛苦

  • 快速拿到推荐路线的点位信息

  • 在地图上直接绘制行进轨迹

如果你也在做类似的系统,可以直接拿去用。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐