一、数据来源:高德开发API(后端调用接口实现数据落库)
行政区域查询-API文档-开发指南-Web服务 API | 高德地图API
二、需要用到的依赖(只附上主要依赖)
其他依赖:MybatisPlus、SpringBoot、Mysql、Lombok等(你不会没有吧)
<!--请求工具依赖-->
<dependency>
<groupId>com.github.kevinsawicki</groupId>
<artifactId>http-request</artifactId>
<version>5.6</version>
</dependency>
<!--JSON转换依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
三、类封装
第一个,请求结果工具类(方便数据转换):
package icu.liuwisdom.request.util;
import com.alibaba.fastjson.JSON;
import com.github.kevinsawicki.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* Http请求工具
*
* @author LDB
* @version 1.0
* @date 2022-07-25 15:10
*/
@Slf4j
@Component
public class HttpRequestUtil {
/**
* 获取最后请求到的数据
*
* @param request 请求后的结果
* @param c 指定类类型
* @return T
* @author LDB
* @date 2022-07-25
**/
public static <T> T getRequestResult(HttpRequest request, Class<T> c) {
log.info(request.url().toString());
if (!request.ok()) {
log.error(request.message());
}
return JSON.parseObject(request.body(), c);
}
}
第二个(因为我们需要用到一些不变的数据,请求key记得替换成自己的):
package icu.liuwisdom.request.gaode.common;
import java.util.Arrays;
import java.util.List;
/**
* 高德API
*
* @author LDB
* @version 1.0
* @date 2022-07-25 15:52
*/
public interface GaoDeApi {
/**
* 接口地址前缀
*
* @author LDB
* @date 2022-07-25 15:53
* @version 1.0
*/
String URL = "https://restapi.amap.com/v3/config/district?key=" + GaoDeApi.KEY + "&subdistrict=3&extensions=base&";
/**
* 请求key
*
* @author LDB
* @date 2022-07-25 15:55
* @version 1.0
*/
String KEY = "your self key!";
/**
* 省份关键字列表
*
* @author LDB
* @date 2022-07-25 22:20
* @version 1.0
*/
List<String> keywords = Arrays.asList(new String[]{"河北省", "山西省", "辽宁省", "吉林省", "黑龙江省", "江苏省", "浙江省", "安徽省", "福建省", "江西省", "山东省", "河南省", "湖北省", "湖南省", "广东省", "海南省", "四川省", "贵州省", "云南省", "陕西省", "甘肃省", "青海省", "台湾省", "内蒙古自治区", "广西壮族自治区", "西藏自治区", "宁夏回族自治区", "新疆维吾尔自治区", "北京市", "天津市", "上海市", "重庆市", "香港特别行政区", "澳门特别行政区"});
}
第三个,实体类(po、vo,需要对照高德API给的数据来)
package icu.liuwisdom.request.gaode;
import lombok.Data;
/**
* 高德数据结果
*
* @author LDB
* @version 1.0
* @date 2022-07-25 15:56
*/
@Data
public class GaoResult {
/**
* 返回结果状态值
*
* @author LDB
* @date 2022-07-25 22:12
* @version 1.0
*/
private String status;
/**
* 返回状态说明
*
* @author LDB
* @date 2022-07-25 22:12
* @version 1.0
*/
private String info;
/**
* 状态码
*
* @author LDB
* @date 2022-07-25 22:12
* @version 1.0
*/
private String infocode;
/**
* 查询个数
*
* @author LDB
* @date 2022-07-25 22:29
* @version 1.0
*/
private String count;
}
package icu.liuwisdom.request.gaode.vo;
import icu.liuwisdom.request.gaode.GaoResult;
import icu.liuwisdom.request.gaode.po.District;
import icu.liuwisdom.request.gaode.po.Districts;
import icu.liuwisdom.request.gaode.po.Suggestion;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 区域Vo
*
* @author LDB
* @version 1.0
* @date 2022-07-25 22:28
*/
@Data
public class DistrictsVo extends GaoResult {
/**
* 建议结果
*
* @author LDB
* @date 2022-07-25 22:30
* @version 1.0
*/
private Suggestion suggestion;
/**
* 行政区列表
*
* @author LDB
* @date 2022-07-25 22:32
* @version 1.0
*/
private List<Districts> districts = new ArrayList<>();
}
package icu.liuwisdom.request.gaode.po;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 建议结果列表
*
* @author LDB
* @version 1.0
* @date 2022-07-25 22:22
*/
@Data
public class Suggestion {
/**
* 建议关键字列表
*
* @author LDB
* @date 2022-07-25 22:23
* @version 1.0
*/
List<String> keywords = new ArrayList<>();
/**
* 建议城市列表
*
* @author LDB
* @date 2022-07-25 22:23
* @version 1.0
*/
List<String> cites = new ArrayList<>();
}
package icu.liuwisdom.request.gaode.po;
import icu.liuwisdom.core.modal.BaseModel;
import lombok.Data;
/**
* 行政区信息
*
* @author LDB
* @version 1.0
* @date 2022-07-25 22:25
*/
@Data
public class District extends BaseModel {
/**
* 主键id
*
* @author LDB
* @date 2022-07-25 22:46
* @version 1.0
*/
private String id;
/**
* 上级id
*
* @author LDB
* @date 2022-07-25 22:46
* @version 1.0
*/
private String parentId;
/**
* 城市编码
*
* @author LDB
* @date 2022-07-25 22:25
* @version 1.0
*/
private String cityCode;
/**
* 区域编码
*
* @author LDB
* @date 2022-07-25 22:25
* @version 1.0
*/
private String adcode;
/**
* 行政区名称
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String name;
/**
* 行政区边界坐标点
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String polyline;
/**
* 区域中心点
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String center;
/**
* 行政区划级别
* <p>
* <p>
* country:国家 province:省份(直辖市会在province和city显示) city:市(直辖市会在province和city显示) district:区县 street:街道
* <p>
*
* <p>
*
* <p>
*
* <p>
*
* @author LDB
* @date 2022-07-25 22:27
* @version 1.0
*/
private String level;
public Districts toVo() {
Districts vo = new Districts();
vo.setId(this.id);
vo.setParentId(this.parentId);
vo.setCityCode(this.cityCode);
vo.setAdcode(this.adcode);
vo.setName(this.name);
vo.setPolyline(this.polyline);
vo.setCenter(this.center);
vo.setLevel(this.level);
return vo;
}
}
package icu.liuwisdom.request.gaode.po;
import icu.liuwisdom.core.modal.BaseModel;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 行政区信息
*
* @author LDB
* @version 1.0
* @date 2022-07-25 22:25
*/
@Data
public class Districts extends BaseModel {
/**
* 主键id
*
* @author LDB
* @date 2022-07-25 22:46
* @version 1.0
*/
private String id;
/**
* 上级id
*
* @author LDB
* @date 2022-07-25 22:46
* @version 1.0
*/
private String parentId;
/**
* 城市编码
*
* @author LDB
* @date 2022-07-25 22:25
* @version 1.0
*/
private String cityCode;
/**
* 区域编码
*
* @author LDB
* @date 2022-07-25 22:25
* @version 1.0
*/
private String adcode;
/**
* 行政区名称
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String name;
/**
* 行政区边界坐标点
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String polyline;
/**
* 区域中心点
*
* @author LDB
* @date 2022-07-25 22:26
* @version 1.0
*/
private String center;
/**
* 行政区划级别
* <p>
* <p>
* country:国家 province:省份(直辖市会在province和city显示) city:市(直辖市会在province和city显示) district:区县 street:街道
* <p>
*
* <p>
*
* <p>
*
* <p>
*
* @author LDB
* @date 2022-07-25 22:27
* @version 1.0
*/
private String level;
/**
* 下级行政区列表,包含district元素
*
* @author LDB
* @date 2022-07-25 22:28
* @version 1.0
*/
private List<Districts> districts = new ArrayList<>();
public District toPo() {
District po = new District();
po.setId(this.id);
po.setParentId(this.parentId);
po.setAdcode(this.adcode);
po.setCityCode(this.cityCode);
po.setLevel(this.level);
po.setPolyline(this.polyline);
po.setCenter(this.center);
po.setName(this.name);
return po;
}
}
差点忘了,还有一个uuid类
package icu.liuwisdom.utils;
import java.util.UUID;
/**
* UUID工具类
* */
public class IdUtils {
public static String getUUID() {
String id = UUID.randomUUID().toString();
String[] split = id.split("-");
String res = new String();
for (String s : split) {
res += s;
}
return res;
}
}
四、数据库设计
CREATE TABLE `district` (
`id` varchar(32) DEFAULT NULL COMMENT '编号',
`parent_id` varchar(32) DEFAULT NULL COMMENT '上级行政区id',
`city_code` varchar(500) DEFAULT NULL COMMENT '城市编码',
`adcode` varchar(500) DEFAULT NULL COMMENT '区域编码',
`name` varchar(500) DEFAULT NULL COMMENT '行政区名称',
`polyline` varchar(5000) DEFAULT NULL COMMENT '行政区边界坐标点',
`center` varchar(500) DEFAULT NULL COMMENT '区域中心点',
`level` varchar(100) DEFAULT NULL COMMENT '行政区划级别 country:国家 province:省份(直辖市会在province和city显示) city:市(直辖市会在province和city显示) district:区县 street:街道',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`last_update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`last_update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remarks` varchar(255) DEFAULT NULL COMMENT '备注信息',
`del_flag` tinyint(4) DEFAULT '0' COMMENT '是否删除 -1:已删除 0:正常',
KEY `index_1` (`id`),
KEY `index_2` (`parent_id`),
KEY `index_3` (`parent_id`),
KEY `index_4` (`level`),
KEY `index_5` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='省份区域信息表';
四、核心代码
好啦,准备工作已经做完了,核心思路就是:按照省份关键字来循环调用接口,将获取到的数据新增到自己的数据库中,因为需要区分上下级关系,所以id由咱自己定!
package icu.liuwisdom.request.gaode.controller;
import com.github.kevinsawicki.http.HttpRequest;
import icu.liuwisdom.core.http.HttpResult;
import icu.liuwisdom.request.gaode.common.GaoDeApi;
import icu.liuwisdom.request.gaode.query.DistrictQuery;
import icu.liuwisdom.request.gaode.service.DistrictService;
import icu.liuwisdom.request.gaode.vo.DistrictsVo;
import icu.liuwisdom.request.util.HttpRequestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.val;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* <p>
* 省份区域信息表 前端控制器
* </p>
*
* @author ldb
* @since 2022-07-25
*/
@RestController
@Api(tags = "省份区域信息")
@RequestMapping("request/district")
public class DistrictController {
@Resource
DistrictService districtService;
@ApiOperation("请求省市区数据")
@GetMapping("/")
public HttpResult get() {
val city = GaoDeApi.keywords;
for (String c : city) {
DistrictsVo vo = HttpRequestUtil.getRequestResult(HttpRequest.get(GaoDeApi.URL + "keywords=" + c), DistrictsVo.class);
districtService.insert(vo);
}
return HttpResult.ok("获取省市区数据成功");
}
@ApiOperation("获取省市区")
@PostMapping("/tree")
public HttpResult post(@RequestBody DistrictQuery query) {
return HttpResult.ok("获取省市区成功", districtService.tree(query));
}
}
package icu.liuwisdom.request.gaode.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import icu.liuwisdom.request.gaode.mapper.DistrictMapper;
import icu.liuwisdom.request.gaode.po.District;
import icu.liuwisdom.request.gaode.po.Districts;
import icu.liuwisdom.request.gaode.query.DistrictQuery;
import icu.liuwisdom.request.gaode.service.DistrictService;
import icu.liuwisdom.request.gaode.vo.DistrictsVo;
import icu.liuwisdom.utils.IdUtils;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* <p>
* 省份区域信息表 服务实现类
* </p>
*
* @author ldb
* @since 2022-07-25
*/
@Service
public class DistrictServiceImpl extends ServiceImpl<DistrictMapper, District> implements DistrictService {
@Resource
DistrictMapper mapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void insert(DistrictsVo vo) {
// 请求到的数据为空
if (Objects.isNull(vo)) {
return;
}
// 获取区域信息
List<Districts> districts = vo.getDistricts();
List<Districts> districtList = new ArrayList<>();
// 递归传入父id(所有id都交由用户自行定义)
// 先设置所有一级的区域id
for (Districts district : districts) {
val parentId = IdUtils.getUUID();
district.setId(parentId);
// 如果有子区域,则递归设置
if (!district.getDistricts().isEmpty()) {
injectId(district.getDistricts(), parentId, districtList);
}
districtList.add(district);
}
if (!districtList.isEmpty()) {
List<District> list = districtList.stream().map(val -> val.toPo()).collect(Collectors.toList());
this.saveBatch(list);
}
}
@Override
public List<District> tree(DistrictQuery query) {
PageHelper.startPage(query.getPageNum(), query.getPageSize());
val wrapper = new LambdaQueryWrapper<District>()
.eq(StringUtils.isNotEmpty(query.getId()), District::getId, query.getId())
.eq(StringUtils.isNotEmpty(query.getParentId()), District::getParentId, query.getParentId())
.eq(StringUtils.isNotEmpty(query.getCityCode()), District::getCityCode, query.getCityCode())
.eq(StringUtils.isNotEmpty(query.getAdcode()), District::getAdcode, query.getAdcode())
.like(StringUtils.isNotEmpty(query.getName()), District::getName, query.getName())
.like(StringUtils.isNotEmpty(query.getPolyline()), District::getPolyline, query.getPolyline())
.like(StringUtils.isNotEmpty(query.getCenter()), District::getCenter, query.getCenter())
.eq(StringUtils.isNotEmpty(query.getLevel()), District::getLevel, query.getLevel());
return mapper.selectList(wrapper);
}
/**
* 生成子区域id数据
*
* @param districts 子区域列表
* @param parentId 父id
* @param districtList 要新增的区域数据列表
* @author LDB
* @date 2022-07-25
**/
private void injectId(List<Districts> districts, String parentId, List<Districts> districtList) {
for (Districts district : districts) {
String currentId = IdUtils.getUUID();
district.setId(currentId);
district.setParentId(parentId);
districtList.add(district);
if (!district.getDistricts().isEmpty()) {
injectId(district.getDistricts(), currentId, districtList);
}
}
}
}
五、大功告成⛏
附录-补充信息
package icu.liuwisdom.core.page;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 分页请求对象
*
* @author ldb
* @ClassName PageRequest.java
* @Data 2022-02-19 15:10
*/
@Data
@ApiModel("分页请求对象")
public class PageRequest implements Serializable {
@ApiModelProperty("页码")
private int pageNum = 1;
@ApiModelProperty("页数")
private int pageSize = 10;
@ApiModelProperty("关键字")
private String keyword;
@ApiModelProperty("多个状态值,根据多个条件查询时用到 比如:1,2,3")
private String dataStates;
@ApiModelProperty(value = "主表id,一对多分页使用", hidden = true)
private List<String> ids;
}
package icu.liuwisdom.core.http;
import icu.liuwisdom.constant.ErrorCode;
import icu.liuwisdom.constant.SystemConstant;
import icu.liuwisdom.utils.DateUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
* 请求结果封装类
*
* @author ldb
* @ClassName HttpResult.java
* @Data 2022-02-19 15:48
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("请求结果封装类")
public class HttpResult<T> {
@ApiModelProperty("响应码")
private int code;
@ApiModelProperty("响应消息")
private String msg;
@ApiModelProperty("响应数据")
private T data;
@ApiModelProperty("响应时间")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime time;
public static HttpResult<Boolean> error() {
return error(666, "请求失败");
}
public static HttpResult<Boolean> error(String msg) {
return error(666, msg);
}
public static HttpResult<Boolean> error(int code, String msg) {
return new HttpResult(code, msg, false, LocalDateTime.now());
}
public static HttpResult<Boolean> ok(String msg) {
return new HttpResult(200, msg, true, LocalDateTime.now());
}
public static <D> HttpResult<D> ok(String msg, D data) {
return new HttpResult<D>(200, msg, data, LocalDateTime.now());
}
public static <D> HttpResult<D> ok(D data) {
return new HttpResult<D>(200, "请求成功", data, LocalDateTime.now());
}
public static HttpResult<Boolean> ok() {
return ok("请求成功");
}
}