补充客户信息,检索信息

This commit is contained in:
2026-05-03 10:42:07 +08:00
parent 29b97839ba
commit f833f373a8
2 changed files with 79 additions and 30 deletions

View File

@@ -10,8 +10,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
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.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 {
String url = UriComponentsBuilder.fromUriString(GEOCODE_URL)
.queryParam("key", amapProperties.getWebServiceKey())
.queryParam("city", city)
.queryParam("address", address)
.queryParam("output", "json")
.build()
.encode()
.toUriString();
String json = restTemplate.getForObject(url, String.class);
String json = fetchGeocode(city, address);
String loc = parseGeocodeLocation(json);
if (loc != null) {
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、outputcity 与 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())) {
String info = root.path("info").asText("地理编码失败");
throw new IllegalArgumentException("地理编码失败:" + info);
return null;
}
JsonNode geocodes = root.path("geocodes");
if (!geocodes.isArray() || geocodes.isEmpty()) {
throw new IllegalArgumentException("未解析到该地址的经纬度,请检查 CITY、ADDRESS");
return null;
}
String loc = geocodes.get(0).path("location").asText("");
if (!StringUtils.hasText(loc)) {
throw new IllegalArgumentException("地理编码结果中无 location 字段");
}
return loc;
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) {
String url = UriComponentsBuilder.fromUriString(AROUND_URL)
.queryParam("key", amapProperties.getWebServiceKey())
.queryParam("location", location)
.queryParam("radius", radius)
.queryParam("offset", offset)
.queryParam("page", page)
.queryParam("output", "json")
.build()
.encode()
.toUriString();
String body = restTemplate.getForObject(url, String.class);
String url = AROUND_URL + "?key=" + amapProperties.getWebServiceKey()
+ "&location=" + location
+ "&radius=" + radius
+ "&offset=" + offset
+ "&page=" + page
+ "&output=json";
String body = restTemplate.getForObject(URI.create(url), String.class);
if (body == null) {
throw new IllegalStateException("高德周边搜索返回空响应");
}

View File

@@ -271,9 +271,10 @@ dify:
top-sales-alldim-token: app-99nVuuKfcRR2vikxgOTiNQm0
classification-token: app-Id1eOuv5yBb1pexpEWVDqSS3
# 高德地图 Web 服务(地理编码、周边 POI;本地可设环境变量 AMAP_WEB_SERVICE_KEY
# 高德地图 Web 服务(地理编码、周边 POI
# 未设环境变量时使用与 com.rj.gaode.AllShopCollectorV5 一致的本地默认;生产/正式环境请设置 AMAP_WEB_SERVICE_KEY 覆盖
amap:
web-service-key: ${AMAP_WEB_SERVICE_KEY:}
web-service-key: ${AMAP_WEB_SERVICE_KEY:34eaa47387aa9e8c1a8ca0d4c8abaa1d}
# MinIO 对象存储配置
minio: