一、高德地图简介
1.1 高德地图概述
高德地图是中国领先的数字地图内容、导航和位置服务解决方案提供商,由阿里巴巴集团控股。它提供了全面的地图服务,包括:
- 基础地图服务:街道、建筑物、地形等地图数据
- 定位服务:gps、基站、wi-fi多重定位
- 地理编码:地址与坐标之间的相互转换
- 路径规划:驾车、步行、骑行、公交路线规划
- 地图展示:2d/3d地图展示、自定义地图样式
- 地点搜索:poi(兴趣点)搜索、周边搜索
- 轨迹服务:车辆轨迹管理和分析
1.2 高德地图服务优势
- 高精度定位:米级到厘米级精确定位
- 丰富api:提供web端、android、ios、服务端全方位sdk
- 实时路况:覆盖全国主要城市的实时交通信息
- 数据更新快:地图数据每周更新
1.3 高德地图应用场景
- 位置服务(lbs)应用
- 物流配送和路径优化
- 出行服务和导航应用
- 地理信息系统(gis)
- 商业分析和选址决策
二、springboot集成高德地图sdk详细步骤
2.1 环境准备
2.1.1 注册高德开发者账号
- 访问高德开放平台
- 注册账号并完成实名认证
- 创建应用,获取api key
2.1.2 创建springboot项目
# 使用spring initializr创建项目 mvn archetype:generate -dgroupid=com.example -dartifactid=amap-demo -darchetypeartifactid=maven-archetype-quickstart -dinteractivemode=false # 或使用spring boot cli spring init --dependencies=web,configuration-processor amap-demo
2.2 项目依赖配置
pom.xml配置
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0"
xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
xsi:schemalocation="http://maven.apache.org/pom/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.7.0</version>
<relativepath/>
</parent>
<groupid>com.example</groupid>
<artifactid>amap-demo</artifactid>
<version>1.0.0</version>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<!-- spring boot web -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<!-- spring boot configuration processor -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-configuration-processor</artifactid>
<optional>true</optional>
</dependency>
<!-- lombok -->
<dependency>
<groupid>org.projectlombok</groupid>
<artifactid>lombok</artifactid>
<optional>true</optional>
</dependency>
<!-- http client -->
<dependency>
<groupid>org.apache.httpcomponents</groupid>
<artifactid>httpclient</artifactid>
<version>4.5.13</version>
</dependency>
<!-- json processing -->
<dependency>
<groupid>com.fasterxml.jackson.core</groupid>
<artifactid>jackson-databind</artifactid>
</dependency>
<!-- test dependencies -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
</project>
2.3 配置文件
application.yml
server:
port: 8080
servlet:
context-path: /api
spring:
application:
name: amap-service
# 高德地图配置
amap:
# 在高德开放平台申请的key
api-key: your-amap-api-key-here
# api基础url
base-url: https://restapi.amap.com/v3
# 地理编码服务路径
geocode-path: /geocode/geo
# 逆地理编码服务路径
regeocode-path: /geocode/regeo
# 路径规划服务路径
direction-path: /direction/driving
# ip定位服务路径
ip-locate-path: /ip
# 天气查询服务路径
weather-path: /weather/weatherinfo
# 签名密钥(可选)
sig-key:
# 返回数据格式
output: json
2.4 核心代码实现
2.4.1 配置类
package com.example.amap.config;
import lombok.data;
import org.springframework.boot.context.properties.configurationproperties;
import org.springframework.context.annotation.configuration;
@data
@configuration
@configurationproperties(prefix = "amap")
public class amapproperties {
private string apikey;
private string baseurl;
private string geocodepath;
private string regeocodepath;
private string directionpath;
private string iplocatepath;
private string weatherpath;
private string sigkey;
private string output = "json";
public string getgeocodeurl() {
return baseurl + geocodepath;
}
public string getregeocodeurl() {
return baseurl + regeocodepath;
}
public string getdirectionurl() {
return baseurl + directionpath;
}
public string getiplocateurl() {
return baseurl + iplocatepath;
}
public string getweatherurl() {
return baseurl + weatherpath;
}
}
2.4.2 http客户端配置
package com.example.amap.config;
import org.apache.http.client.config.requestconfig;
import org.apache.http.impl.client.closeablehttpclient;
import org.apache.http.impl.client.httpclientbuilder;
import org.apache.http.impl.conn.poolinghttpclientconnectionmanager;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.http.client.clienthttprequestfactory;
import org.springframework.http.client.httpcomponentsclienthttprequestfactory;
import org.springframework.web.client.resttemplate;
@configuration
public class httpclientconfig {
@bean
public resttemplate resttemplate() {
return new resttemplate(httprequestfactory());
}
@bean
public clienthttprequestfactory httprequestfactory() {
return new httpcomponentsclienthttprequestfactory(httpclient());
}
@bean
public closeablehttpclient httpclient() {
poolinghttpclientconnectionmanager connectionmanager =
new poolinghttpclientconnectionmanager();
connectionmanager.setmaxtotal(200);
connectionmanager.setdefaultmaxperroute(50);
requestconfig requestconfig = requestconfig.custom()
.setsockettimeout(10000)
.setconnecttimeout(5000)
.setconnectionrequesttimeout(5000)
.build();
return httpclientbuilder.create()
.setconnectionmanager(connectionmanager)
.setdefaultrequestconfig(requestconfig)
.build();
}
}
2.4.3 服务层实现
package com.example.amap.service;
import com.example.amap.config.amapproperties;
import com.example.amap.model.*;
import com.fasterxml.jackson.databind.jsonnode;
import com.fasterxml.jackson.databind.objectmapper;
import lombok.requiredargsconstructor;
import lombok.extern.slf4j.slf4j;
import org.springframework.http.responseentity;
import org.springframework.stereotype.service;
import org.springframework.web.client.resttemplate;
import org.springframework.web.util.uricomponentsbuilder;
import java.net.uri;
import java.util.hashmap;
import java.util.map;
@slf4j
@service
@requiredargsconstructor
public class amapservice {
private final resttemplate resttemplate;
private final amapproperties amapproperties;
private final objectmapper objectmapper;
/**
* 地理编码:地址转坐标
*/
public georesult geocode(string address, string city) {
map<string, string> params = new hashmap<>();
params.put("key", amapproperties.getapikey());
params.put("address", address);
if (city != null && !city.isempty()) {
params.put("city", city);
}
string url = buildurl(amapproperties.getgeocodeurl(), params);
log.info("请求地理编码api: {}", url);
responseentity<string> response = resttemplate.getforentity(url, string.class);
return parsegeoresult(response.getbody());
}
/**
* 逆地理编码:坐标转地址
*/
public regeoresult regeocode(string location) {
map<string, string> params = new hashmap<>();
params.put("key", amapproperties.getapikey());
params.put("location", location);
params.put("extensions", "all"); // 返回详细信息
string url = buildurl(amapproperties.getregeocodeurl(), params);
log.info("请求逆地理编码api: {}", url);
responseentity<string> response = resttemplate.getforentity(url, string.class);
return parseregeoresult(response.getbody());
}
/**
* 路径规划
*/
public directionresult direction(string origin, string destination, string strategy) {
map<string, string> params = new hashmap<>();
params.put("key", amapproperties.getapikey());
params.put("origin", origin);
params.put("destination", destination);
params.put("strategy", strategy != null ? strategy : "0"); // 0:速度优先
string url = buildurl(amapproperties.getdirectionurl(), params);
log.info("请求路径规划api: {}", url);
responseentity<string> response = resttemplate.getforentity(url, string.class);
return parsedirectionresult(response.getbody());
}
/**
* ip定位
*/
public iplocateresult iplocate(string ip) {
map<string, string> params = new hashmap<>();
params.put("key", amapproperties.getapikey());
params.put("ip", ip != null ? ip : "");
string url = buildurl(amapproperties.getiplocateurl(), params);
log.info("请求ip定位api: {}", url);
responseentity<string> response = resttemplate.getforentity(url, string.class);
return parseiplocateresult(response.getbody());
}
/**
* 天气查询
*/
public weatherresult weather(string city, string extensions) {
map<string, string> params = new hashmap<>();
params.put("key", amapproperties.getapikey());
params.put("city", city);
params.put("extensions", extensions != null ? extensions : "base"); // base:实时天气
string url = buildurl(amapproperties.getweatherurl(), params);
log.info("请求天气查询api: {}", url);
responseentity<string> response = resttemplate.getforentity(url, string.class);
return parseweatherresult(response.getbody());
}
/**
* 构建请求url
*/
private string buildurl(string baseurl, map<string, string> params) {
uricomponentsbuilder builder = uricomponentsbuilder.fromhttpurl(baseurl);
params.foreach(builder::queryparam);
return builder.build().touristring();
}
/**
* 解析地理编码结果
*/
private georesult parsegeoresult(string json) {
try {
jsonnode root = objectmapper.readtree(json);
georesult result = new georesult();
result.setstatus(root.get("status").astext());
result.setinfo(root.get("info").astext());
if ("1".equals(result.getstatus())) {
jsonnode geocodes = root.get("geocodes");
if (geocodes != null && geocodes.isarray() && geocodes.size() > 0) {
jsonnode first = geocodes.get(0);
geocode geocode = new geocode();
geocode.setformattedaddress(first.get("formatted_address").astext());
geocode.setcountry(first.get("country").astext());
geocode.setprovince(first.get("province").astext());
geocode.setcity(first.get("city").astext());
geocode.setdistrict(first.get("district").astext());
string location = first.get("location").astext();
if (location.contains(",")) {
string[] coords = location.split(",");
geocode.setlongitude(double.parsedouble(coords[0]));
geocode.setlatitude(double.parsedouble(coords[1]));
}
result.setgeocode(geocode);
}
}
return result;
} catch (exception e) {
log.error("解析地理编码结果失败", e);
return null;
}
}
/**
* 解析逆地理编码结果
*/
private regeoresult parseregeoresult(string json) {
try {
jsonnode root = objectmapper.readtree(json);
regeoresult result = new regeoresult();
result.setstatus(root.get("status").astext());
result.setinfo(root.get("info").astext());
if ("1".equals(result.getstatus())) {
jsonnode regeocode = root.get("regeocode");
if (regeocode != null) {
regeocode regeocode = new regeocode();
regeocode.setformattedaddress(regeocode.get("formatted_address").astext());
result.setregeocode(regeocode);
}
}
return result;
} catch (exception e) {
log.error("解析逆地理编码结果失败", e);
return null;
}
}
// 其他解析方法类似,限于篇幅省略...
}
2.4.4 数据模型
package com.example.amap.model;
import lombok.data;
import java.util.list;
@data
public class georesult {
private string status;
private string info;
private geocode geocode;
}
@data
class geocode {
private string formattedaddress;
private string country;
private string province;
private string city;
private string district;
private double longitude;
private double latitude;
}
@data
public class regeoresult {
private string status;
private string info;
private regeocode regeocode;
}
@data
class regeocode {
private string formattedaddress;
private addresscomponent addresscomponent;
}
@data
class addresscomponent {
private string province;
private string city;
private string district;
private string township;
}
@data
public class directionresult {
private string status;
private string info;
private route route;
}
@data
class route {
private list<path> paths;
}
@data
class path {
private double distance;
private double duration;
private string strategy;
private string tolls;
private string restriction;
private string trafficlights;
}
@data
public class iplocateresult {
private string status;
private string info;
private string province;
private string city;
private string adcode;
private string rectangle;
}
@data
public class weatherresult {
private string status;
private string info;
private string count;
private list<liveweather> lives;
private list<forecastweather> forecasts;
}
@data
class liveweather {
private string province;
private string city;
private string adcode;
private string weather;
private string temperature;
private string winddirection;
private string windpower;
private string humidity;
private string reporttime;
}
@data
class forecastweather {
private string city;
private string adcode;
private string province;
private string reporttime;
private list<cast> casts;
}
@data
class cast {
private string date;
private string week;
private string dayweather;
private string nightweather;
private string daytemp;
private string nighttemp;
private string daywind;
private string nightwind;
private string daypower;
private string nightpower;
}
2.4.5 控制器层
package com.example.amap.controller;
import com.example.amap.model.*;
import com.example.amap.service.amapservice;
import lombok.requiredargsconstructor;
import org.springframework.web.bind.annotation.*;
@restcontroller
@requestmapping("/amap")
@requiredargsconstructor
public class amapcontroller {
private final amapservice amapservice;
/**
* 地址转坐标
*/
@getmapping("/geocode")
public apiresponse<georesult> geocode(
@requestparam string address,
@requestparam(required = false) string city) {
georesult result = amapservice.geocode(address, city);
return apiresponse.success(result);
}
/**
* 坐标转地址
*/
@getmapping("/regeocode")
public apiresponse<regeoresult> regeocode(@requestparam string location) {
regeoresult result = amapservice.regeocode(location);
return apiresponse.success(result);
}
/**
* 路径规划
*/
@getmapping("/direction")
public apiresponse<directionresult> direction(
@requestparam string origin,
@requestparam string destination,
@requestparam(required = false) string strategy) {
directionresult result = amapservice.direction(origin, destination, strategy);
return apiresponse.success(result);
}
/**
* ip定位
*/
@getmapping("/ip-locate")
public apiresponse<iplocateresult> iplocate(@requestparam(required = false) string ip) {
iplocateresult result = amapservice.iplocate(ip);
return apiresponse.success(result);
}
/**
* 天气查询
*/
@getmapping("/weather")
public apiresponse<weatherresult> weather(
@requestparam string city,
@requestparam(required = false) string extensions) {
weatherresult result = amapservice.weather(city, extensions);
return apiresponse.success(result);
}
}
/**
* 统一api响应格式
*/
@data
class apiresponse<t> {
private int code;
private string message;
private t data;
private long timestamp;
public static <t> apiresponse<t> success(t data) {
apiresponse<t> response = new apiresponse<>();
response.setcode(200);
response.setmessage("success");
response.setdata(data);
response.settimestamp(system.currenttimemillis());
return response;
}
public static <t> apiresponse<t> error(int code, string message) {
apiresponse<t> response = new apiresponse<>();
response.setcode(code);
response.setmessage(message);
response.settimestamp(system.currenttimemillis());
return response;
}
}
2.4.6 全局异常处理
package com.example.amap.exception;
import com.example.amap.controller.apiresponse;
import lombok.extern.slf4j.slf4j;
import org.springframework.web.bind.annotation.exceptionhandler;
import org.springframework.web.bind.annotation.restcontrolleradvice;
@slf4j
@restcontrolleradvice
public class globalexceptionhandler {
@exceptionhandler(exception.class)
public apiresponse<object> handleexception(exception e) {
log.error("系统异常", e);
return apiresponse.error(500, e.getmessage());
}
@exceptionhandler(amapexception.class)
public apiresponse<object> handleamapexception(amapexception e) {
log.error("高德地图服务异常", e);
return apiresponse.error(e.getcode(), e.getmessage());
}
}
class amapexception extends runtimeexception {
private int code;
public amapexception(int code, string message) {
super(message);
this.code = code;
}
public int getcode() {
return code;
}
}
2.4.7 启动类
package com.example.amap;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.boot.context.properties.enableconfigurationproperties;
@springbootapplication
@enableconfigurationproperties
public class amapapplication {
public static void main(string[] args) {
springapplication.run(amapapplication.class, args);
}
}
2.5 测试示例
package com.example.amap.test;
import com.example.amap.amapapplication;
import com.example.amap.service.amapservice;
import lombok.extern.slf4j.slf4j;
import org.junit.jupiter.api.test;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.boot.test.context.springboottest;
@slf4j
@springboottest(classes = amapapplication.class)
public class amapservicetest {
@autowired
private amapservice amapservice;
@test
void testgeocode() {
var result = amapservice.geocode("北京市朝阳区阜通东大街6号", "北京");
log.info("地理编码结果: {}", result);
}
@test
void testregeocode() {
var result = amapservice.regeocode("116.481488,39.990464");
log.info("逆地理编码结果: {}", result);
}
@test
void testdirection() {
var result = amapservice.direction("116.481488,39.990464", "116.434307,39.90909", "0");
log.info("路径规划结果: {}", result);
}
}
三、详细总结
3.1 集成要点总结
技术架构优势
- 微服务友好:通过resttemplate封装,易于集成到微服务架构
- 配置灵活:使用spring boot配置属性,支持多环境配置
- 性能优化:http连接池配置,提高并发性能
- 异常处理:统一的异常处理机制,提高系统稳定性
- 日志完善:完整的日志记录,便于问题排查
安全性考虑
- api key保护:配置文件中存储,避免硬编码
- 请求签名:支持sig参数,提高接口安全性
- 输入验证:对用户输入进行校验,防止非法参数
- 限流机制:可结合redis实现api调用限流
3.2 最佳实践建议
性能优化
// 1. 使用缓存减少重复请求
@cacheable(value = "geocodecache", key = "#address + '-' + #city")
public georesult geocode(string address, string city) {
// 实现逻辑
}
// 2. 异步调用提高响应速度
@async
public completablefuture<georesult> geocodeasync(string address, string city) {
return completablefuture.completedfuture(geocode(address, city));
}
// 3. 批量处理接口
public list<georesult> batchgeocode(list<addressrequest> requests) {
return requests.stream()
.map(req -> geocode(req.getaddress(), req.getcity()))
.collect(collectors.tolist());
}
监控与告警
// 添加监控指标
@component
public class amapmetrics {
private final meterregistry meterregistry;
private final counter successcounter;
private final counter failurecounter;
private final timer apitimer;
public amapmetrics(meterregistry meterregistry) {
this.meterregistry = meterregistry;
this.successcounter = counter.builder("amap.api.calls")
.tag("status", "success")
.register(meterregistry);
this.failurecounter = counter.builder("amap.api.calls")
.tag("status", "failure")
.register(meterregistry);
this.apitimer = timer.builder("amap.api.duration")
.register(meterregistry);
}
public void recordsuccess(long duration) {
successcounter.increment();
apitimer.record(duration, timeunit.milliseconds);
}
}
3.3 扩展功能
- 地理围栏服务:实现电子围栏监控
- 轨迹分析:车辆轨迹管理和分析
- 热力图生成:基于位置数据的可视化
- 地址标准化:地址数据清洗和标准化
- 智能推荐:基于位置的商家推荐
3.4 注意事项
- api调用限制:注意高德地图api的调用频率限制
- 错误码处理:完整处理高德地图返回的错误码
- 服务降级:在api服务不可用时实现降级策略
- 数据一致性:考虑数据更新和缓存的同步问题
- 合规性:确保应用符合国家的地理信息安全规定
3.5 部署
- 多环境配置:开发、测试、生产环境使用不同的api key
- 密钥轮换:定期更新api key,提高安全性
- 监控告警:设置api调用异常告警
- 文档完善:编写详细的api使用文档
- 压力测试:上线前进行充分的压力测试
通过以上完整的集成方案,springboot应用可以高效、稳定地集成高德地图sdk,为业务提供丰富的位置服务功能。
以上就是springboot集成高德地图sdk的详细步骤的详细内容,更多关于springboot集成高德地图sdk的资料请关注代码网其它相关文章!
发表评论