一、驾车路线服务简介
本节将对百度地图的驾车路线服务进行简单的介绍。这不仅是我们开发的重要文档,也是我们后续进行问题查找的重要资料。这里将详细的介绍百度地图提供哪些规划服务、驾车路线服务包括哪些以及驾车路线服务的请求参数和响应参数信息。
基于 Java 调用百度地图驾车路线规划 API 实现路线查询功能。内容包含接口请求参数详解、响应数据结构分析,演示如何使用 UniHttp 进行接口集成与本地测试,并通过 GSON 将 JSON 数据封装为 JavaBean 对象以便持久化。此外,针对坐标顺序错误及坐标格式不支持 WGS84 返回等常见问题提供了具体解决方案,帮助开发者完成路径规划服务的稳定接入。

本节将对百度地图的驾车路线服务进行简单的介绍。这不仅是我们开发的重要文档,也是我们后续进行问题查找的重要资料。这里将详细的介绍百度地图提供哪些规划服务、驾车路线服务包括哪些以及驾车路线服务的请求参数和响应参数信息。
路线规划服务(又名 Direction API)是一套 REST 风格的 Web 服务 API,以 HTTP/HTTPS 形式提供了路线规划服务。

从上图可以看到,百度地图的路线规划服务视图是非常丰富的,不仅包含驾车的方式,还包含骑行、步行和公交。大家可以根据自己的业务需要来调用相应的服务即可。
驾车服务作为路线服务中非常重要的一环。如今随着城市交通建设的大力发展,许多城市的道路建设几乎是日新月异,如果没有路线导航服务,出行一定会受到极大的限制。
百度驾车路线服务:
根据起终点坐标检索符合条件的驾车路线规划方案,支持以下功能:
支持一次请求返回多条路线(备用路线)
支持 18 个以内的途径点
支持传入车牌规避限行路段
支持传入起点车头方向,辅助判断起点所在正逆向车道,辅助更准确算路
支持未来出行规划,指定未来 7 天任意出发时刻,将依据智能预测路况和道路限行规划合理路线
驾车路线服务的访问地址如下:
https://api.map.baidu.com/direction/v2/driving?origin=40.01116,116.339303&destination=39.936404,116.452562&ak=您的 AK
| 字段名称 | 含义 | 字段类型 | 必填 | 备注 |
|---|---|---|---|---|
| ak | 用户的访问权限,AK 申请 | string | 必填 | |
| origin | 起点经纬度,小数点后不超过 6 位,40.056878,116.30815 | string | 必填 | 起点经纬度,格式为:纬度,经度;小数点后不超过 6 位 |
| destination | 终点经纬度,小数点后不超过 6 位,40.056878,116.30815 | string | 必填 | 终点经纬度,格式为:纬度,经度;小数点后不超过 6 位 |
| origin_uid | POI 的 uid(在已知起点 POI 的 uid 情况下,请尽量填写 uid,将提升路线规划的准确性) | string | 选填 | |
| destination_uid | POI 的 uid(在已知终点 POI 的 uid 情况下,请尽量填写 uid,将提升路线规划的准确性) | string | 选填 | |
| waypoints | 途径点坐标串,支持 18 个以内的有序途径点。多个途径点坐标按顺序以英文竖线符号分隔 | string | 选填 | |
| coord_type | 坐标类型,可选参数,默认为 bd09ll。允许的值为:bd09ll(百度经纬度坐标)、bd09mc(百度墨卡托坐标)、gcj02(国测局加密坐标)、wgs84(gps 设备获取的坐标) | string | 选填 | 默认 bd09ll |
| ret_coordtype | 返回结果坐标类型,默认为 bd09ll,允许的值为:bd09ll(百度经纬度坐标)、gcj02(国测局加密坐标) | string | 选填 | 默认 bd09ll |
| tactics | 策略:0:默认;2:距离最短;3:不走高速;4:高速优先;5:躲避拥堵;6:少收费;7: 躲避拥堵 & 高速优先等 | int | 选填 | 默认 0:默认策略 |
| alternatives | 是否返回备选路线:0:返回一条推荐路线;1:返回 1-3 条路线供选择 | int | 选填 | 默认 0 |
| cartype | 车辆类型:0:普通汽车;1:纯电动汽车 | int | 选填 | 默认 0 |
| plate_number | 车牌号,如 京 A00022。用于规避车牌号限行路段 | string | 选填 | 不填则不做规避 |
| departure_time | 设置出发时间(支持未来 7 天),UNIX 时间戳。该功能为高级付费服务 | string | 选填 | 默认为当前时间 |
| ext_departure_time | 更多出发时间,UNIX 时间戳。用于返回驾车路线历史耗时 | string | 选填 | 不填则不返回 ext_duration 字段 |
| expect_arrival_time | 预期的到达时间,UNIX 时间戳。用于返回建议出发时间 | string | 选填 | 不填则不返回 suggest_departure_time 字段 |
| gps_direction | 起点的车头方向。字段类型:int64 取值范围:0-359 | int | 选填 | |
| radius | 起点的定位精度,字段类型:float,取值范围 [0,2000] | float | 选填 | 配合 gps_direction 字段使用 |
| speed | 起点车辆的行驶速度,字段类型:float | float | 选填 | 单位:米/秒,配合 gps_direction 字段使用 |
| output | 表示输出类型,可设置为 xml 或 json | string | 选填 | 默认为 json |
| sn | 用户的权限签名,当 AK 设置为 SN 校验时,该参数必填 | string | 选填 | |
| timestamp | 时间戳,与 SN 配合使用 | int64 | SN 存在时必填 | |
| callback | 回调函数 | string | 选填 | 仅在 output=json 时,该参数有效 |
| intelligent_plan | 传入多个途经点,综合考虑路况、交规限行、途经点的相对位置以及路线整体的绕路成本等,支持智能调整途经点顺序 | int | 选填 | 默认 0:不执行途经点智能规划 |
| walkinfo | 起终点步导路线:1 表示下发起终点步导路线;0 不下发 | int | 选填 | 默认值为 0 |
| steps_info | 是否下发 step 详情:1:下发 step 详情;0:不下发 step 详情 | int | 选填 | |
| origin_bind_strategy | 起点绑路策略:0-起点绑路不剔除封闭道路;1-起点绑路剔除封闭道路 | int | 选填 | 默认值 0 |
| dest_bind_strategy | 终点绑路策略:0-终点绑路不剔除封闭道路;1-终点绑路剔除封闭道路 | int | 选填 | 默认值 0 |
| origin_road_type | 起点道路类型:0 普通道路 [默认];1 高架上;2 高架下;3 主路;4 辅路 | int | 选填 | 默认值 0 |
| 字段名称 | 字段含义 | 字段类型 | 备注 |
|---|---|---|---|
| status | 状态码 | int | 0:成功;1:服务内部错误;2:参数无效;7:无返回结果 |
| message | 状态码对应的信息 | string | |
| type | 默认返回 2,开发者无需关注 | int | |
| result | 返回的结果 | ||
| restriction | 限行结果提示信息 | string | 若无限行路线,则返回空 |
| total | 返回方案的总数 | int | |
| routes | 返回的方案集 | array | |
| restriction_info | 限行状态 | object | status: 限行状态 (0:无限行 1:已规避限行 2:无法规避限行) |
| desc | 限行提示语 | string | |
| origin | 起点 | object | lng: 起点经度; lat: 起点纬度 |
| destination | 终点 | object | lng: 终点经度; lat: 终点纬度 |
| tag | 方案标签 | string | |
| traffic_light | 红绿灯数量 | int | |
| route_id | 路线 ID | string | |
| distance | 方案距离,单位:米 | int | |
| duration | 未来驾车路线耗时,单位:秒 | int | |
| ext_duration | 驾车路线历史耗时(扩展),单位:秒 | int | |
| suggest_departure_time | 建议出发时间,单位:秒 | int64 | |
| taxi_fee | 出租车费用,单位:元 | int | |
| toll | 此路线道路收费,单位:元 | int | |
| toll_distance | 收费路段里程,单位:米 | int | |
| steps | 路线分段 | array | |
| leg_index | 途径点序号 | int | |
| direction | 进入道路的角度 | int | 枚举值 0-11 |
| road_name | 分段的道路名称 | string | |
| road_type | 分段的道路类型 | int | 0:高速路; 1:城市高速路; ... |
| start_location | 分段起点 | object | lng, lat |
| end_location | 分段终点 | object | lng, lat |
| path | 分段坐标 | string | |
| adcodes | 分段途经的城市编码 | string | |
| traffic_condition | 分段路况详情 | array | status: 路况指数 (0:无路况 1:畅通 2:缓行 3:拥堵 4:非常拥堵) |
| end_walkinfo | 终点步导路线 | array | |
| start_walkinfo | 起点步导路线 | array |
本节详细说明如何进行访问接口的创建和本地接口的创建和集成。本节是实际的进行接口调用,并且返回相应的结果实战。
package com.yelang.project.thridinterface;
import com.burukeyou.uniapi.http.annotation.param.QueryPar;
import com.burukeyou.uniapi.http.annotation.request.GetHttpInterface;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
import com.yelang.project.thridinterface.apiprocessor.BaiduHttpApi;
@BaiduHttpApi(snMode = false)
public interface BaiduDrivingV2Service {
@GetHttpInterface(path = "/direction/v2/driving")
public HttpResponse<String> getSearch(@QueryPar("ak") String ak,
@QueryPar("origin") String origin,
@QueryPar("destination") String destination,
@QueryPar("coord_type") String coordType,
@QueryPar("ret_coordtype") String retCoordtype,
@QueryPar("tactics") int tactics,
@QueryPar("alternatives") int alternatives,
@QueryPar("cartype") int cartype,
@QueryPar("speed") float speed,
@QueryPar("steps_info") int stepsInfo);
}
以上参数是根据业务的需求进行定义的,除必填的参数以外,很多选填的参数是可以不定义,直接使用默认值即可。
下面我们以从广东省广州市为起点,驾车开往贵州省铜仁市为例,车速选择匀速 100 公里,车型为普通油车、需要返回备选路线、并且返回下发详情的实例进行接口请求。这里我们使用 Junit 的方式进行集成,核心代码如下:
package com.yelang.project.unihttp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
import com.yelang.common.utils.StringUtils;
import com.yelang.project.thridinterface.BaiduDrivingV2Service;
@SpringBootTest
@RunWith(SpringRunner.class)
public class BaiduDrivingV2ServiceCase {
private static final String BAIDU_CLIENT_AK = "yourak";
@Autowired
private BaiduDrivingV2Service drivingService;
@Test
public void testDriving() {
String origin = "23.115102,113.269043";//出发地:广东省广州市
String destination = "27.728514,109.186249";//目的地:贵州省铜仁市
String coordType = "wgs84";
String retCoordtype = "bd09ll";//返回坐标类型,请跟入参的坐标类型有所区别
int tactics = 0;//默认距离最短
int alternatives = 1;//1 表示返回 1-3 条备选路线
int cartype = 0;//普通油车
float speed = 27.78F;//100 千米/小时 ≈ 27.78 米/秒
int stepsInfo = 1;//下发详情
HttpResponse<String> result = drivingService.getSearch(BAIDU_CLIENT_AK, origin, destination, coordType, retCoordtype, tactics, alternatives, cartype, speed, stepsInfo);
System.out.println(result.getBodyResult());
}
}
在本地 IDE 中运行以上程序后,可以看到以下输出:

在文本编辑器中对返回数据进行 json 格式化后,可以看到如下结构:

这个结构很重要,这个结构是我们下一步进行 Java 对象封装的重要参考资料。
通过上一节,我们已经成功的获取到了百度地图开放平台返回的路径规划结果,数据格式是 json,在实际业务中,我们需要使用 Java 来进行数据的持久化或者数据挖掘,因此需要将 json 反序列化成 JavaBean。这里分别介绍响应类图、以及相应的实现,最后基于 GSON 来进行对象转换说明。
根据前面的响应参数介绍以及在上一小节的真实响应对象的研究,我们大致对返回对象有了一个初印象。整理成如下类图:

根据业务的需要,为了完整的业务数据还原,这里设计 11 个类来对百度地图的路线规划服务接口返回数据进行接收。
公共对象是所有百度公共接口的父类,用来定义响应数据的公共属性,定义如下:
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdCommonDTO implements Serializable {
private static final long serialVersionUID = 4985268844473756688L;
private int status;//状态码 本次 API 访问状态,如果成功返回 0,如果失败返回其他数字。
private String message;//响应信息 对 status 的中文描述
}
驾车路线数据传输类封装了规划的路线信息,核心代码如下:
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import com.yelang.project.meteorology.domain.BdCommonDTO;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString(callSuper=true)
@EqualsAndHashCode(callSuper=true)
public class BdDrivingDTO extends BdCommonDTO implements Serializable{
private static final long serialVersionUID = 5055488530865458258L;
private Integer type;//默认返回 2,开发者无需关注
private BdDrivingResultDTO result;
}
导航信息类包含了分段信息、方案总数、具体的方案路线信息,核心代码如下:
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdDrivingResultDTO implements Serializable{
private static final long serialVersionUID = 6407644142297216118L;
private String restriction;//限行结果提示信息
private int total;//返回方案的总数
@SerializedName("navi_restype")
private String naviRestype;
@SerializedName("session_id")
private String sessionId;
private List<BdDrivingRouteDTO> routes;
private String holiday;
@SerializedName("ret_coordtype")
private String retCoordtype;
@SerializedName("api_restype")
private String apiRestype;
}
具体路线分段信息类,封装了路线详情、距离、打车费用预估、预计时间和具体的转折路线列表,核心代码如下:
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdDrivingRouteDTO implements Serializable{
private static final long serialVersionUID = -2475019111446934340L;
private BdLocationDTO origin;
private BdLocationDTO destination;
private String tag;//方案标签
private String mrsl;
@SerializedName("route_md5")
private String routeMd5;
@SerializedName("data_version")
private String dataVersion;
@SerializedName("traffic_light")
private int trafficLight;
private float distance;//距离,单位米
private int duration;//未来驾车路线耗时,单位:秒
@SerializedName("taxi_fee")
private float taxiFee;
@SerializedName("has_guidance")
private boolean hasGuidance;
private List<BdDrivingStepDTO> steps;//路线分段集合
@SerializedName("restriction_info")
private BdDrivingRestrictionInfoDTO restrictionInfo;
@SerializedName("yellow_tip")
private List<BdDrivingYelloTipDTO> yellowTipList;
private int toll;//此路线道路收费,单位:元
@SerializedName("toll_distance")
private float tollDistance;
private float score;
@SerializedName("route_id")
private String routeId;
}
最后我们将百度开放平台返回的 JSON 数据转换成 Java 对象,转换框架这里以 Gson 为例,其它的 json 框架也是可以的。转换代码如下:
Gson gson = new Gson();
if(StringUtils.isNotEmpty(result.getBodyResult())) {
BdDrivingDTO drivingDTO = gson.fromJson(result.getBodyResult(), BdDrivingDTO.class);
System.out.println(drivingDTO);
System.out.println("---------------------------");
System.out.println(gson.toJson(drivingDTO));
}
运行程序后,可以看到正常的数据输出。后续我们可以基于此和其他应用的结合。
在百度驾车路线规划服务集成过程中,可能会遇到一些问题。比如我在集成过程中就遇到了关于坐标精度和坐标和格式的问题。
众所周知,在地理位置中,经纬度是描述一个点的具体格式。因此我们特别习惯在描述一个点时,使用(经度,纬度)的方式,如:113.269043,23.115102。但是这种方式在实际查询过程中会报以下错误:

解决的办法也比较简单,在百度的位置描述中,将纬度描述在前,即(纬度,经度)即可。
坐标类型永远是 GIS 应用中绕不开的话题,大家可能都以为通用的 WGS84,在接口的参数定义中,我们可以看到,查询参数的坐标是支持 WGS84 的,但是在返回的坐标中,却没有了这个参数支持。如果在返回参数中设置了 WGS84,大概率是会报错的,如下图所示:

解决办法就是按照文档调整参数设置即可。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online