Java 集成百度地图 API 实现实时路况检索
在开发涉及位置服务的系统时,实时获取道路拥堵情况往往是个刚需。本文以长沙市为例,演示如何通过 Java 调用百度地图 Traffic API,实现对热门道路与景点的实时路况查询。
实时路况服务简介
百度地图提供了 Traffic API 接口,支持分钟级更新的路况数据。主要包含两种查询模式:
- 道路实时路况:根据具体道路名称查询拥堵状态。
- 周边实时路况:根据中心点坐标和半径查询周围路网情况。
这两个接口返回的数据结构基本一致,便于统一封装处理。
请求参数说明
道路实时路况查询
| 参数名称 | 含义 | 类型 | 必填 |
|---|---|---|---|
| ak | 开发者访问密钥 | string | 是 |
| road_name | 道路名称(如'北五环') | string | 是 |
| city | 城市名称或 adcode | string | 是 |
| sn | SN 校验签名(可选) | - | 否 |
注意:多方向立交桥和多方向道路可能不支持精确查询。
周边实时路况查询
| 参数名称 | 含义 | 类型 | 必填 |
|---|---|---|---|
| center | 中心点坐标(纬度,经度) | string | 是 |
| radius | 查询半径(米) | int | 是 |
| coord_type_input | 输入坐标类型 | string | 否 |
| coord_type_output | 输出坐标类型 | string | 否 |
返回数据结构
无论哪种查询方式,返回的 JSON 结构都包含状态码、整体评估及详细路段信息。核心字段包括 status(状态)、description(语义化描述)、evaluation(整体评价)以及 road_traffic(具体路段列表)。其中 road_traffic 数组中包含了每条路的拥堵趋势、平均速度和拥堵距离等关键指标。
Java 响应对象封装
为了简化数据处理,建议将 API 返回的 JSON 映射为 Java 对象。这里使用 Lombok 简化代码,并配合 Gson 进行反序列化。
公共基础类
首先定义一个父类,用于承载通用的状态信息。
package com.yelang.project.meteorology.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdCommonDTO {
private int status; // 状态码,0 表示成功
private String message; // 响应信息
}
路况详情对象
主对象继承自公共类,包含路况的整体评估和具体路段列表。
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.*;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BdTrafficDTO extends BdCommonDTO implements Serializable {
private static final long serialVersionUID = -5247239994807521257L;
private String description; // 路况语义化描述
private BdTrafficEvaluation evaluation; // 整体评估
@SerializedName("road_traffic")
private List<BdRoadTrafficDetail> roadTraffic; // 详细路段列表
}
细分对象
针对整体评估和具体路段,分别建立对应的 DTO 类。
// BdTrafficEvaluation.java
package com.yelang.project.meteorology.domain;
import com.google.gson.annotations.SerializedName;
import lombok.*;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdTrafficEvaluation implements Serializable {
private int status; // 0:未知 1:畅通 2:缓行 3:拥堵 4:严重拥堵
@SerializedName("status_desc")
private String statusDesc; // 语义化描述
}
// BdRoadTrafficDetail.java
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.*;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdRoadTrafficDetail implements Serializable {
private static final long serialVersionUID = 3662254110577542026L;
@SerializedName("road_name")
private String roadName; // 道路名称
@SerializedName("congestion_sections")
private List<BdTrafficCongestionSection> congestionSections; // 拥堵路段详情
}
// BdTrafficCongestionSection.java
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
import lombok.*;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdTrafficCongestionSection implements Serializable {
private static final long serialVersionUID = 6723821728526157035L;
@SerializedName("section_desc")
private String sectionDesc; // 路段描述
private int status; // 拥堵等级
private double speed; // 平均速度 (km/h)
@SerializedName("congestion_distance")
private int congestionDistance; // 拥堵距离 (米)
@SerializedName("congestion_trend")
private String congestionTrend; // 拥堵趋势
}
UniHttp 集成及调用
在实际项目中,我们通常使用 HTTP 客户端工具来发起请求。这里以 UniHttp 为例,展示如何声明接口并进行调用。
接口声明
定义一个接口来映射百度地图的 Traffic API 路径。注意配置 snMode = false,因为示例中未启用 SN 签名校验。
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 BaiduTrafficService {
/**
* 道路路况查询
*/
@GetHttpInterface(path = "/traffic/v1/road")
HttpResponse<String> roadTraffic(
@QueryPar("road_name") String roadName,
@QueryPar("city") String city,
@QueryPar("ak") String ak
);
/**
* 周边路况查询
*/
@GetHttpInterface(path = "/traffic/v1/around")
HttpResponse<String> aroundTraffic(
@QueryPar("center") String center,
@QueryPar("radius") int radius,
@QueryPar("road_grade") int roadGrade,
@QueryPar("coord_type_input") String coordTypeInput,
@QueryPar("coord_type_output") String coordTypeOutput,
@QueryPar("ak") String ak
);
}
测试调用示例
下面是一个简单的单元测试,演示如何批量查询长沙市的几条主干道。
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.google.gson.Gson;
import com.yelang.common.utils.StringUtils;
import com.yelang.project.meteorology.domain.BdTrafficDTO;
import com.yelang.project.thridinterface.BaiduTrafficService;
@SpringBootTest
@RunWith(SpringRunner.class)
public class BaiduTrafficServiceCase {
private static final String BAIDU_DEFAULT_AK = "yourak";
@Autowired
private BaiduTrafficService trafficService;
private static final String DEFAULT_CITY = "长沙市";
@Test
public void testRoadTraffic() throws InterruptedException {
String[] roadArray = {"三一大道", "南湖路", "五一大道", "枫林三路", "芙蓉中路"};
Gson gson = new Gson();
for (String road : roadArray) {
HttpResponse<String> result = trafficService.roadTraffic(road, DEFAULT_CITY, BAIDU_DEFAULT_AK);
if (StringUtils.isNotEmpty(result.getBodyResult())) {
BdTrafficDTO trafficDTO = gson.fromJson(result.getBodyResult(), BdTrafficDTO.class);
System.out.println(trafficDTO);
}
Thread.sleep(1500L); // 避免请求过快被限流
}
}
}
对于周边查询,需要先将地点转换为经纬度坐标。注意坐标顺序必须是 纬度,经度,且输入输出坐标类型要匹配。
@Test
public void testAroundTraffic() throws InterruptedException {
// 橘子洲景区、芙蓉广场地铁站、岳麓山风景区、湖南省博物馆
String[] centers = {
"28.198986,112.95722",
"28.198243,112.978962",
"28.196981,112.943391",
"28.215134,112.986896"
};
Gson gson = new Gson();
int radius = 100;
int roadGrade = 0; // 全部驾车道路
String coordTypeInput = "wgs84";
String coordTypeOutput = "bd09ll";
for (String center : centers) {
HttpResponse<String> result = trafficService.aroundTraffic(
center, radius, roadGrade, coordTypeInput, coordTypeOutput, BAIDU_DEFAULT_AK
);
if (StringUtils.isNotEmpty(result.getBodyResult())) {
BdTrafficDTO trafficDTO = gson.fromJson(result.getBodyResult(), BdTrafficDTO.class);
System.out.println(trafficDTO);
}
Thread.sleep(1500L);
}
}
常见问题排查
在接入过程中,以下几个坑点值得注意:
1. 道路名称不匹配
百度地图的路网数据有标准命名。例如'五一路'在系统中可能被记录为'五一大道'。如果查询失败,会返回 road_name 错误。建议先通过官方地点提示接口确认标准名称。
2. 坐标格式问题
周边查询对坐标格式非常敏感。常见错误包括:
- 经纬度顺序颠倒(应为 纬度,经度)。
- 坐标串中包含空格。
- 坐标类型标识错误(如 GPS 坐标应选
wgs84,而非gps)。
3. 返回坐标类型限制
虽然输入可以指定多种坐标类型,但返回结果的 coord_type_output 目前仅支持 bd09ll 和 gcj02,不支持 wgs84。如果业务需要 WGS84 坐标,需在本地进行转换。
4. 参数命名差异
请求参数中的道路等级叫 road_grade,但在部分返回数据中可能对应 road_type。虽然不影响解析,但保持命名一致性有助于维护。
总结
通过上述步骤,我们完成了从 API 选型、对象封装到实际调用的全过程。利用 Java 结合百度地图 Traffic API,可以快速构建出具备实时路况感知能力的功能模块。只要处理好坐标转换和参数校验,这套方案能很好地服务于导航优化、出行规划等场景。


