From 353e302df9041ffc18092fe14bb780f714858132 Mon Sep 17 00:00:00 2001 From: cb <275647614@qq.com> Date: Sat, 23 Aug 2025 16:45:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=A6=E7=BB=86=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E8=AE=A1=E7=AE=97=E4=B8=8E=E5=BA=97=E9=93=BA=E7=9A=84?= =?UTF-8?q?=E8=B7=9D=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- .../ghy/web/controller/ShopController.java | 41 +++-- .../ghy/shop/domain/ShopDistanceQuery.java | 55 +++++- .../shop/service/impl/ShopServiceImpl.java | 167 ++++++++++++------ 4 files changed, 192 insertions(+), 74 deletions(-) diff --git a/.gitignore b/.gitignore index 66a4e8ae..f92d93ec 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ build/ ### VS Code ### .vscode/ /logs/ -/ghy-admin/src/test/ \ No newline at end of file +/ghy-admin/src/test/ +ghy-shop/ADDRESS_QUERY_EXAMPLE.md diff --git a/ghy-admin/src/main/java/com/ghy/web/controller/ShopController.java b/ghy-admin/src/main/java/com/ghy/web/controller/ShopController.java index 229a6efd..f0c3bf82 100644 --- a/ghy-admin/src/main/java/com/ghy/web/controller/ShopController.java +++ b/ghy-admin/src/main/java/com/ghy/web/controller/ShopController.java @@ -439,6 +439,12 @@ public class ShopController extends BaseController { /** * 通过店铺ID查询详细信息并计算距离 + * 最终效果: + * 1. 传入的详细地址 → 转换为经纬度 + * 2. 店铺有经纬度 → 直接使用 + * 3. 店铺没有经纬度 → 通过详细地址生成经纬度 + * 4. 最终通过经纬度计算距离 → 放在店铺的距离字段上 + * * @param query 距离查询请求实体 * @return 包含距离信息的完整店铺详情 */ @@ -450,14 +456,25 @@ public class ShopController extends BaseController { return AjaxResult.error("店铺ID不能为空"); } - if (query.getLatitude() == null || query.getLongitude() == null) { - return AjaxResult.error("经纬度参数不能为空"); + // 验证是否有足够的信息来计算距离或获取位置 + if (!query.hasEnoughInfo()) { + return AjaxResult.error("请提供经纬度或地址信息"); } - if (!LocationUtils.isValidCoordinate(query.getLatitude(), query.getLongitude())) { + // 如果提供了经纬度,验证其有效性 + if (query.hasCoordinateInfo() && !LocationUtils.isValidCoordinate(query.getLatitude(), query.getLongitude())) { return AjaxResult.error("无效的坐标参数"); } + // 验证地址参数(如果提供了地址信息,则验证其完整性) + if (query.hasAddressInfo()) { + String fullAddress = query.getFullAddress(); + if (fullAddress.trim().length() < 5) { + return AjaxResult.error("地址信息不完整,请提供更详细的地址"); + } + logger.info("使用传入的地址信息: {}", fullAddress); + } + // 调用服务层方法获取店铺详情和距离 Shop shop = shopService.getShopWithDistance(query); @@ -466,8 +483,13 @@ public class ShopController extends BaseController { } // 检查距离是否有效 - if (shop.getDistance() == null || shop.getDistance().equals("-1")) { - return AjaxResult.error("无法计算店铺距离,请检查店铺地址信息"); + if (shop.getDistance() == null || shop.getDistance().equals("无法计算距离")) { + if (query.hasCoordinateInfo()) { + return AjaxResult.error("无法计算店铺距离,请检查店铺地址信息或提供更详细的地址参数"); + } else { + // 如果没有经纬度,只获取位置信息 + logger.info("仅获取店铺位置信息,无法计算距离"); + } } // 构建返回结果 @@ -490,14 +512,7 @@ public class ShopController extends BaseController { result.put("longitude", shop.getLongitude()); result.put("distance", shop.getDistance()); - // 添加额外的距离信息 - Map distanceInfo = new HashMap<>(); - distanceInfo.put("formattedDistance", shop.getDistance()); - distanceInfo.put("currentLatitude", query.getLatitude()); - distanceInfo.put("currentLongitude", query.getLongitude()); - - result.put("distanceInfo", distanceInfo); - + return AjaxResult.success("查询成功", result); } catch (Exception e) { diff --git a/ghy-shop/src/main/java/com/ghy/shop/domain/ShopDistanceQuery.java b/ghy-shop/src/main/java/com/ghy/shop/domain/ShopDistanceQuery.java index ac9897e3..64edb29f 100644 --- a/ghy-shop/src/main/java/com/ghy/shop/domain/ShopDistanceQuery.java +++ b/ghy-shop/src/main/java/com/ghy/shop/domain/ShopDistanceQuery.java @@ -9,9 +9,20 @@ import java.io.Serializable; @Data public class ShopDistanceQuery implements Serializable { - private Long shopId; // 店铺ID - private Double latitude; // 当前纬度 - private Double longitude; // 当前经度 + private Long shopId; // 店铺ID (必填) + private Double latitude; // 当前纬度 (可选,如果有地址信息) + private Double longitude; // 当前经度 (可选,如果有地址信息) + + // 地址相关参数(用于查询经纬度) + private Long provinceId; // 省份ID + private String provinceName; // 省份名称 + private Long cityId; // 城市ID + private String cityName; // 城市名称 + private Long countryId; // 区县ID + private String countryName; // 区县名称 + private Long streetId; // 街道ID + private String streetName; // 街道名称 + private String address; // 详细地址 // 可选参数,用于扩展 private String unit; // 距离单位:km(公里)、m(米) @@ -24,4 +35,42 @@ public class ShopDistanceQuery implements Serializable { this.latitude = latitude; this.longitude = longitude; } + + /** + * 构建完整地址字符串 + */ + public String getFullAddress() { + StringBuilder fullAddress = new StringBuilder(); + if (provinceName != null) fullAddress.append(provinceName); + if (cityName != null) fullAddress.append(cityName); + if (countryName != null) fullAddress.append(countryName); + if (streetName != null) fullAddress.append(streetName); + if (address != null) fullAddress.append(address); + return fullAddress.toString(); + } + + /** + * 检查是否有地址信息 + */ + public boolean hasAddressInfo() { + return (provinceName != null && !provinceName.trim().isEmpty()) || + (cityName != null && !cityName.trim().isEmpty()) || + (countryName != null && !countryName.trim().isEmpty()) || + (streetName != null && !streetName.trim().isEmpty()) || + (address != null && !address.trim().isEmpty()); + } + + /** + * 检查是否有坐标信息 + */ + public boolean hasCoordinateInfo() { + return latitude != null && longitude != null; + } + + /** + * 检查是否有足够的信息来计算距离 + */ + public boolean hasEnoughInfo() { + return hasAddressInfo() || hasCoordinateInfo(); + } } diff --git a/ghy-shop/src/main/java/com/ghy/shop/service/impl/ShopServiceImpl.java b/ghy-shop/src/main/java/com/ghy/shop/service/impl/ShopServiceImpl.java index 81b6cff7..fb79f9ad 100644 --- a/ghy-shop/src/main/java/com/ghy/shop/service/impl/ShopServiceImpl.java +++ b/ghy-shop/src/main/java/com/ghy/shop/service/impl/ShopServiceImpl.java @@ -11,9 +11,13 @@ import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; import java.util.HashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @Service public class ShopServiceImpl implements ShopService { + private static final Logger logger = LoggerFactory.getLogger(ShopServiceImpl.class); + @Autowired private ShopMapper shopMapper; @@ -56,15 +60,13 @@ public class ShopServiceImpl implements ShopService { } // 计算距离 - double distance = calculateDistance(shop, query.getLatitude(), query.getLongitude()); + double distance = calculateDistance(shop, query); // 设置距离信息 - shop.setDistance(LocationUtils.formatDistance(distance * 1000)); // 转换为米并格式化 - - // 如果请求更新店铺位置信息,则更新店铺的经纬度 - if (query.getUpdateShopLocation() != null && query.getUpdateShopLocation() && - shop.getLatitude() != null && shop.getLongitude() != null) { - shopMapper.update(shop); + if (distance >= 0) { + shop.setDistance(LocationUtils.formatDistance(distance * 1000)); // 转换为米并格式化 + } else { + shop.setDistance("无法计算距离"); } return shop; @@ -72,19 +74,50 @@ public class ShopServiceImpl implements ShopService { /** * 计算店铺与指定坐标的距离 - * 如果店铺有经纬度,直接计算;如果没有,则通过地址解析获取经纬度后计算 + * 实现逻辑: + * 1. 传入的详细地址 → 转换为经纬度(作为用户当前位置) + * 2. 店铺有经纬度 → 直接使用 + * 3. 店铺没有经纬度 → 通过详细地址生成经纬度 + * 4. 最终计算用户位置与店铺位置的距离 */ - private double calculateDistance(Shop shop, Double latitude, Double longitude) { - // 如果店铺有经纬度,直接计算距离 - if (shop.getLatitude() != null && shop.getLongitude() != null) { - return LocationUtils.getDistanceInKilometers( - latitude, longitude, - shop.getLatitude(), shop.getLongitude() - ); + private double calculateDistance(Shop shop, ShopDistanceQuery query) { + Double userLat = null; + Double userLng = null; + Double shopLat = null; + Double shopLng = null; + + // 1. 获取用户当前位置(优先使用传入的经纬度,其次使用传入地址转换的经纬度) + if (query.hasCoordinateInfo()) { + // 直接使用传入的经纬度作为用户位置 + userLat = query.getLatitude(); + userLng = query.getLongitude(); + logger.info("使用传入的经纬度作为用户位置: 经度={}, 纬度={}", userLng, userLat); + } else if (query.hasAddressInfo()) { + // 通过传入的地址信息生成用户位置的经纬度 + try { + String fullAddress = query.getFullAddress(); + if (!fullAddress.isEmpty()) { + logger.info("通过传入的地址信息生成用户位置经纬度: {}", fullAddress); + + Map coordinates = getCoordinatesByAddress(fullAddress); + if (coordinates != null) { + userLat = coordinates.get("latitude"); + userLng = coordinates.get("longitude"); + logger.info("通过传入地址成功生成用户位置经纬度: 经度={}, 纬度={}", userLng, userLat); + } + } + } catch (Exception e) { + logger.warn("通过传入地址生成用户位置经纬度失败: {}", e.getMessage()); + } } - // 如果店铺没有经纬度但有地址,尝试通过地址解析获取经纬度 - if (shop.getAddress() != null && !shop.getAddress().trim().isEmpty()) { + // 2. 获取店铺位置(优先使用店铺已有的经纬度,其次使用店铺地址生成的经纬度) + if (shop.getLatitude() != null && shop.getLongitude() != null) { + shopLat = shop.getLatitude(); + shopLng = shop.getLongitude(); + logger.info("使用店铺已有的经纬度: 经度={}, 纬度={}", shopLng, shopLat); + } else if (shop.getAddress() != null && !shop.getAddress().trim().isEmpty()) { + // 通过店铺的地址信息生成经纬度 try { // 构建完整地址 StringBuilder fullAddress = new StringBuilder(); @@ -96,69 +129,89 @@ public class ShopServiceImpl implements ShopService { String address = fullAddress.toString(); if (!address.isEmpty()) { - // 这里应该调用地图API获取地址的经纬度 - // 暂时使用示例坐标(实际使用时请替换为真实的API调用) + logger.info("通过店铺地址信息生成经纬度: {}", address); + Map coordinates = getCoordinatesByAddress(address); if (coordinates != null) { - double shopLat = coordinates.get("latitude"); - double shopLng = coordinates.get("longitude"); - - // 计算距离 - double distance = LocationUtils.getDistanceInKilometers( - latitude, longitude, shopLat, shopLng - ); + shopLat = coordinates.get("latitude"); + shopLng = coordinates.get("longitude"); + logger.info("通过店铺地址成功生成经纬度: 经度={}, 纬度={}", shopLng, shopLat); // 更新店铺的经纬度信息 shop.setLatitude(shopLat); shop.setLongitude(shopLng); - return distance; + // 如果请求更新店铺位置信息,则保存到数据库 + if (query.getUpdateShopLocation() != null && query.getUpdateShopLocation()) { + shopMapper.update(shop); + logger.info("已更新并保存店铺[{}]的经纬度: 经度={}, 纬度={}", + shop.getShopName(), shopLng, shopLat); + } } } } catch (Exception e) { - // 地址解析失败,记录日志但不影响主流程 - System.err.println("地址解析失败: " + e.getMessage()); + logger.warn("通过店铺地址生成经纬度失败: {}", e.getMessage()); } } - // 无法获取距离,返回-1表示无效 - return -1; + // 3. 计算用户位置与店铺位置的距离 + if (userLat != null && userLng != null && shopLat != null && shopLng != null) { + // 有用户位置和店铺位置,计算距离 + double distance = LocationUtils.getDistanceInKilometers(userLat, userLng, shopLat, shopLng); + logger.info("成功计算用户位置与店铺位置的距离: {} 公里", distance); + return distance; + } else if (shopLat != null && shopLng != null) { + // 只有店铺位置,没有用户位置,无法计算距离 + logger.info("已获取店铺位置,但未获取到用户位置,无法计算距离"); + return 0; // 返回0表示成功获取店铺位置但无法计算距离 + } else { + // 无法获取店铺位置,返回-1表示无效 + logger.warn("无法获取店铺[{}]的经纬度信息,无法计算距离", shop.getShopName()); + return -1; + } } /** * 通过地址获取经纬度坐标 - * 这是一个示例实现,实际使用时请替换为真实的地图API调用 + * 直接调用百度地图正向地理编码API */ private Map getCoordinatesByAddress(String address) { try { - // TODO: 这里应该调用真实的地图API - // 示例:百度地图正向地理编码API - // String url = "https://api.map.baidu.com/geocoding/v3/?address=" + - // java.net.URLEncoder.encode(address, "UTF-8") + - // "&output=json&ak=YOUR_BAIDU_API_KEY"; - // - // String result = restTemplate.getForObject(url, String.class); - // JSONObject jsonResult = JSONObject.parseObject(result); - // - // if ("0".equals(jsonResult.getString("status"))) { - // JSONObject location = jsonResult.getJSONObject("result").getJSONObject("location"); - // Double lng = location.getDouble("lng"); - // Double lat = location.getDouble("lat"); - // - // Map coordinates = new HashMap<>(); - // coordinates.put("longitude", lng); - // coordinates.put("latitude", lat); - // return coordinates; - // } + if (address == null || address.trim().isEmpty()) { + logger.warn("地址为空,无法获取坐标"); + return null; + } - // 临时返回示例坐标(实际使用时请替换为真实的API调用) - Map coordinates = new HashMap<>(); - coordinates.put("latitude", 39.915 + Math.random() * 0.1); // 示例纬度 - coordinates.put("longitude", 116.404 + Math.random() * 0.1); // 示例经度 + logger.info("开始调用百度地图API解析地址: {}", address); + + // 调用百度地图正向地理编码API + String encoded = java.net.URLEncoder.encode(address, "UTF-8"); + String url = "https://api.map.baidu.com/geocoding/v3/?output=json&ak=ZQTgMW7W0GTuE7Ripb0HDp5TqRaOI6PZ&address=" + encoded; + + // 使用HttpUtils发送GET请求 + String result = com.ghy.common.utils.http.HttpUtils.sendGet(url); + result = result.replaceAll("\n", "").replaceAll("\t", ""); + + // 解析返回结果 + com.alibaba.fastjson.JSONObject resultJson = com.alibaba.fastjson.JSONObject.parseObject(result); + if ("0".equals(resultJson.getString("status"))) { + com.alibaba.fastjson.JSONObject location = resultJson.getJSONObject("result").getJSONObject("location"); + Double lng = location.getDouble("lng"); + Double lat = location.getDouble("lat"); + + Map coordinates = new HashMap<>(); + coordinates.put("longitude", lng); + coordinates.put("latitude", lat); + + logger.info("百度地图API解析成功: {} -> 经度={}, 纬度={}", address, lng, lat); + return coordinates; + } else { + logger.error("百度地图API解析失败: {} - {}", address, resultJson.getString("msg")); + return null; + } - return coordinates; } catch (Exception e) { - System.err.println("地址解析失败: " + e.getMessage()); + logger.error("调用百度地图API失败: {} - {}", address, e.getMessage(), e); return null; } }