package com.estate.expert.admin.component.map;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
import org.springframework.web.client.RestTemplate;
|
|
/**
|
* 地理位置翻译组件
|
*
|
* <p>该组件提供地址到地理坐标的转换功能,基于高德地图API实现。
|
* 主要用于将中文地址转换为精确的经纬度坐标,支持各种基于位置的服务。</p>
|
*
|
* <p>主要功能:</p>
|
* <ul>
|
* <li>地址解析:将文本地址转换为地理坐标</li>
|
* <li>坐标获取:提供精确的经纬度信息</li>
|
* <li>位置服务:支持地图定位和导航功能</li>
|
* </ul>
|
*
|
* <p>技术特点:</p>
|
* <ul>
|
* <li>基于高德地图Web服务API</li>
|
* <li>支持中文地址解析</li>
|
* <li>提供高精度的地理坐标</li>
|
* <li>包含完整的错误处理机制</li>
|
* </ul>
|
*
|
* <p>使用场景:</p>
|
* <ul>
|
* <li>工程项目位置定位</li>
|
* <li>设备安装位置记录</li>
|
* <li>安全检查地点标记</li>
|
* <li>地图可视化展示</li>
|
* </ul>
|
*
|
* @author daisy
|
* @since 2023/10/29
|
*/
|
@Slf4j
|
@Component
|
public class GeoTranslateComponent {
|
|
/**
|
* 高德地图地理编码API地址
|
*
|
* <p>高德地图提供的地理编码服务接口,用于将地址转换为地理坐标。</p>
|
*
|
* <p>API说明:</p>
|
* <ul>
|
* <li>服务类型:RESTful Web API</li>
|
* <li>请求方式:HTTP GET</li>
|
* <li>响应格式:JSON</li>
|
* <li>坐标系统:WGS84</li>
|
* </ul>
|
*
|
* <p>请求参数:</p>
|
* <ul>
|
* <li>address:待解析的地址(必填)</li>
|
* <li>key:API密钥(必填)</li>
|
* </ul>
|
*
|
* <p>API文档:https://lbs.amap.com/api/webservice/guide/api/georegeo</p>
|
*/
|
private static final String MAP_API_URL = "https://restapi.amap.com/v3/geocode/geo";
|
|
/**
|
* 高德地图API密钥
|
*
|
* <p>用于访问高德地图服务的认证密钥,从配置文件中读取。</p>
|
*
|
* <p>配置说明:</p>
|
* <ul>
|
* <li>配置文件:application.yml</li>
|
* <li>配置项:map.api.key</li>
|
* <li>默认值:5ad97434d47b7cc74b4145d5509d28d2</li>
|
* </ul>
|
*
|
* <p>安全注意事项:</p>
|
* <ul>
|
* <li>API密钥应妥善保管,避免泄露</li>
|
* <li>建议在生产环境中使用环境变量或加密配置</li>
|
* <li>定期检查和更新API密钥</li>
|
* </ul>
|
*/
|
@Value("${map.api.key}")
|
private final String API_KEY = "5ad97434d47b7cc74b4145d5509d28d2";
|
|
/**
|
* HTTP客户端模板
|
*
|
* <p>用于发送HTTP请求到高德地图API服务。
|
* Spring RestTemplate提供了便捷的HTTP客户端功能。</p>
|
*/
|
RestTemplate restTemplate = new RestTemplate();
|
|
/**
|
* 地址转坐标方法
|
*
|
* <p>该方法将文本地址转换为地理坐标(经纬度),支持中文地址解析。
|
* 通过调用高德地图地理编码API实现地址到坐标的转换。</p>
|
*
|
* <p>处理流程:</p>
|
* <ol>
|
* <li>构建API请求URL,包含地址和API密钥参数</li>
|
* <li>发送HTTP GET请求到高德地图API</li>
|
* <li>解析JSON响应数据</li>
|
* <li>提取第一个地理编码结果的坐标信息</li>
|
* <li>将坐标字符串解析为Double数组</li>
|
* <li>处理异常情况并返回null</li>
|
* </ol>
|
*
|
* <p>坐标格式:</p>
|
* <ul>
|
* <li>返回数组:[经度, 纬度]</li>
|
* <li>经度范围:-180.0 到 180.0</li>
|
* <li>纬度范围:-90.0 到 90.0</li>
|
* <li>精度:通常精确到小数点后6位</li>
|
* </ul>
|
*
|
* <p>异常处理:</p>
|
* <ul>
|
* <li>网络异常:记录错误日志,返回null</li>
|
* <li>API错误:记录错误信息,返回null</li>
|
* <li>解析异常:记录解析错误,返回null</li>
|
* <li>空结果:当API返回空结果时,返回null</li>
|
* </ul>
|
*
|
* @param address 待解析的地址文本,支持中文地址
|
* @return Double[] 坐标数组,格式为[经度, 纬度],解析失败时返回null
|
*
|
* @see GeoResponse API响应格式说明
|
*
|
* <p>使用示例:</p>
|
* <pre>
|
* GeoTranslateComponent component = new GeoTranslateComponent();
|
* Double[] coords = component.translate("北京市朝阳区阜通东大街6号");
|
* if (coords != null) {
|
* double longitude = coords[0]; // 经度
|
* double latitude = coords[1]; // 纬度
|
* }
|
* </pre>
|
*/
|
public Double[] translate(String address) {
|
try {
|
// 构建API请求URL
|
String url = MAP_API_URL + "?address=" + address + "&key=" + API_KEY;
|
log.debug("发送地理编码请求: {}", url);
|
|
// 发送HTTP GET请求并获取响应
|
var response = restTemplate.getForObject(url, GeoResponse.class);
|
|
// 检查响应数据是否有效
|
if (response != null && response.getGeocodes() != null && !response.getGeocodes().isEmpty()) {
|
// 获取第一个地理编码结果的坐标字符串
|
var location = response.getGeocodes().get(0).getLocation();
|
log.debug("获取到坐标: {}", location);
|
|
// 解析坐标字符串为Double数组
|
var locationArray = location.split(",");
|
if (locationArray.length >= 2) {
|
double longitude = Double.parseDouble(locationArray[0]);
|
double latitude = Double.parseDouble(locationArray[1]);
|
log.info("地址 '{}' 解析成功: 经度={}, 纬度={}", address, longitude, latitude);
|
return new Double[]{longitude, latitude};
|
} else {
|
log.warn("坐标格式无效: {}", location);
|
}
|
} else {
|
log.warn("地址 '{}' 未找到匹配的地理编码结果", address);
|
}
|
|
} catch (Exception e) {
|
// 记录详细的错误信息
|
log.error("地理编码API请求失败, 地址: {}, 错误: {}", address, e.getMessage(), e);
|
}
|
|
// 异常情况下返回null
|
return null;
|
}
|
|
/**
|
* 测试方法 - 地址转坐标示例
|
*
|
* <p>该方法演示了如何使用地理编码组件进行地址到坐标的转换。
|
* 适用于功能测试和开发调试。</p>
|
*
|
* <p>测试地址:</p>
|
* <ul>
|
* <li>示例地址:北京市朝阳区阜通东大街6号</li>
|
* <li>预期结果:返回该地址的精确经纬度坐标</li>
|
* </ul>
|
*
|
* <p>使用说明:</p>
|
* <ul>
|
* <li>该方法主要用于功能测试和演示</li>
|
* <li>实际使用时需要根据具体需求调整地址参数</li>
|
* <li>建议在生产环境中移除或注释掉此方法</li>
|
* </ul>
|
*/
|
public static void main(String[] args) {
|
// 创建地理编码组件实例
|
GeoTranslateComponent component = new GeoTranslateComponent();
|
|
// 测试地址转坐标功能
|
var result = component.translate("北京市朝阳区阜通东大街6号");
|
|
// 输出结果
|
if (result != null) {
|
System.out.println("地址解析成功:");
|
System.out.println("经度: " + result[0]);
|
System.out.println("纬度: " + result[1]);
|
} else {
|
System.out.println("地址解析失败");
|
}
|
}
|
|
}
|