Просмотр исходного кода

添加接口,根据经纬度调取高德接口,获取城市信息

wangzhijun 2 недель назад
Родитель
Сommit
37497d9fb7

+ 9 - 0
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/AreaController.java

@@ -7,7 +7,9 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ylx.massage.domain.Area;
+import com.ylx.massage.domain.dto.CoordinateDTO;
 import com.ylx.massage.domain.vo.AreaTreeNode;
+import com.ylx.massage.domain.vo.CityInfoVo;
 import com.ylx.massage.service.AreaService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -122,5 +124,12 @@ public class AreaController {
         List<AreaTreeNode> tree = this.areaService.getAreaTree();
         return R.ok(tree);
     }
+
+    @PostMapping("/city")
+    @ApiOperation("根据经纬度获取城市信息")
+    public R<CityInfoVo> getCityInfoByCoordinates(@RequestBody CoordinateDTO dto) {
+        CityInfoVo cityInfoVo = this.areaService.getCityInfoByCoordinates(dto);
+        return R.ok(cityInfoVo);
+    }
 }
 

+ 4 - 0
nightFragrance-admin/src/main/resources/application-dev.yml

@@ -277,3 +277,7 @@ ffmpeg:
   container-work-dir: /data
   # 宿主机路径映射(Docker volume映射的源路径)
   host-volume-path: /usr/local/java/nightFragrance/uploadPath
+
+# 高德地图
+amap:
+  apiKey: 5457092e6c62b83c1b2e45dbe973d858

+ 4 - 0
nightFragrance-admin/src/main/resources/application-pro.yml

@@ -277,3 +277,7 @@ ffmpeg:
   # 宿主机路径映射(Docker volume映射的源路径)
   host-volume-path: /usr/local/java/nightFragrance/uploadPath
 
+# 高德地图
+amap:
+  apiKey: 5457092e6c62b83c1b2e45dbe973d858
+

+ 5 - 1
nightFragrance-admin/src/main/resources/application-test.yml

@@ -289,4 +289,8 @@ ffmpeg:
   # Docker容器内工作目录
   container-work-dir: /data
   # 宿主机路径映射(Docker volume映射的源路径)
-  host-volume-path: /usr/local/java/nightFragrance/uploadPath
+  host-volume-path: /usr/local/java/nightFragrance/uploadPath
+
+# 高德地图
+amap:
+  apiKey: 5457092e6c62b83c1b2e45dbe973d858

+ 14 - 0
nightFragrance-common/src/main/java/com/ylx/common/config/AmapConfig.java

@@ -0,0 +1,14 @@
+package com.ylx.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "amap")
+public class AmapConfig {
+
+    private String apiKey;
+
+}

+ 1 - 1
nightFragrance-framework/src/main/java/com/ylx/framework/config/SecurityConfig.java

@@ -112,7 +112,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                         "/api/lbt/v1/getAll", "/api/js/v1/select", "/api/xiangmu/v1/wx/getAll", "/api/order/v1/getStatus",
                         "/api/xiangmu/v1/getByid", "/api/xiangmu/v1/highlights", "/api/js/v1/wx/getByid", "/api/js/v1/wx/select", "/api/js/v1/wx/add", "/api/recharge/v1/test",
                         "/wx/pay/payNotify", "/wx/pay/refundNotify", "/weChat/getAccessToken","/weChat/phoneLogin", "/weChat/getCode", "/weChat/verifyToken", "/sq/getAccessToken",
-                        "/area/select", "/system/dept/list", "/api/xiangmu/v1/wx/recommend", "/product/category/create","/area/code","/product/category/list",
+                        "/area/select", "/system/dept/list", "/api/xiangmu/v1/wx/recommend", "/product/category/create","/area/code","/area/city","/product/category/list",
                         "/api/products/options","/wx/pay/query/order/{outTradeNo}","/api/products/options/service").permitAll()
                 // 静态资源,可匿名访问
                 .antMatchers(HttpMethod.GET, "/", "/*.txt", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()

+ 17 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/CoordinateDTO.java

@@ -0,0 +1,17 @@
+package com.ylx.massage.domain.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel(description = "经纬度查询dto")
+public class CoordinateDTO {
+
+    @ApiModelProperty(value = "经度", required = true)
+    private double longitude;
+
+    @ApiModelProperty(value = "纬度", required = true)
+    private double latitude;
+
+}

+ 20 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/AddressComponent.java

@@ -0,0 +1,20 @@
+package com.ylx.massage.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+
+@Data
+@ApiModel("地址组件信息")
+public class AddressComponent {
+
+    private String city;
+    private String province;
+    private String adcode;
+    private String district;
+    private String towncode;
+    private StreetNumber streetNumber;
+    private String country;
+    private String township;
+    private String citycode;
+}

+ 14 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/AmapRegeoVo.java

@@ -0,0 +1,14 @@
+package com.ylx.massage.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel("高德地图逆地理编码响应视图对象vo")
+public class AmapRegeoVo {
+
+    private String status;
+    private Regeocode regeocode;
+    private String info;
+    private String infocode;
+}

+ 19 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/CityInfoVo.java

@@ -0,0 +1,19 @@
+package com.ylx.massage.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@ApiModel("城市信息数据")
+@AllArgsConstructor
+public class CityInfoVo {
+
+    @ApiModelProperty("城市名称")
+    private String cityName;
+
+    @ApiModelProperty("城市区域码")
+    private String cityCode;
+
+}

+ 12 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/Regeocode.java

@@ -0,0 +1,12 @@
+package com.ylx.massage.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+@Data
+@ApiModel("街道号码信息")
+public class Regeocode {
+
+    private AddressComponent addressComponent;
+    private String formattedAddress;
+}

+ 16 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/vo/StreetNumber.java

@@ -0,0 +1,16 @@
+package com.ylx.massage.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@ApiModel("街道号码信息")
+public class StreetNumber {
+
+    private List<String> number;
+    private List<String> direction;
+    private List<String> distance;
+    private List<String> street;
+}

+ 4 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/AreaService.java

@@ -2,7 +2,9 @@ package com.ylx.massage.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ylx.massage.domain.Area;
+import com.ylx.massage.domain.dto.CoordinateDTO;
 import com.ylx.massage.domain.vo.AreaTreeNode;
+import com.ylx.massage.domain.vo.CityInfoVo;
 
 import java.util.List;
 
@@ -15,5 +17,7 @@ import java.util.List;
 public interface AreaService extends IService<Area> {
 
     List<AreaTreeNode> getAreaTree();
+
+    CityInfoVo getCityInfoByCoordinates(CoordinateDTO dto);
 }
 

+ 98 - 1
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/AreaServiceImpl.java

@@ -1,13 +1,24 @@
 package com.ylx.massage.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.config.AmapConfig;
+import com.ylx.common.core.domain.R;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.common.utils.http.HttpUtils;
 import com.ylx.massage.domain.Area;
-import com.ylx.massage.domain.vo.AreaTreeNode;
+import com.ylx.massage.domain.dto.CoordinateDTO;
+import com.ylx.massage.domain.vo.*;
 import com.ylx.massage.mapper.AreaMapper;
 import com.ylx.massage.service.AreaService;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -16,6 +27,17 @@ import java.util.stream.Collectors;
 @Service("areaService")
 public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements AreaService {
 
+    @Resource
+    private AmapConfig amapConfig;
+
+    private static final String AMAP_URL_PATTERN = "https://restapi.amap.com/v3/geocode/regeo?key=%s&location=%s,%s";
+
+    private static final String AMAP_SUCCESS_STATUS = "1";
+    private static final String ERROR_MSG_API_KEY_MISSING = "配置文件中未找到或 app.amap-api-key 为空";
+    private static final String ERROR_MSG_LOCATION_FAILED = "获取地理位置异常";
+    private static final String ERROR_MSG_CITY_NOT_FOUND = "城市数据不存在";
+    private static final int MAX_QUERY_RESULTS = 1;
+
     /**
      * 一次性查询所有区域,内存构建树形结构
      */
@@ -58,4 +80,79 @@ public class AreaServiceImpl extends ServiceImpl<AreaMapper, Area> implements Ar
                 .filter(node -> "0".equals(node.getParentCode()))
                 .collect(Collectors.toList());
     }
+
+    @Override
+    public CityInfoVo getCityInfoByCoordinates(CoordinateDTO dto) {
+        // 参数验证
+        validateCoordinates(dto);
+
+        // 获取API Key
+        String amapKey = amapConfig.getApiKey();
+        if (StrUtil.isEmpty(amapKey)) {
+            log.error(ERROR_MSG_API_KEY_MISSING);
+            throw new ServiceException(ERROR_MSG_API_KEY_MISSING);
+        }
+
+        try {
+            // 调用高德API
+            String url = String.format(AMAP_URL_PATTERN, amapKey, dto.getLongitude(), dto.getLatitude());
+            String response = HttpUtils.sendGet(url);
+
+            // 解析响应
+            AmapRegeoVo amapResponse = parseAmapResponse(response);
+
+            // 获取城市信息
+            return getCityInfo(amapResponse);
+        } catch (Exception e) {
+            log.error("获取城市信息失败", e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    private void validateCoordinates(CoordinateDTO dto) {
+        if (dto == null) {
+            throw new IllegalArgumentException("坐标信息不能为空");
+        }
+        if (dto.getLongitude() < -180 || dto.getLongitude() > 180) {
+            throw new IllegalArgumentException("经度必须在-180到180之间");
+        }
+        if (dto.getLatitude() < -90 || dto.getLatitude() > 90) {
+            throw new IllegalArgumentException("纬度必须在-90到90之间");
+        }
+    }
+
+    private AmapRegeoVo parseAmapResponse(String response) {
+        if (StrUtil.isEmpty(response)) {
+            throw new ServiceException(ERROR_MSG_LOCATION_FAILED);
+        }
+
+        AmapRegeoVo vo = JSONObject.parseObject(response, AmapRegeoVo.class);
+        if (vo == null || !AMAP_SUCCESS_STATUS.equals(vo.getStatus())) {
+            throw new ServiceException(ERROR_MSG_LOCATION_FAILED);
+        }
+        return vo;
+    }
+
+    private CityInfoVo getCityInfo(AmapRegeoVo amapResponse) {
+        if (amapResponse == null || amapResponse.getRegeocode() == null) {
+            return null;
+        }
+
+        AddressComponent addressComponent = amapResponse.getRegeocode().getAddressComponent();
+        if (addressComponent == null || StrUtil.isEmpty(addressComponent.getCity())) {
+            return null;
+        }
+
+        // 优化查询,只取第一条记录
+        LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(Area::getName, addressComponent.getCity())
+                .last("LIMIT " + MAX_QUERY_RESULTS);
+
+        Area area = this.getOne(queryWrapper);
+        if (area == null) {
+            throw new ServiceException(ERROR_MSG_CITY_NOT_FOUND);
+        }
+
+        return new CityInfoVo(area.getName(), area.getCode());
+    }
 }