src/main/java/com/mzl/flower/config/GaodeMapProperties.java
对比新文件 @@ -0,0 +1,17 @@ package com.mzl.flower.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Data @Component @ConfigurationProperties(prefix = "map.gaode") public class GaodeMapProperties { /** * 高德地图地址行政区划查询接口 */ private String administrativeDivisionsUrl; } src/main/java/com/mzl/flower/config/TengxunMapProperties.java
对比新文件 @@ -0,0 +1,17 @@ package com.mzl.flower.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Data @Component @ConfigurationProperties(prefix = "map.tengxun") public class TengxunMapProperties { /** * 腾讯地图地址行政区划查询接口 */ private String administrativeDivisionsUrl; } src/main/java/com/mzl/flower/dto/map/gaode/CityCodeTypeAdapter.java
对比新文件 @@ -0,0 +1,43 @@ package com.mzl.flower.dto.map.gaode; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; public class CityCodeTypeAdapter extends TypeAdapter<String> { @Override public void write(JsonWriter out, String value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(value); } } @Override public String read(JsonReader in) throws IOException { if (in.peek() == JsonToken.BEGIN_ARRAY) { // 处理数组类型 StringBuilder result = new StringBuilder(); in.beginArray(); while (in.hasNext()) { if (result.length() > 0) { result.append(","); } result.append(in.nextString()); } in.endArray(); return result.toString(); } else if (in.peek() == JsonToken.STRING) { // 处理字符串类型 return in.nextString(); } else if (in.peek() == JsonToken.NULL) { in.nextNull(); return ""; } else { throw new IllegalStateException("Unexpected JSON type: " + in.peek()); } } } src/main/java/com/mzl/flower/dto/map/gaode/GaodeDistrict.java
对比新文件 @@ -0,0 +1,99 @@ package com.mzl.flower.dto.map.gaode; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.google.gson.annotations.JsonAdapter; import com.mzl.flower.dto.map.tengxun.TengxunLocation; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; // 行政区划对象 /** * 代码共6位,前两位代表省(一级)、中间两位为市/地区(二级),最后两位为区县(三级) * 1)省级:前两位有值,后4位置0,如,河北省:130000 * 2)市/地区:前4四位有值,包含省代码与市代码,最后两位置0,如河北省保定市:130600 * 3)区县:6位全有值,包含前4位省市代码及区县代码,河北省保定市涿州市:130681 * 4)直辖市、香港、澳门: * 同省级,在行政区划接口(ws/district/v1/list)中,其下直接为区级(没有二级结构填充) * 例:北京,东城区 (而非:“北京,北京,东城区”) * 5)直辖县:第3、4位为90的,为省直辖县 * 6)中国范围内,省市区行政区划以外的区域值为999999(如中国东海) * 7)东莞市、中山市、儋州市、嘉峪关市 因其下无区县级,因此增加了末位为99代码的同名子级,用于补齐到三级区划的结构 * * 如何获取城市编码(city_code): * 1)编码前4位不为0,第5、6位为0的,为常规城市,可直接取用 * 2)北京、上海、重庆、天津、香港、澳门,编码和省一致,需要单独提出 * 3)第3、4位为90的为省直辖县,一般当做城市来应用,也需要单独提出 */ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) public class GaodeDistrict { private String id; /** * 城市编码 */ @JsonAdapter(CityCodeTypeAdapter.class) private String citycode; /** * 区域编码 * 街道没有独有的 adcode,均继承父类(区县)的 adcode */ private String adcode; /** * 行政区名称 */ private String name; /** * 行政区边界坐标点 * 当一个行政区范围,由完全分隔两块或者多块的地块组 * * 成,每块地的 polyline 坐标串以 | 分隔 。 * * 如北京 的 朝阳区 * */ private String polyline; /** * * 区域中心点 * 乡镇级别返回的center是边界线上的形点,其他行政级别返回的center不一定是中心点,若政府机构位于面内,则返回政府坐标,政府不在面内,则返回繁华点坐标 */ private String center; /** * 行政区划级别 * * country:国家 * * province:省份(直辖市会在province显示) * * city:市(直辖市会在province显示) * * district:区县 * * street:街道 * */ private String level; /** * 下级行政区列表,包含 district 元素 */ private List<GaodeDistrict> districts; /** * 行政区划父级别唯一标识(adcode) */ private String parentId; } src/main/java/com/mzl/flower/dto/map/gaode/GaodeMapResponse.java
对比新文件 @@ -0,0 +1,33 @@ package com.mzl.flower.dto.map.gaode; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import java.util.List; // 顶层对象 @JsonIgnoreProperties(ignoreUnknown = true) @Data public class GaodeMapResponse { /** * 返回结果状态值 * 值为0或1,0表示失败;1表示成功 */ private String status; /** * 返回状态说明 */ private String info; /** * 状态码 * 返回状态说明,10000代表正确,详情参阅 info 状态表 */ private String infocode; private int count; /** * 行政区列表 */ private List<GaodeDistrict> districts; } src/main/java/com/mzl/flower/dto/map/tengxun/TencentMapResponse.java
对比新文件 @@ -0,0 +1,40 @@ package com.mzl.flower.dto.map.tengxun; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.gson.annotations.SerializedName; import lombok.Data; import java.util.List; // 顶层对象 @JsonIgnoreProperties(ignoreUnknown = true) @Data public class TencentMapResponse { private int status; private String message; private String requestId; private int dataVersion; private List<TengxunDistrict> result; @SerializedName("request_id") public String getRequestId() { return requestId; } @SerializedName("request_id") public void setRequestId(String requestId) { this.requestId = requestId; } @SerializedName("data_version") public int getDataVersion() { return dataVersion; } @SerializedName("data_version") public void setDataVersion(int dataVersion) { this.dataVersion = dataVersion; } } src/main/java/com/mzl/flower/dto/map/tengxun/TengxunDistrict.java
对比新文件 @@ -0,0 +1,77 @@ package com.mzl.flower.dto.map.tengxun; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; // 行政区划对象 /** * 代码共6位,前两位代表省(一级)、中间两位为市/地区(二级),最后两位为区县(三级) * 1)省级:前两位有值,后4位置0,如,河北省:130000 * 2)市/地区:前4四位有值,包含省代码与市代码,最后两位置0,如河北省保定市:130600 * 3)区县:6位全有值,包含前4位省市代码及区县代码,河北省保定市涿州市:130681 * 4)直辖市、香港、澳门: * 同省级,在行政区划接口(ws/district/v1/list)中,其下直接为区级(没有二级结构填充) * 例:北京,东城区 (而非:“北京,北京,东城区”) * 5)直辖县:第3、4位为90的,为省直辖县 * 6)中国范围内,省市区行政区划以外的区域值为999999(如中国东海) * 7)东莞市、中山市、儋州市、嘉峪关市 因其下无区县级,因此增加了末位为99代码的同名子级,用于补齐到三级区划的结构 * * 如何获取城市编码(city_code): * 1)编码前4位不为0,第5、6位为0的,为常规城市,可直接取用 * 2)北京、上海、重庆、天津、香港、澳门,编码和省一致,需要单独提出 * 3)第3、4位为90的为省直辖县,一般当做城市来应用,也需要单独提出 */ @Data @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) public class TengxunDistrict { /** * 行政区划唯一标识(adcode) */ private String id; /** * 行政区划唯一标识(adcode) */ private String code; /** * 简称,如“内蒙古” */ private String name; /** * 全称,如“内蒙古自治区” */ private String fullname; /** * 行政区划级别 */ private Integer level; /** * 行政区划拼音,每一下标为一个字的全拼,如: * [“nei”,“meng”,“gu”] */ private List<String> pinyin; /** * 经纬度 */ private TengxunLocation tengxunLocation; /** * 当前区划的下级区划信息,结构与当前区划一致,如果没有下级区划则不返回此字段 * 行政区划代码(adcode)规则说明 */ private List<TengxunDistrict> districts; /** * 行政区划父级别唯一标识(adcode) */ private String parentId; } src/main/java/com/mzl/flower/dto/map/tengxun/TengxunLocation.java
对比新文件 @@ -0,0 +1,25 @@ package com.mzl.flower.dto.map.tengxun; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; // 经纬度对象 @NoArgsConstructor @AllArgsConstructor @Data @JsonIgnoreProperties(ignoreUnknown = true) public class TengxunLocation { /** * 纬度 */ private double lat; /** * 经度 */ private double lng; } src/main/java/com/mzl/flower/dto/request/district/CreateDistrictGaodeDTO.java
对比新文件 @@ -0,0 +1,59 @@ package com.mzl.flower.dto.request.district; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotEmpty; @Data @ApiModel("高德地图的行政区划 ") public class CreateDistrictGaodeDTO { private String id; /** * 名称 */ @ApiModelProperty(value = "name") @NotEmpty(message = "名称不能为空") private String name; /** * 区域编码 */ @ApiModelProperty(value = "citycode") private String citycode; /** * 区域编码 */ @NotEmpty(message = "区域编码不能为空") @ApiModelProperty(value = "adcode") private String adcode; /** * 行政区域边界坐标点 */ @ApiModelProperty(value = "adcode") private String polyline; /** * 区域中心点 */ @ApiModelProperty(value = "adcode") private String center; @ApiModelProperty(value = "等级") private Integer level; /** * 父id */ @ApiModelProperty(value = "父id") private String parentId; } src/main/java/com/mzl/flower/dto/request/district/CreateDistrictTengxunDTO.java
对比新文件 @@ -0,0 +1,50 @@ package com.mzl.flower.dto.request.district; import com.baomidou.mybatisplus.annotation.TableId; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiOperation; import lombok.Data; import javax.validation.constraints.NotEmpty; @Data @ApiModel("腾讯地图的行政区划 ") public class CreateDistrictTengxunDTO { private String id; /** * 名称 */ @ApiModelProperty(value = "name") @NotEmpty(message = "名称不能为空") private String name; /** * 全称 */ @ApiModelProperty(value = "fullname") @NotEmpty(message = "全称不能为空") private String fullname; /** * 区域编码 */ @ApiModelProperty(value = "code") @NotEmpty(message = "编码不能为空") private String code; @ApiModelProperty(value = "等级") private Integer level; /** * 父id */ @ApiModelProperty(value = "父id") private String parentId; } src/main/java/com/mzl/flower/dto/request/district/QueryDistrictTengxunDTO.java
对比新文件 @@ -0,0 +1,8 @@ package com.mzl.flower.dto.request.district; import lombok.Data; @Data public class QueryDistrictTengxunDTO { } src/main/java/com/mzl/flower/dto/response/district/DistrictTengxunVO.java
对比新文件 @@ -0,0 +1,13 @@ package com.mzl.flower.dto.response.district; import com.mzl.flower.entity.district.DistrictTengxunDO; import lombok.Data; import java.util.List; @Data public class DistrictTengxunVO extends DistrictTengxunDO { List<DistrictTengxunVO> children; } src/main/java/com/mzl/flower/dto/response/district/DistrictVO.java
对比新文件 @@ -0,0 +1,48 @@ package com.mzl.flower.dto.response.district; import lombok.Data; import java.util.List; @Data public class DistrictVO { private String id; /** * 名称 */ private String name; /** * 城市编码 */ private String citycode; /** * 区域编码 */ private String adcode; /** * 行政区域边界坐标点 */ private String polyline; /** * 区域中心点 */ private String center; /** * 行政区划级别(country国家 province 省份 city市 district 区县 street街道) */ private String level; /** * 父id */ private String parentId; List<DistrictVO> children; } src/main/java/com/mzl/flower/dto/response/system/AreaDTO.java
@@ -1,12 +1,23 @@ package com.mzl.flower.dto.response.system; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor public class AreaDTO { private String code; private String name; private List<AreaDTO> children; private List<AreaDTO> children=new ArrayList<>(); public AreaDTO(String code, String name) { this.code = code; this.name = name; } } src/main/java/com/mzl/flower/entity/district/DistrictDO.java
对比新文件 @@ -0,0 +1,58 @@ package com.mzl.flower.entity.district; import com.baomidou.mybatisplus.annotation.TableName; import com.mzl.flower.base.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * 对接高德地图行政区划 * * @author @TaoJie * @since 2024-12-19 */ @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) @TableName("t_district") public class DistrictDO extends BaseEntity { /** * 名称 */ private String name; /** * 城市编码 */ private String citycode; /** * 区域编码 */ private String adcode; /** * 行政区域边界坐标点 */ private String polyline; /** * 区域中心点 */ private String center; /** * 行政区划级别(country国家 province 省份 city市 district 区县 street街道) */ private String level; /** * 父id */ private String parentId; } src/main/java/com/mzl/flower/entity/district/DistrictTengxunDO.java
对比新文件 @@ -0,0 +1,46 @@ package com.mzl.flower.entity.district; import com.baomidou.mybatisplus.annotation.TableName; import com.mzl.flower.base.BaseEntity; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * 对接高德地图行政区划 * * @author @TaoJie * @since 2024-12-19 */ @Data @EqualsAndHashCode(callSuper = true) @Accessors(chain = true) @TableName("t_district_tengxun") public class DistrictTengxunDO extends BaseEntity { /** * 名称 */ private String name; /** * 城市编码 */ private String fullname; /** * 区域编码 */ private String code; private Integer level; /** * 父id */ private String parentId; } src/main/java/com/mzl/flower/mapper/district/DistrictMapper.java
对比新文件 @@ -0,0 +1,16 @@ package com.mzl.flower.mapper.district; import com.mzl.flower.entity.district.DistrictDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * <p> * 对接高德地图行政区划 Mapper 接口 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictMapper extends BaseMapper<DistrictDO> { } src/main/java/com/mzl/flower/mapper/district/DistrictMapperCustom.java
对比新文件 @@ -0,0 +1,18 @@ package com.mzl.flower.mapper.district; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mzl.flower.entity.district.DistrictDO; /** * <p> * 对接高德地图行政区划 Mapper 接口 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictMapperCustom extends BaseMapper<DistrictDO> { void removeAllDistricts(); } src/main/java/com/mzl/flower/mapper/district/DistrictTengxunMapper.java
对比新文件 @@ -0,0 +1,17 @@ package com.mzl.flower.mapper.district; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.entity.district.DistrictTengxunDO; /** * <p> * 对接高德地图行政区划 Mapper 接口 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictTengxunMapper extends BaseMapper<DistrictTengxunDO> { } src/main/java/com/mzl/flower/mapper/district/DistrictTengxunMapperCustom.java
对比新文件 @@ -0,0 +1,19 @@ package com.mzl.flower.mapper.district; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.entity.district.DistrictTengxunDO; /** * <p> * 对接高德地图行政区划 Mapper 接口 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictTengxunMapperCustom extends BaseMapper<DistrictTengxunDO> { void removeAllDistricts(); } src/main/java/com/mzl/flower/schedule/MapScheduleService.java
对比新文件 @@ -0,0 +1,43 @@ package com.mzl.flower.schedule; import com.mzl.flower.service.district.DistrictTengxunService; import com.mzl.flower.service.map.MapGaodeService; import com.mzl.flower.service.map.MapTengxunService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component @Slf4j public class MapScheduleService { @Autowired private MapTengxunService mapTengxunService; @Autowired private MapGaodeService mapGaodeService; @Autowired private DistrictTengxunService districtTengxunService; /** * 积分兑换券过期 */ @Scheduled(cron = "5 * * * * ?") public void expiredPointGoodsRecord() { // 高德地图解析-行政区划 // mapGaodeService.getAdministrativeDivision(); // 腾讯地图解析-行政区划 // mapTengxunService.getAdministrativeDivision(); // districtTengxunService.refreshDistrict(); } } src/main/java/com/mzl/flower/service/district/DistrictService.java
对比新文件 @@ -0,0 +1,80 @@ package com.mzl.flower.service.district; import com.mzl.flower.dto.request.district.CreateDistrictGaodeDTO; import com.mzl.flower.dto.response.district.DistrictVO; import com.mzl.flower.dto.response.system.AreaDTO; import com.mzl.flower.entity.district.DistrictDO; import com.baomidou.mybatisplus.extension.service.IService; import java.util.List; /** * <p> * 对接高德地图行政区划 服务类 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictService extends IService<DistrictDO> { void removeAllDistricts(); void refreshDistrict(); /** * 获取所有的行政区划列表 * @return */ List<DistrictDO> getAllDistrict(); /** * 从数据库里面获取 * @return */ List<AreaDTO> getAreaDTOListByDB(); /** * 从JSON文件里面获取 * @return */ List<AreaDTO> getAreaDTOListByJsonFile(); /** * 保存高德数据库入数据库 * @param districtDOList */ void saveRemoteDistricts(List<DistrictDO> districtDOList); List<DistrictVO> getDistrictTreeList(); /** * 创建行政区划 * @param dto * @return */ boolean createDistrict(CreateDistrictGaodeDTO dto); /** * 更新行政区划 * @param dto * @return */ boolean updateDistrict(CreateDistrictGaodeDTO dto); /** * 删除行政区划 * @param id * @return */ boolean deleteDistrict(String id); /** * 获取行政区划 * @return */ String getChineseArea(); void clearChineseDataCache(); } src/main/java/com/mzl/flower/service/district/DistrictTengxunService.java
对比新文件 @@ -0,0 +1,71 @@ package com.mzl.flower.service.district; import com.baomidou.mybatisplus.extension.service.IService; import com.mzl.flower.dto.request.district.CreateDistrictTengxunDTO; import com.mzl.flower.dto.response.district.DistrictTengxunVO; import com.mzl.flower.dto.response.system.AreaDTO; import com.mzl.flower.entity.district.DistrictTengxunDO; import java.util.List; /** * <p> * 对接高德地图行政区划 服务类 * </p> * * @author @TaoJie * @since 2024-12-19 */ public interface DistrictTengxunService extends IService<DistrictTengxunDO> { void removeAllDistricts(); void refreshDistrict(); /** * 获取所有的行政区划列表 * @return */ List<DistrictTengxunDO> getAllDistrict(); /** * 从数据库里面获取 * @return */ List<AreaDTO> getAreaDTOListByDB(); /** * 从JSON文件里面获取 * @return */ List<AreaDTO> getAreaDTOListByJsonFile(); /** * 将远程的数据保存入库 * @param districtTengxunDOList */ void saveRemoteDistricts(List<DistrictTengxunDO> districtTengxunDOList); List<DistrictTengxunVO> getDistrictTreeList(); /** * 创建行政区 * @param dto * @return */ boolean createDistrict(CreateDistrictTengxunDTO dto); /** * 删除行政区划及所有下级 * @param id * @return */ boolean deleteDistrict(String id); boolean updateDistrict(CreateDistrictTengxunDTO dto); String getChineseArea(); void clearChineseDataCache(); } src/main/java/com/mzl/flower/service/impl/district/DistrictServiceImpl.java
对比新文件 @@ -0,0 +1,303 @@ package com.mzl.flower.service.impl.district; import cn.hutool.core.util.IdUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.google.gson.Gson; import com.mzl.flower.base.cache.StringCacheClient; import com.mzl.flower.config.exception.ValidationException; import com.mzl.flower.config.security.SecurityUtils; import com.mzl.flower.dto.request.district.CreateDistrictGaodeDTO; import com.mzl.flower.dto.response.district.DistrictVO; import com.mzl.flower.dto.response.system.AreaDTO; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.entity.district.DistrictTengxunDO; import com.mzl.flower.mapper.district.DistrictMapper; import com.mzl.flower.mapper.district.DistrictMapperCustom; import com.mzl.flower.service.district.DistrictService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mzl.flower.utils.ConverterUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; /** * <p> * 对接高德地图行政区划 服务实现类 * </p> * * @author @TaoJie * @since 2024-12-19 */ @Service public class DistrictServiceImpl extends ServiceImpl<DistrictMapper, DistrictDO> implements DistrictService { @Autowired private DistrictMapperCustom districtMapperCustom; @Autowired private StringCacheClient stringCacheClient; @Override public void removeAllDistricts() { districtMapperCustom.removeAllDistricts(); } @Override public void refreshDistrict() { // 获取所有的数据,并组织成树形结构 List<DistrictDO> districtDOList = getAllDistrict(); List<DistrictVO> districtVOList= ConverterUtil.transList(districtDOList, DistrictVO.class); if(CollectionUtils.isNotEmpty(districtDOList)){ // 找出parent_id 是null的为根节点 Optional<DistrictVO> root = districtVOList.stream().filter(districtVO -> districtVO.getParentId() == null).findFirst(); // 遍历districtDOList,形成树形结构 if(null!=root && root.isPresent()){ DistrictVO rootNode = root.get(); // 构建树形结构 buildTree(rootNode, districtVOList); // 查看这里的树形状结构,将这里的树型转换成之前前端使用的结构 AreaDTO areaDTO = transform(rootNode); Gson gson=new Gson(); System.out.println("整个中国地图的json"); System.out.println(gson.toJson(areaDTO)); System.out.println("整个中国地图下城市的json"); System.out.println(gson.toJson(areaDTO.getChildren())); } } // 根据id和partent_id 构造出行政区划字典 // AreaDTO areaDTO = AreaDTO.build(districtDOList); } // 递归构建树形结构 private static void buildTree(DistrictVO parent, List<DistrictVO> allNodes) { List<DistrictVO> children = allNodes.stream() .filter(node -> parent.getId().equals(node.getParentId())) .collect(Collectors.toList()); parent.setChildren(children); for (DistrictVO child : children) { buildTree(child, allNodes); } } // 转换方法 public static AreaDTO transform(DistrictVO sourceNode) { if (sourceNode == null) { return null; } // 映射当前节点 AreaDTO targetNode = new AreaDTO(sourceNode.getName(), sourceNode.getName()); // 递归映射子节点 if (sourceNode.getChildren() != null) { for (DistrictVO child : sourceNode.getChildren()) { targetNode.getChildren().add(transform(child)); } } return targetNode; } @Override public List<DistrictDO> getAllDistrict() { return baseMapper.selectList(new LambdaQueryWrapper<DistrictDO>().eq(DistrictDO::getDeleted, false).orderByAsc(DistrictDO::getAdcode)); } @Override public List<AreaDTO> getAreaDTOListByDB() { return null; } @Override public List<AreaDTO> getAreaDTOListByJsonFile() { return null; } @Override public void saveRemoteDistricts(List<DistrictDO> districtDOList) { // 先把所有数据放入缓存 removeAllDistricts(); districtDOList.stream().forEach(districtDO -> { districtDO.create(); districtDO.setCreateBy("system"); districtDO.setUpdateBy("system"); }); // 保存数据入库 saveBatch(districtDOList); // saveOrUpdateBatch(districtDOList) } @Override public List<DistrictVO> getDistrictTreeList() { // 获取所有的数据,并组织成树形结构 List<DistrictDO> districtDOList = getAllDistrict(); List<DistrictVO> districtVOList= ConverterUtil.transList(districtDOList, DistrictVO.class); if(CollectionUtils.isNotEmpty(districtDOList)){ // 找出parent_id 是null的为根节点 Optional<DistrictVO> root = districtVOList.stream().filter(districtVO -> districtVO.getParentId() == null).findFirst(); // 遍历districtDOList,形成树形结构 if(null!=root && root.isPresent()){ DistrictVO rootNode = root.get(); // 构建树形结构 buildTree(rootNode, districtVOList); return rootNode.getChildren(); } } return null; } @Transactional @Override public boolean createDistrict(CreateDistrictGaodeDTO dto) { // 查看相同节点下的名称是否存在,这里的partentId可能是null的情况 if(StringUtils.isBlank(dto.getParentId())){ // 获取根节点 adcode=100000 LambdaQueryWrapper<DistrictDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictDO::getDeleted, false).eq(DistrictDO::getAdcode,"100000"); List<DistrictDO> list = list(queryWrapper); if(CollectionUtils.isNotEmpty(list)){ DistrictDO districtDO = list.get(0); dto.setParentId(districtDO.getId()); } } if(StringUtils.isNotBlank(dto.getName())){ LambdaQueryWrapper<DistrictDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictDO::getDeleted, false).eq(DistrictDO::getName, dto.getName()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictDO::getParentId); } else { queryWrapper.eq(DistrictDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前名称已经存在"); } } DistrictDO districtDO =new DistrictDO(); BeanUtils.copyProperties(dto,districtDO); districtDO.setId(IdUtil.simpleUUID()); districtDO.create(SecurityUtils.getUserId()); boolean result= save(districtDO); // 清空缓存 clearChineseDataCache(); return result; } @Transactional @Override public boolean updateDistrict(CreateDistrictGaodeDTO dto) { DistrictDO existsDistrict = getById(dto.getId()); if(Objects.isNull(existsDistrict)){ throw new ValidationException("当前id不存在"); } if(StringUtils.isNotBlank(dto.getName())){ LambdaQueryWrapper<DistrictDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictDO::getDeleted, false) .eq(DistrictDO::getName, dto.getName()) .ne(DistrictDO::getId,dto.getId()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictDO::getParentId); } else { queryWrapper.eq(DistrictDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前名称已经存在"); } } BeanUtils.copyProperties(dto, existsDistrict); existsDistrict.update(SecurityUtils.getUserId()); boolean result= updateById(existsDistrict); // 清空缓存 clearChineseDataCache(); return result; } @Transactional @Override public boolean deleteDistrict(String id) { DistrictDO existsDistrict = getById(id); existsDistrict.update(SecurityUtils.getUserId()); existsDistrict.setDeleted(true); updateById(existsDistrict); List<DistrictDO> childrenList = list(new LambdaQueryWrapper<DistrictDO>().eq(DistrictDO::getParentId, id)); if(CollectionUtils.isNotEmpty(childrenList)){ childrenList.stream().forEach(districtTengxunDO -> { deleteDistrict(districtTengxunDO.getId()); }); } // 清空缓存 clearChineseDataCache(); return true; } @Override public String getChineseArea() { String result = stringCacheClient.get("CHINA_AREA_DATA"); if (StringUtils.isNotBlank(result)) { return result; } else { List<DistrictDO> districtDOList = getAllDistrict(); List<DistrictVO> districtVOList= ConverterUtil.transList(districtDOList, DistrictVO.class); if(CollectionUtils.isNotEmpty(districtDOList)){ // 找出parent_id 是null的为根节点 Optional<DistrictVO> root = districtVOList.stream().filter(districtVO -> districtVO.getParentId() == null).findFirst(); // 遍历districtDOList,形成树形结构 if(null!=root && root.isPresent()){ DistrictVO rootNode = root.get(); // 构建树形结构 buildTree(rootNode, districtVOList); // 查看这里的树形状结构,将这里的树型转换成之前前端使用的结构 AreaDTO areaDTO = transform(rootNode); Gson gson=new Gson(); result=gson.toJson(areaDTO.getChildren()); // System.out.println(result); if(StringUtils.isNotBlank(result)){ stringCacheClient.set("CHINA_AREA_DATA", result); } return result; } } return null; } } @Override public void clearChineseDataCache() { stringCacheClient.delete("CHINA_AREA_DATA"); } } src/main/java/com/mzl/flower/service/impl/district/DistrictTengxunServiceImpl.java
对比新文件 @@ -0,0 +1,367 @@ package com.mzl.flower.service.impl.district; import cn.hutool.core.util.IdUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; import com.mzl.flower.base.cache.StringCacheClient; import com.mzl.flower.config.exception.ValidationException; import com.mzl.flower.config.security.SecurityUtils; import com.mzl.flower.dto.request.district.CreateDistrictTengxunDTO; import com.mzl.flower.dto.response.district.DistrictTengxunVO; import com.mzl.flower.dto.response.system.AreaDTO; import com.mzl.flower.entity.district.DistrictTengxunDO; import com.mzl.flower.entity.district.DistrictTengxunDO; import com.mzl.flower.mapper.district.DistrictTengxunMapper; import com.mzl.flower.mapper.district.DistrictTengxunMapperCustom; import com.mzl.flower.service.district.DistrictTengxunService; import com.mzl.flower.utils.ConverterUtil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; /** * <p> * 对接高德地图行政区划 服务实现类 * </p> * * @author @TaoJie * @since 2024-12-19 */ @Service public class DistrictTengxunServiceImpl extends ServiceImpl<DistrictTengxunMapper, DistrictTengxunDO> implements DistrictTengxunService { @Autowired private DistrictTengxunMapperCustom districtTengxunMapperCustom; @Override public void removeAllDistricts() { districtTengxunMapperCustom.removeAllDistricts(); } @Autowired private StringCacheClient stringCacheClient; @Override public void refreshDistrict() { List<DistrictTengxunDO> districtTengxunDOList = getAllDistrict(); List<DistrictTengxunVO> districtTengxunVOList = ConverterUtil.transList(districtTengxunDOList, DistrictTengxunVO.class); if (CollectionUtils.isNotEmpty(districtTengxunDOList)) { // 找出所有 parent_id 为 null 的节点作为根节点集合 List<DistrictTengxunVO> roots = districtTengxunVOList.stream() .filter(districtTengxunVO -> districtTengxunVO.getParentId() == null) .collect(Collectors.toList()); // 遍历根节点,构建每棵树形结构 List<AreaDTO> areaDTOList = new ArrayList<>(); for (DistrictTengxunVO rootNode : roots) { // 构建树形结构 buildTree(rootNode, districtTengxunVOList); // 将树形转换成前端需要的结构 AreaDTO areaDTO = transform(rootNode); areaDTOList.add(areaDTO); // 打印每个根节点对应的树形 JSON Gson gson = new Gson(); System.out.println("根节点:" + rootNode.getName()); System.out.println("树形结构 JSON:" + gson.toJson(areaDTO)); } // 如果需要整个树形结构的 JSON Gson gson = new Gson(); System.out.println("整个中国地图的 JSON:" + gson.toJson(areaDTOList)); } } // 递归构建树形结构 private static void buildTree(DistrictTengxunVO parent, List<DistrictTengxunVO> allNodes) { List<DistrictTengxunVO> children = allNodes.stream() .filter(node -> parent.getId().equals(node.getParentId())) .collect(Collectors.toList()); parent.setChildren(children); for (DistrictTengxunVO child : children) { buildTree(child, allNodes); } } // 转换方法 public static AreaDTO transform(DistrictTengxunVO sourceNode) { if (sourceNode == null) { return null; } // 映射当前节点 AreaDTO targetNode = new AreaDTO(sourceNode.getName(), sourceNode.getName()); // 递归映射子节点 if (sourceNode.getChildren() != null) { for (DistrictTengxunVO child : sourceNode.getChildren()) { targetNode.getChildren().add(transform(child)); } } return targetNode; } @Override public List<DistrictTengxunDO> getAllDistrict() { return baseMapper.selectList(new LambdaQueryWrapper<DistrictTengxunDO>().eq(DistrictTengxunDO::getDeleted, false).orderByAsc(DistrictTengxunDO::getCode)); } @Override public List<AreaDTO> getAreaDTOListByDB() { return null; } @Override public List<AreaDTO> getAreaDTOListByJsonFile() { return null; } @Override public void saveRemoteDistricts(List<DistrictTengxunDO> districtTengxunDOList) { districtTengxunDOList.stream().forEach(districtTengxunDO -> { // 保存数据库中必要的信息 districtTengxunDO.create(); districtTengxunDO.setCreateBy("system"); districtTengxunDO.setUpdateBy("system"); }); saveOrUpdateBatch(districtTengxunDOList); /* List<DistrictTengxunDO> existList=new ArrayList<>(); List<DistrictTengxunDO> noneExistList=new ArrayList<>(); // 查看是否已经存在code,如果存在则更新,不存在则插入 districtTengxunDOList.stream().forEach(districtTengxunDO -> { List<DistrictTengxunDO> list = list(new LambdaQueryWrapper<DistrictTengxunDO>().eq(DistrictTengxunDO::getDeleted, false).eq(DistrictTengxunDO::getCode,districtTengxunDO.getCode() )); if (CollectionUtils.isNotEmpty(list)) { existList.add(districtTengxunDO); } else { // 插入 noneExistList.add(districtTengxunDO); } }); removeAllDistricts(); System.out.println("删除成功"); // 保存数据入库 saveBatch(districtTengxunDOList);*/ System.out.println("保存成功"); } @Override public List<DistrictTengxunVO> getDistrictTreeList() { List<DistrictTengxunDO> districtTengxunDOList = getAllDistrict(); List<DistrictTengxunVO> districtTengxunVOList = ConverterUtil.transList(districtTengxunDOList, DistrictTengxunVO.class); if (CollectionUtils.isNotEmpty(districtTengxunDOList)) { // 找出所有 parent_id 为 null 的节点作为根节点集合 List<DistrictTengxunVO> roots = districtTengxunVOList.stream() .filter(districtTengxunVO -> districtTengxunVO.getParentId() == null) .collect(Collectors.toList()); for (DistrictTengxunVO rootNode : roots) { // 构建树形结构 buildTree(rootNode, districtTengxunVOList); } return roots; } return null; } @Transactional @Override public boolean createDistrict(CreateDistrictTengxunDTO dto) { // 查看编码是否存在 if (count(new LambdaQueryWrapper<DistrictTengxunDO>() .eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getCode, dto.getCode()))>0) { throw new ValidationException("当前编码已经存在,code全局唯一"); } // 查看相同节点下的名称是否存在,这里的partentId可能是null的情况 if(StringUtils.isNotBlank(dto.getName())){ LambdaQueryWrapper<DistrictTengxunDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getName, dto.getName()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictTengxunDO::getParentId); } else { queryWrapper.eq(DistrictTengxunDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前名称已经存在"); } } if(StringUtils.isNotBlank(dto.getFullname())){ LambdaQueryWrapper<DistrictTengxunDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getFullname, dto.getFullname()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictTengxunDO::getParentId); } else { queryWrapper.eq(DistrictTengxunDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前全称已经存在"); } } DistrictTengxunDO districtTengxunDO =new DistrictTengxunDO(); BeanUtils.copyProperties(dto,districtTengxunDO); districtTengxunDO.setId(IdUtil.simpleUUID()); districtTengxunDO.create(SecurityUtils.getUserId()); // 保存 boolean result=save(districtTengxunDO); // 清空缓存 clearChineseDataCache(); return result; } @Transactional @Override public boolean deleteDistrict(String id) { DistrictTengxunDO existsDistrict = getById(id); existsDistrict.update(SecurityUtils.getUserId()); existsDistrict.setDeleted(true); updateById(existsDistrict); List<DistrictTengxunDO> childrenList = list(new LambdaQueryWrapper<DistrictTengxunDO>().eq(DistrictTengxunDO::getParentId, id)); if(CollectionUtils.isNotEmpty(childrenList)){ childrenList.stream().forEach(districtTengxunDO -> { deleteDistrict(districtTengxunDO.getId()); }); } // 清空缓存 clearChineseDataCache(); return true; } @Transactional @Override public boolean updateDistrict(CreateDistrictTengxunDTO dto) { DistrictTengxunDO existsDistrict = getById(dto.getId()); if(Objects.isNull(existsDistrict)){ throw new ValidationException("当前id不存在"); } // 查看编码是否存在 if (count(new LambdaQueryWrapper<DistrictTengxunDO>() .eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getCode, dto.getCode()).ne(DistrictTengxunDO::getId,dto.getId()))>0) { throw new ValidationException("当前编码已经存在,code全局唯一"); } // 查看相同节点下的名称是否存在,这里的partentId可能是null的情况 if(StringUtils.isNotBlank(dto.getName())){ LambdaQueryWrapper<DistrictTengxunDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getName, dto.getName()) .ne(DistrictTengxunDO::getId,dto.getId()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictTengxunDO::getParentId); } else { queryWrapper.eq(DistrictTengxunDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前名称已经存在"); } } if(StringUtils.isNotBlank(dto.getFullname())){ LambdaQueryWrapper<DistrictTengxunDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(DistrictTengxunDO::getDeleted, false) .eq(DistrictTengxunDO::getFullname, dto.getFullname()) .ne(DistrictTengxunDO::getId,dto.getId()); if (dto.getParentId() == null) { queryWrapper.isNull(DistrictTengxunDO::getParentId); } else { queryWrapper.eq(DistrictTengxunDO::getParentId, dto.getParentId()); } if (count(queryWrapper)>0) { throw new ValidationException("当前全称已经存在"); } } BeanUtils.copyProperties(dto, existsDistrict); existsDistrict.update(SecurityUtils.getUserId()); boolean result= updateById(existsDistrict); // 清空缓存 clearChineseDataCache(); return result; } @Override public String getChineseArea() { String result = stringCacheClient.get("CHINA_AREA_DATA"); if (StringUtils.isNotBlank(result)) { return result; } else { // 打印每个根节点对应的树形 JSON Gson gson = new Gson(); List<DistrictTengxunDO> districtTengxunDOList = getAllDistrict(); List<DistrictTengxunVO> districtTengxunVOList = ConverterUtil.transList(districtTengxunDOList, DistrictTengxunVO.class); if (CollectionUtils.isNotEmpty(districtTengxunDOList)) { // 找出所有 parent_id 为 null 的节点作为根节点集合 List<DistrictTengxunVO> roots = districtTengxunVOList.stream() .filter(districtTengxunVO -> districtTengxunVO.getParentId() == null) .collect(Collectors.toList()); // 遍历根节点,构建每棵树形结构 List<AreaDTO> areaDTOList = new ArrayList<>(); for (DistrictTengxunVO rootNode : roots) { // 构建树形结构 buildTree(rootNode, districtTengxunVOList); // 将树形转换成前端需要的结构 AreaDTO areaDTO = transform(rootNode); areaDTOList.add(areaDTO); } result=gson.toJson(areaDTOList); if(StringUtils.isNotBlank(result)){ stringCacheClient.set("CHINA_AREA_DATA", result); } return result; } return ""; } } @Override public void clearChineseDataCache() { stringCacheClient.delete("CHINA_AREA_DATA"); } } src/main/java/com/mzl/flower/service/impl/map/MapGaodeServiceImpl.java
对比新文件 @@ -0,0 +1,107 @@ package com.mzl.flower.service.impl.map; import cn.hutool.core.util.IdUtil; import cn.hutool.http.HttpUtil; import com.google.gson.Gson; import com.mzl.flower.config.GaodeMapProperties; import com.mzl.flower.dto.map.gaode.GaodeDistrict; import com.mzl.flower.dto.map.gaode.GaodeMapResponse; import com.mzl.flower.dto.response.coupon.CouponTemplateActivyVO; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.service.district.DistrictService; import com.mzl.flower.service.map.MapGaodeService; import com.mzl.flower.utils.ConverterUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.Md5Crypt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @Service @Slf4j public class MapGaodeServiceImpl implements MapGaodeService { @Autowired private GaodeMapProperties gaodeMapProperties; @Autowired private DistrictService districtService; @Override public void getAdministrativeDivision() { String administrativeDivisionsUrl = gaodeMapProperties.getAdministrativeDivisionsUrl(); System.out.println(administrativeDivisionsUrl); //可以单独传入http参数,这样参数会自动做URL编码,拼接在URL中 HashMap<String, Object> paramMap = new HashMap<>(); String result= HttpUtil.get(administrativeDivisionsUrl, paramMap); System.out.println(result); // 使用 Gson 解析 JSON 字符串 Gson gson = new Gson(); GaodeMapResponse response = gson.fromJson(result, GaodeMapResponse.class); if(response.getStatus().equals("1")&&response.getInfocode().equals("10000")){ log.info("高德地图获取行政区划成功"); log.info(response.getDistricts().toString()); List<GaodeDistrict> allTengxunDistricts = new ArrayList<>(); for (GaodeDistrict gaodeDistrict : response.getDistricts()){ addDistrictToList(gaodeDistrict, null, allTengxunDistricts); // 从根节点开始,父节点 ID 为 null } // 打印所有区划信息 for (GaodeDistrict gaodeDistrict :allTengxunDistricts){ printDistrictInfo(gaodeDistrict); } // 保存所有的行政区划数据到数据库中 // 将allTengxunDistricts转换成List<DsitrictVO> List<DistrictDO> districtDOList= ConverterUtil.transList(allTengxunDistricts, DistrictDO.class); /** * 保存数据到数据库中 */ districtService.saveRemoteDistricts(districtDOList); System.out.println("保存成功"); }else{ log.error("高德地图获取行政区划失败"); } } public static void addDistrictToList(GaodeDistrict gaodeDistrict, String parentId, List<GaodeDistrict> allTengxunDistricts) { // 设置id gaodeDistrict.setId(IdUtil.simpleUUID()); // String idStr=gaodeDistrict.getAdcode()+gaodeDistrict.getLevel(); // gaodeDistrict.setId(idStr); // 设置父节点 ID gaodeDistrict.setParentId(parentId); // 将当前区划添加到结果列表 allTengxunDistricts.add(gaodeDistrict); // 递归遍历子区划 if (gaodeDistrict.getDistricts() != null) { for (GaodeDistrict child : gaodeDistrict.getDistricts()) { addDistrictToList(child, gaodeDistrict.getId(), allTengxunDistricts); // 将当前节点的 ID 作为子节点的父节点 ID } } } public static void printDistrictInfo(GaodeDistrict gaodeDistrict) { // 打印相关信息 System.out.println("ID: " + gaodeDistrict.getId() + ", 父节点ID: " + gaodeDistrict.getParentId()); System.out.println("名称: " + gaodeDistrict.getName()); System.out.println("编码: " + gaodeDistrict.getAdcode()); System.out.println("级别: " + gaodeDistrict.getLevel()); System.out.println("边界线: " + gaodeDistrict.getPolyline()); System.out.println("中心点: " + gaodeDistrict.getCenter()); System.out.println("子节点数量: " + gaodeDistrict.getDistricts().size()); System.out.println("--------------------------"); } } src/main/java/com/mzl/flower/service/impl/map/MapTengxunServiceImpl.java
对比新文件 @@ -0,0 +1,154 @@ package com.mzl.flower.service.impl.map; import cn.hutool.core.util.IdUtil; import cn.hutool.http.HttpUtil; import com.google.gson.Gson; import com.mzl.flower.config.TengxunMapProperties; import com.mzl.flower.dto.map.gaode.GaodeDistrict; import com.mzl.flower.dto.map.tengxun.TengxunDistrict; import com.mzl.flower.dto.map.tengxun.TencentMapResponse; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.entity.district.DistrictTengxunDO; import com.mzl.flower.service.BaseService; import com.mzl.flower.service.district.DistrictTengxunService; import com.mzl.flower.service.map.MapTengxunService; import com.mzl.flower.utils.ConverterUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @Slf4j @Service public class MapTengxunServiceImpl extends BaseService implements MapTengxunService { @Autowired private TengxunMapProperties tengxunMapProperties; @Autowired private DistrictTengxunService districtTengxunService; @Override public void getAdministrativeDivision() { // TODO: 获取行政区域数据 String administrativeDivisionsUrl = tengxunMapProperties.getAdministrativeDivisionsUrl(); System.out.println(administrativeDivisionsUrl); //可以单独传入http参数,这样参数会自动做URL编码,拼接在URL中 HashMap<String, Object> paramMap = new HashMap<>(); String result= HttpUtil.get(administrativeDivisionsUrl, paramMap); System.out.println(result); // 使用 Gson 解析 JSON 字符串 Gson gson = new Gson(); TencentMapResponse response = gson.fromJson(result, TencentMapResponse.class); if(response.getStatus()==0){ List<TengxunDistrict> allDistricts = response.getResult(); // 将腾讯地图返回的数据格式转换成标准的三层结构 List<TengxunDistrict> formatterDistrict =normalizeTreeToThreeLevels(allDistricts); List<TengxunDistrict> allTengxunDistricts = new ArrayList<>(); // 递归遍历所有的节点,然后把所有节点加入到 allDistricts 列表中 for (TengxunDistrict tengxunDistrict : formatterDistrict){ addDistrictToList(tengxunDistrict, null, allTengxunDistricts); // 从根节点开始,父节点 ID 为 null } List<DistrictTengxunDO> districtTengxunDOList= ConverterUtil.transList(allTengxunDistricts, DistrictTengxunDO.class); districtTengxunService.saveRemoteDistricts(districtTengxunDOList); // for (TengxunDistrict tengxunDistrict : allTengxunDistricts) { // printDistrictInfo(tengxunDistrict); // } } } public static List<TengxunDistrict> normalizeTreeToThreeLevels(List<TengxunDistrict> tree) { List<TengxunDistrict> result = new ArrayList<>(); for (TengxunDistrict node : tree) { int depth = getTreeDepth(node); if(depth<3){ List<TengxunDistrict> childrenList=new ArrayList<>(); childrenList.add(node); TengxunDistrict tengxunDistrict= new TengxunDistrict(); BeanUtils.copyProperties(node, tengxunDistrict); tengxunDistrict.setDistricts(childrenList); // 虚拟的id、code tengxunDistrict.setId(tengxunDistrict.getId()+"virtual"); // 虚拟的层级 tengxunDistrict.setLevel(-1); result.add(tengxunDistrict); continue; }else{ result.add(node); } } return result; } /** * 遍历树的深度 * @param node * @return */ private static int getTreeDepth(TengxunDistrict node) { if (node == null || node.getDistricts() == null || node.getDistricts().isEmpty()) { return 1; } int maxDepth = 0; for (TengxunDistrict child : node.getDistricts()) { maxDepth = Math.max(maxDepth, getTreeDepth(child)); } return maxDepth + 1; } // 打印区划信息的辅助方法 public static void printDistrictInfo(TengxunDistrict tengxunDistrict) { System.out.println("ID: " + tengxunDistrict.getId() + ", 父节点ID: " + tengxunDistrict.getParentId()); System.out.println("名称: " + tengxunDistrict.getName()); System.out.println("全称: " + tengxunDistrict.getFullname()); System.out.println("级别: " + tengxunDistrict.getLevel()); System.out.println("拼音: " + tengxunDistrict.getPinyin()); System.out.println("经纬度: " + tengxunDistrict.getTengxunLocation()); System.out.println("--------------------------"); } // 递归遍历区划节点,并将它们添加到 allDistricts 列表 public static void addDistrictToList(TengxunDistrict tengxunDistrict, String parentId, List<TengxunDistrict> allTengxunDistricts) { // 将腾讯地图返回的id作为code存放到code中 tengxunDistrict.setCode(tengxunDistrict.getId()); // 如果name 是空的话,则将fullname赋值给name if(StringUtils.isBlank(tengxunDistrict.getName())){ tengxunDistrict.setName(tengxunDistrict.getFullname()); } // tengxunDistrict.setId(IdUtil.simpleUUID()); // 设置父节点 ID tengxunDistrict.setParentId(parentId); // 将当前区划添加到结果列表 allTengxunDistricts.add(tengxunDistrict); // 递归遍历子区划 if (tengxunDistrict.getDistricts()!= null) { for (TengxunDistrict child : tengxunDistrict.getDistricts()) { addDistrictToList(child, tengxunDistrict.getId(), allTengxunDistricts); // 将当前节点的 ID 作为子节点的父节点 ID } } } } src/main/java/com/mzl/flower/service/map/MapGaodeService.java
对比新文件 @@ -0,0 +1,11 @@ package com.mzl.flower.service.map; public interface MapGaodeService { /** * 获取腾讯的行政区划 */ void getAdministrativeDivision(); } src/main/java/com/mzl/flower/service/map/MapTengxunService.java
对比新文件 @@ -0,0 +1,11 @@ package com.mzl.flower.service.map; public interface MapTengxunService { /** * 获取腾讯的行政区划 */ void getAdministrativeDivision(); } src/main/java/com/mzl/flower/web/system/ProvinceController.java
@@ -2,6 +2,8 @@ import com.mzl.flower.base.BaseController; import com.mzl.flower.base.R; import com.mzl.flower.service.district.DistrictService; import com.mzl.flower.service.district.DistrictTengxunService; import com.mzl.flower.service.system.ProvinceService; import com.mzl.flower.utils.LocalUtil; import io.swagger.annotations.Api; @@ -23,6 +25,18 @@ @Autowired private ProvinceService provinceService; /** * 腾讯地图获取中国省市区数据 */ @Autowired private DistrictTengxunService districtTengxunService; /** * 高德地图获取中国省市区数据 */ @Autowired private DistrictService districtService; @ApiOperation(value = "获取省份") @GetMapping("/provinces") @@ -58,13 +72,19 @@ @ApiOperation(value = "获取中国省市区数据") @GetMapping("/area/json") public ResponseEntity<String> getChineseArea() { return returnData(R.SUCCESS.getCode(), provinceService.getChineseArea()); // 高德地图 // return returnData(R.SUCCESS.getCode(), districtService.getChineseArea()); return returnData(R.SUCCESS.getCode(), districtTengxunService.getChineseArea()); // return returnData(R.SUCCESS.getCode(), provinceService.getChineseArea()); } @ApiOperation(value = "刷新中国省市区数据缓存") @GetMapping("/area/json/refresh") public ResponseEntity<String> refresh() { provinceService.refreshChineseData(); // provinceService.refreshChineseData(); // districtService.clearChineseDataCache(); districtTengxunService.clearChineseDataCache(); return returnData(R.SUCCESS.getCode(), null); } } src/main/java/com/mzl/flower/web/v2/district/DistrictGaodeController.java
对比新文件 @@ -0,0 +1,79 @@ package com.mzl.flower.web.v2.district; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mzl.flower.base.BaseController; import com.mzl.flower.base.R; import com.mzl.flower.base.ReturnDataDTO; import com.mzl.flower.dto.request.district.CreateDistrictGaodeDTO; import com.mzl.flower.dto.request.district.CreateDistrictTengxunDTO; import com.mzl.flower.dto.request.district.QueryDistrictTengxunDTO; import com.mzl.flower.dto.response.district.DistrictVO; import com.mzl.flower.service.district.DistrictService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import com.mzl.flower.entity.district.DistrictDO; /** * 对接高德地图行政区划前端控制器 * * @author @TaoJie * @since 2024-12-19 */ @RestController @RequestMapping("/v2/district-gaode") public class DistrictGaodeController extends BaseController { @Autowired private DistrictService districtService; @PostMapping("") @ApiOperation(value = "新增", notes = "新增") public ResponseEntity<ReturnDataDTO> create(@Validated @RequestBody CreateDistrictGaodeDTO dto) { return returnData(R.SUCCESS.getCode(), districtService.createDistrict(dto)); } @PutMapping("/{id}") @ApiOperation(value = "修改", notes = "修改") public ResponseEntity<ReturnDataDTO> update(@PathVariable String id,@Validated @RequestBody CreateDistrictGaodeDTO dto) { dto.setId(id); return returnData(R.SUCCESS.getCode(), districtService.updateDistrict(dto)); } @DeleteMapping("/{id}") @ApiOperation(value = "删除", notes = "删除") public ResponseEntity<ReturnDataDTO> delete(@PathVariable String id) { return returnData(R.SUCCESS.getCode(), districtService.deleteDistrict(id)); } @GetMapping("/{id}") @ApiOperation(value = "详情", notes = "详情") public DistrictDO get(@PathVariable String id) { return districtService.getById(id); } @GetMapping("/page") @ApiOperation(value = "查询-分页", notes = "查询-分页") public ResponseEntity<ReturnDataDTO<Page<DistrictDO>>> page(Page page, QueryDistrictTengxunDTO dto ) { // return returnData(R.SUCCESS.getCode(), ConverterUtil.transPage(resultPage, CouponTemplateActivyVO.class)); return null; } @GetMapping("/list") @ApiOperation(value = "查询-全部", notes = "查询-全部") public ResponseEntity<ReturnDataDTO<Page<DistrictVO>>> list(QueryDistrictTengxunDTO dto) { return returnData(R.SUCCESS.getCode(), districtService.getDistrictTreeList()); } } src/main/java/com/mzl/flower/web/v2/district/DistrictTengxunController.java
对比新文件 @@ -0,0 +1,76 @@ package com.mzl.flower.web.v2.district; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mzl.flower.base.BaseController; import com.mzl.flower.base.R; import com.mzl.flower.base.ReturnDataDTO; import com.mzl.flower.dto.request.district.CreateDistrictTengxunDTO; import com.mzl.flower.dto.request.district.QueryDistrictTengxunDTO; import com.mzl.flower.dto.response.district.DistrictTengxunVO; import com.mzl.flower.entity.district.DistrictDO; import com.mzl.flower.entity.district.DistrictTengxunDO; import com.mzl.flower.service.district.DistrictTengxunService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** * 对接腾讯地图行政区划前端控制器 * * @author @TaoJie * @since 2024-12-19 */ @RestController @RequestMapping("/v2/district-tengxun") public class DistrictTengxunController extends BaseController { @Autowired private DistrictTengxunService districtTengxunService; @PostMapping("") @ApiOperation(value = "新增", notes = "新增") public ResponseEntity<ReturnDataDTO> create(@Validated @RequestBody CreateDistrictTengxunDTO dto) { return returnData(R.SUCCESS.getCode(), districtTengxunService.createDistrict(dto)); } @PutMapping("/{id}") @ApiOperation(value = "修改", notes = "修改") public ResponseEntity<ReturnDataDTO> update(@PathVariable String id,@Validated @RequestBody CreateDistrictTengxunDTO dto) { dto.setId(id); return returnData(R.SUCCESS.getCode(), districtTengxunService.updateDistrict(dto)); } @DeleteMapping("/{id}") @ApiOperation(value = "删除", notes = "删除") public ResponseEntity<ReturnDataDTO> delete(@PathVariable String id) { return returnData(R.SUCCESS.getCode(), districtTengxunService.deleteDistrict(id)); } @GetMapping("/{id}") @ApiOperation(value = "详情", notes = "详情") public DistrictTengxunDO get(@PathVariable String id) { return districtTengxunService.getById(id); } @GetMapping("/page") @ApiOperation(value = "查询-分页", notes = "查询-分页") public ResponseEntity<ReturnDataDTO<Page<DistrictDO>>> page(Page page, QueryDistrictTengxunDTO dto ) { // return returnData(R.SUCCESS.getCode(), ConverterUtil.transPage(resultPage, CouponTemplateActivyVO.class)); return null; } @GetMapping("/list") @ApiOperation(value = "查询-全部", notes = "查询-全部") public ResponseEntity<ReturnDataDTO<Page<DistrictTengxunVO>>> list(QueryDistrictTengxunDTO dto) { return returnData(R.SUCCESS.getCode(), districtTengxunService.getDistrictTreeList()); } } src/main/resources/application.yml
@@ -87,4 +87,15 @@ secret: 9121c703fb0c416b21a8c289dd73ae9b #secret sms: verificationCode: SMS_301300012 #验证码通用模版 verificationCode: SMS_301300012 #验证码通用模版 map: tengxun: # apiKey: GSBBZ-CJA3U-NNDVH-GE65N-6FIF6-ZGBCU apiKey: PRFBZ-INBLB-PYEU6-JCKUM-AYD7V-V7BIF # 新政区划接口url administrative_divisions_url : https://apis.map.qq.com/ws/district/v1/list?key=${map.tengxun.apiKey}&&struct_type=1 gaode: apiKey: 19b8a6e7325089d484fcee00076746fa # 新政区划接口url administrative_divisions_url: https://restapi.amap.com/v3/config/district?key=${map.gaode.apiKey}&subdistrict=3&subdistrict=3&extensions=base src/main/resources/mapper/district/DistrictMapper.xml
对比新文件 @@ -0,0 +1,22 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mzl.flower.mapper.district.DistrictMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.mzl.flower.entity.district.DistrictDO"> <id column="id" property="id" /> <result column="deleted" property="deleted" /> <result column="create_by" property="createBy" /> <result column="create_time" property="createTime" /> <result column="update_by" property="updateBy" /> <result column="update_time" property="updateTime" /> <result column="name" property="name" /> <result column="citycode" property="citycode" /> <result column="adcode" property="adcode" /> <result column="polyline" property="polyline" /> <result column="center" property="center" /> <result column="level" property="level" /> <result column="parent_id" property="parentId" /> </resultMap> </mapper> src/main/resources/mapper/district/DistrictMapperCustom.xml
对比新文件 @@ -0,0 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mzl.flower.mapper.district.DistrictMapperCustom"> <delete id="removeAllDistricts"> delete from t_district </delete> </mapper> src/main/resources/mapper/district/DistrictTengxunMapper.xml
对比新文件 @@ -0,0 +1,20 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mzl.flower.mapper.district.DistrictTengxunMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.mzl.flower.entity.district.DistrictTengxunDO"> <id column="id" property="id" /> <result column="deleted" property="deleted" /> <result column="create_by" property="createBy" /> <result column="create_time" property="createTime" /> <result column="update_by" property="updateBy" /> <result column="update_time" property="updateTime" /> <result column="name" property="name" /> <result column="fullname" property="fullname" /> <result column="code" property="code" /> <result column="level" property="level" /> <result column="parent_id" property="parentId" /> </resultMap> </mapper> src/main/resources/mapper/district/DistrictTengxunMapperCustom.xml
对比新文件 @@ -0,0 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mzl.flower.mapper.district.DistrictTengxunMapperCustom"> <delete id="removeAllDistricts"> delete from t_district_tengxun </delete> </mapper>