补充客户信息,检索信息
This commit is contained in:
@@ -10,8 +10,10 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -101,44 +103,90 @@ public class NearbyMerchantSearchServiceImpl implements INearbyMerchantSearchSer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地理编码。URL 拼法与 {@link com.rj.gaode#} 一致:
|
||||||
|
* 使用 {@link URLEncoder#encode(String, java.nio.charset.Charset)} 处理中文查询参数。
|
||||||
|
* Spring {@code UriComponentsBuilder} 的编码规则与 {@code URLEncoder} 不一致,易导致高德返回 ENGINE_RESPONSE_DATA_ERROR(如 infocode=30001)。
|
||||||
|
* 首次失败后不传 {@code city},仅用合并后的完整地址再请求一次。
|
||||||
|
*/
|
||||||
private String geocodeToLocation(String city, String address) throws Exception {
|
private String geocodeToLocation(String city, String address) throws Exception {
|
||||||
String url = UriComponentsBuilder.fromUriString(GEOCODE_URL)
|
String json = fetchGeocode(city, address);
|
||||||
.queryParam("key", amapProperties.getWebServiceKey())
|
String loc = parseGeocodeLocation(json);
|
||||||
.queryParam("city", city)
|
if (loc != null) {
|
||||||
.queryParam("address", address)
|
|
||||||
.queryParam("output", "json")
|
|
||||||
.build()
|
|
||||||
.encode()
|
|
||||||
.toUriString();
|
|
||||||
String json = restTemplate.getForObject(url, String.class);
|
|
||||||
JsonNode root = objectMapper.readTree(json);
|
|
||||||
if (!"1".equals(root.path("status").asText())) {
|
|
||||||
String info = root.path("info").asText("地理编码失败");
|
|
||||||
throw new IllegalArgumentException("地理编码失败:" + info);
|
|
||||||
}
|
|
||||||
JsonNode geocodes = root.path("geocodes");
|
|
||||||
if (!geocodes.isArray() || geocodes.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("未解析到该地址的经纬度,请检查 CITY、ADDRESS");
|
|
||||||
}
|
|
||||||
String loc = geocodes.get(0).path("location").asText("");
|
|
||||||
if (!StringUtils.hasText(loc)) {
|
|
||||||
throw new IllegalArgumentException("地理编码结果中无 location 字段");
|
|
||||||
}
|
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String merged = mergeCityAddress(city, address);
|
||||||
|
log.debug("地理编码首次未返回坐标,不传 city、使用合并地址重试");
|
||||||
|
json = fetchGeocode(null, merged);
|
||||||
|
loc = parseGeocodeLocation(json);
|
||||||
|
if (loc != null) {
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw geocodeFailureException(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 与 AllShopCollectorV5 相同:key、c(可选)、address、output;city 与 address 经 UTF-8 URLEncoder。无 city 时不带 city 参数。 */
|
||||||
|
private String fetchGeocode(String city, String address) {
|
||||||
|
String key = amapProperties.getWebServiceKey();
|
||||||
|
StringBuilder sb = new StringBuilder(GEOCODE_URL);
|
||||||
|
sb.append("?key=").append(key);
|
||||||
|
if (StringUtils.hasText(city)) {
|
||||||
|
sb.append("&city=").append(URLEncoder.encode(city, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
sb.append("&address=").append(URLEncoder.encode(address, StandardCharsets.UTF_8));
|
||||||
|
sb.append("&output=json");
|
||||||
|
String url = sb.toString();
|
||||||
|
String json = restTemplate.getForObject(URI.create(url), String.class);
|
||||||
|
if (json == null) {
|
||||||
|
throw new IllegalStateException("高德地理编码返回空响应");
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** status=1 且存在 location 时返回坐标,否则返回 null。 */
|
||||||
|
private String parseGeocodeLocation(String json) throws Exception {
|
||||||
|
JsonNode root = objectMapper.readTree(json);
|
||||||
|
if (!"1".equals(root.path("status").asText())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JsonNode geocodes = root.path("geocodes");
|
||||||
|
if (!geocodes.isArray() || geocodes.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String loc = geocodes.get(0).path("location").asText("");
|
||||||
|
return StringUtils.hasText(loc) ? loc : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String mergeCityAddress(String city, String address) {
|
||||||
|
String c = city.trim();
|
||||||
|
String a = address.trim();
|
||||||
|
if (a.startsWith(c)) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return c + a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IllegalArgumentException geocodeFailureException(String json) throws Exception {
|
||||||
|
JsonNode root = objectMapper.readTree(json);
|
||||||
|
String info = root.path("info").asText("地理编码失败");
|
||||||
|
String infocode = root.path("infocode").asText("");
|
||||||
|
if (StringUtils.hasText(infocode)) {
|
||||||
|
return new IllegalArgumentException("地理编码失败:" + info + "(infocode=" + infocode + ")");
|
||||||
|
}
|
||||||
|
return new IllegalArgumentException("地理编码失败:" + info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 与 AllShopCollectorV5#getAllShops 相同的参数顺序与拼接方式(location 为经纬度串,无需 URL 编码)。 */
|
||||||
private String fetchAroundPage(String location, int radius, int offset, int page) {
|
private String fetchAroundPage(String location, int radius, int offset, int page) {
|
||||||
String url = UriComponentsBuilder.fromUriString(AROUND_URL)
|
String url = AROUND_URL + "?key=" + amapProperties.getWebServiceKey()
|
||||||
.queryParam("key", amapProperties.getWebServiceKey())
|
+ "&location=" + location
|
||||||
.queryParam("location", location)
|
+ "&radius=" + radius
|
||||||
.queryParam("radius", radius)
|
+ "&offset=" + offset
|
||||||
.queryParam("offset", offset)
|
+ "&page=" + page
|
||||||
.queryParam("page", page)
|
+ "&output=json";
|
||||||
.queryParam("output", "json")
|
String body = restTemplate.getForObject(URI.create(url), String.class);
|
||||||
.build()
|
|
||||||
.encode()
|
|
||||||
.toUriString();
|
|
||||||
String body = restTemplate.getForObject(url, String.class);
|
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
throw new IllegalStateException("高德周边搜索返回空响应");
|
throw new IllegalStateException("高德周边搜索返回空响应");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,9 +271,10 @@ dify:
|
|||||||
top-sales-alldim-token: app-99nVuuKfcRR2vikxgOTiNQm0
|
top-sales-alldim-token: app-99nVuuKfcRR2vikxgOTiNQm0
|
||||||
classification-token: app-Id1eOuv5yBb1pexpEWVDqSS3
|
classification-token: app-Id1eOuv5yBb1pexpEWVDqSS3
|
||||||
|
|
||||||
# 高德地图 Web 服务(地理编码、周边 POI);本地可设环境变量 AMAP_WEB_SERVICE_KEY
|
# 高德地图 Web 服务(地理编码、周边 POI)
|
||||||
|
# 未设环境变量时使用与 com.rj.gaode.AllShopCollectorV5 一致的本地默认;生产/正式环境请设置 AMAP_WEB_SERVICE_KEY 覆盖
|
||||||
amap:
|
amap:
|
||||||
web-service-key: ${AMAP_WEB_SERVICE_KEY:}
|
web-service-key: ${AMAP_WEB_SERVICE_KEY:34eaa47387aa9e8c1a8ca0d4c8abaa1d}
|
||||||
|
|
||||||
# MinIO 对象存储配置
|
# MinIO 对象存储配置
|
||||||
minio:
|
minio:
|
||||||
|
|||||||
Reference in New Issue
Block a user