/* * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ package org.sxkj.gd.utils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springblade.core.tool.utils.StringUtil; import org.springframework.web.client.RestTemplate; import java.net.URI; import java.nio.charset.StandardCharsets; import org.springframework.web.util.UriUtils; @Slf4j public class GdGeoAddressUtil { private static final Logger logger = LoggerFactory.getLogger(GdGeoAddressUtil.class); private static final String TIAN_DI_TU_KEY = "9171789c872b8cfee7bba45c35a6b955"; private static final String TIAN_DI_TU_URL = "https://api.tianditu.gov.cn/geocoder"; private static final RestTemplate REST_TEMPLATE = new RestTemplate(); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static String getFormattedAddress(Double longitude, Double latitude) { if (longitude == null || latitude == null) { return null; } try { String postStr = String.format("{'lon':%s,'lat':%s,'ver':1}", longitude, latitude); String address = requestAddress(postStr); return StringUtil.isBlank(address) ? null : address; } catch (Exception e) { logger.warn("天地图逆地理编码调用失败", e); return null; } } /** * 根据经纬度获取区县代码 * @param longitude 经度 * @param latitude 纬度 * @return 区县代码(已去除156国家代码前缀) */ public static String getCountyCode(Double longitude, Double latitude) { if (longitude == null || latitude == null) { return null; } try { String postStr = String.format("{'lon':%s,'lat':%s,'ver':1}", longitude, latitude); String countyCode = requestCountyCode(postStr); // 去除156国家代码前缀 return StringUtil.isBlank(countyCode) ? null : removeCountryCodePrefix(countyCode); } catch (Exception e) { logger.warn("天地图逆地理编码获取区县代码失败", e); return null; } } /** * 根据经纬度获取街道代码 * @param longitude 经度 * @param latitude 纬度 * @return 街道代码(已去除156国家代码前缀) */ public static String getTownCode(Double longitude, Double latitude) { if (longitude == null || latitude == null) { return null; } try { String postStr = String.format("{'lon':%s,'lat':%s,'ver':1}", longitude, latitude); String townCode = requestTownCode(postStr); // 去除156国家代码前缀 return StringUtil.isBlank(townCode) ? null : removeCountryCodePrefix(townCode); } catch (Exception e) { logger.warn("天地图逆地理编码获取街道代码失败", e); return null; } } /** * 去除行政区划代码中的156国家代码前缀 * @param code 原始行政区划代码 * @return 去除156前缀后的代码 */ private static String removeCountryCodePrefix(String code) { if (StringUtil.isBlank(code)) { return code; } // 156是中国的国家代码,去除前缀 return code.startsWith("156") ? code.substring(3) : code; } private static String requestAddress(String postStr) { String encodedPostStr = UriUtils.encodeQueryParam(postStr, StandardCharsets.UTF_8); String url = TIAN_DI_TU_URL + "?postStr=" + encodedPostStr + "&type=geocode&tk=" + TIAN_DI_TU_KEY; URI uri = URI.create(url); log.info("天地图逆地理编码请求地址:{}", url); String response = REST_TEMPLATE.getForObject(uri, String.class); if (StringUtil.isBlank(response)) { return null; } try { log.info("天地图逆地理编码结果:{}", response); JsonNode root = OBJECT_MAPPER.readTree(response); String address = root.path("result").path("formatted_address").asText(); return StringUtil.isBlank(address) ? null : address; } catch (Exception e) { logger.warn("解析天地图逆地理编码结果失败", e); return null; } } /** * 请求天地图API获取区县代码 * @param postStr 请求参数 * @return 区县代码 */ private static String requestCountyCode(String postStr) { String encodedPostStr = UriUtils.encodeQueryParam(postStr, StandardCharsets.UTF_8); String url = TIAN_DI_TU_URL + "?postStr=" + encodedPostStr + "&type=geocode&tk=" + TIAN_DI_TU_KEY; URI uri = URI.create(url); String response = REST_TEMPLATE.getForObject(uri, String.class); if (StringUtil.isBlank(response)) { return null; } try { log.info("天地图逆地理编码结果:{}", response); JsonNode root = OBJECT_MAPPER.readTree(response); String countyCode = root.path("result").path("addressComponent").path("county_code").asText(); return StringUtil.isBlank(countyCode) ? null : countyCode; } catch (Exception e) { logger.warn("解析天地图逆地理编码区县代码失败", e); return null; } } /** * 请求天地图API获取街道代码 * @param postStr 请求参数 * @return 街道代码 */ private static String requestTownCode(String postStr) { // 步骤1:构建请求URL String encodedPostStr = UriUtils.encodeQueryParam(postStr, StandardCharsets.UTF_8); String url = TIAN_DI_TU_URL + "?postStr=" + encodedPostStr + "&type=geocode&tk=" + TIAN_DI_TU_KEY; URI uri = URI.create(url); // 步骤2:发送HTTP请求 String response = REST_TEMPLATE.getForObject(uri, String.class); if (StringUtil.isBlank(response)) { return null; } // 步骤3:解析JSON响应 try { log.info("天地图逆地理编码结果:{}", response); JsonNode root = OBJECT_MAPPER.readTree(response); // 步骤4:提取街道代码 String townCode = root.path("result").path("addressComponent").path("town_code").asText(); return StringUtil.isBlank(townCode) ? null : townCode; } catch (Exception e) { logger.warn("解析天地图逆地理编码街道代码失败", e); return null; } } // public static void main(String[] args) { // String formattedAddress = getFormattedAddress(116.39742, 39.90923); // String countyCode = getCountyCode(116.39742, 39.90923); // System.out.println("地址:" + formattedAddress); // System.out.println("区县代码:" + countyCode); // } }