1. 前言
公司项目需要全国省市区信息,然后就去百度搜索下载了一份,使用时发现数据不是最新的,后来百度了好多都不是最新数据,在查很多博客,说是去国家公开数据上面爬取,后来经过验证,国家统计局数据不是最新的,民政网数据正确但不好爬取,天气预报网爬取只有名称没有编码,最后查询到了高德地图,经过验证是最新数据也是最正确的。
2. 注册高德
高德地址:https://lbs.amap.com/api/webservice/guide/api/district/
注意:需要申请key,接口文档里面有说明。
3. RestTemplate配置
3.1、添加配置项
#RestTemplate配置 (0不受限制)
resttemplate.connection.connection-request-timeout=0
resttemplate.connection.connect-timeout=10000
resttemplate.connection.read-timeout=60000
resttemplate.connection.request-timeout=2000
3.2、创建配置类
package com.modules.data.config;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @Description: RestTemplate连接配置
* @author lc
*/
@Configuration
public class RestTemplateConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
// 最大连接数
private static Integer maxTota = 300;
// 同路由并发数
private static Integer maxPerRoute = 150;
// 连接超时
@Value("${resttemplate.connection.connect-timeout}")
private Integer connectTimeout;
// 数据读取超时时间
@Value("${resttemplate.connection.read-timeout}")
private Integer readTimeout;
// 连接不够用的等待时间
@Value("${resttemplate.connection.request-timeout}")
private Integer requestTimeout;
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
logger.info("开始配置restTemplate");
RestTemplate restTemplate = restTemplateBuilder.build();
restTemplate.getMessageConverters().add(new WxMappingJackson2HttpMessageConverter());
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
if (connectTimeout > 0) {
clientHttpRequestFactory.setConnectTimeout(connectTimeout);
logger.info("配置restTemplate-connectTimeout: {}", connectTimeout);
}
if (readTimeout > 0) {
clientHttpRequestFactory.setReadTimeout(readTimeout);
logger.info("配置restTemplate-readTimeout: {}", readTimeout);
}
restTemplate.setRequestFactory(clientHttpRequestFactory);
// restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
logger.info("restTemplate配置成功");
return restTemplate;
}
@Bean
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
try {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// 开始设置连接池
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(maxTota);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxPerRoute);
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
//0:false超时,禁止重复提交;3:true超时,重试次数3
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
HttpClient httpClient = httpClientBuilder.build();
// httpClient连接配置
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
clientHttpRequestFactory.setConnectTimeout(connectTimeout);
clientHttpRequestFactory.setReadTimeout(readTimeout);
clientHttpRequestFactory.setConnectionRequestTimeout(requestTimeout);
// 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。
clientHttpRequestFactory.setBufferRequestBody(false);
return clientHttpRequestFactory;
} catch (Exception e) {
logger.error("restTemplate初始化HTTP连接池出错!{}", e);
}
return null;
}
}
4. 实现
4.1、创建实体类
创建三张表,省份表,城市表,区县表;
package com.modules.data.access.dto;
public class BaseCodeProvince {
private Integer id;
private Integer provinceId;
private String province;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getProvinceId() {
return provinceId;
}
public void setProvinceId(Integer provinceId) {
this.provinceId = provinceId;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province == null ? null : province.trim();
}
}
package com.modules.data.access.dto;
public class BaseCodeCity {
private Integer id;
private Integer cityId;
private String city;
private Integer provinceId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCityId() {
return cityId;
}
public void setCityId(Integer cityId) {
this.cityId = cityId;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city == null ? null : city.trim();
}
public Integer getProvinceId() {
return provinceId;
}
public void setProvinceId(Integer provinceId) {
this.provinceId = provinceId;
}
}
package com.modules.data.access.dto;
public class BaseCodeArea {
private Integer id;
private Integer areaId;
private String area;
private Integer cityId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAreaId() {
return areaId;
}
public void setAreaId(Integer areaId) {
this.areaId = areaId;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area == null ? null : area.trim();
}
public Integer getCityId() {
return cityId;
}
public void setCityId(Integer cityId) {
this.cityId = cityId;
}
}
4.2、创建实现类
package com.modules.data.access.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.modules.data.access.dao.BaseCodeAreaMapper;
import com.modules.data.access.dao.BaseCodeCityMapper;
import com.modules.data.access.dao.BaseCodeProvinceMapper;
import com.modules.data.access.dto.BaseCodeArea;
import com.modules.data.access.dto.BaseCodeCity;
import com.modules.data.access.dto.BaseCodeProvince;
import com.modules.data.base.enums.PublicEnum;
import com.modules.data.base.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
/**
* 省市区信息
*/
@Service
public class RegionService {
private static Logger logger = LoggerFactory.getLogger(RegionService.class);
@Autowired
RestTemplate restTemplate;
@Autowired
private BaseCodeProvinceMapper provinceMapper;
@Autowired
private BaseCodeCityMapper cityMapper;
@Autowired
private BaseCodeAreaMapper areaMapper;
/**
* 获取省市区
*
* @return
*/
public JSONObject getRegionData() throws URISyntaxException {
StringBuilder sendUrl = null;
JSONObject responseJson = null;
List listP = new ArrayList();
List listC = new ArrayList();
List listA = new ArrayList();
try{
// 拼接参数
sendUrl = new StringBuilder("https://restapi.amap.com/v3/config/district")
.append("?key=").append("40240673aacea99917d")
.append("&keywords=").append("中华人民共和国")
.append("&subdistrict=3&extensions=base");
// 设置通用的请求属性
HttpHeaders headers = new HttpHeaders();
headers.set("Accept-Charset", "utf-8");
headers.add("Content-Type", "text/xml;charset=utf-8");
HttpEntity httpEntity = new HttpEntity(headers);
// 发送请求
ResponseEntity responseEntity = restTemplate.exchange(new URI(sendUrl.toString()), HttpMethod.GET, httpEntity, String.class);
String returnCode = responseEntity.getBody();
responseJson = JSONObject.parseObject(returnCode);
logger.debug("restTemplate返回值:", responseJson);
String statsus = responseJson.getString("status");
if (PublicEnum.YES.getCode().equals(statsus)) {
JSONArray arr = responseJson.getJSONArray("districts");
if(arr.size() <= 0){
return responseJson;
}
// 清理旧数据
deleteByExample();
// 1、更新省
JSONArray provinceJsonArray = responseJson.getJSONArray("districts").getJSONObject(0).getJSONArray("districts");
for (int i = 0; i < provinceJsonArray.size(); i++) {
JSONObject provinceJsonObject = provinceJsonArray.getJSONObject(i);
Integer provinceId = provinceJsonObject.getInteger("adcode");
BaseCodeProvince province = new BaseCodeProvince();
province.setProvinceId(provinceId);
province.setProvince(provinceJsonObject.getString("name"));
listP.add(province);
// 2、更新市
JSONArray cityJsonArray = provinceJsonObject.getJSONArray("districts");
for (int j = 0; j < cityJsonArray.size(); j++) {
JSONObject cityJsonObject = cityJsonArray.getJSONObject(j);
Integer cityId = cityJsonObject.getInteger("adcode");
BaseCodeCity city = new BaseCodeCity();
city.setProvinceId(provinceId);
city.setCityId(cityId);
city.setCity(cityJsonObject.getString("name"));
listC.add(city);
// 3、更新区县
JSONArray areaJsonArray = cityJsonObject.getJSONArray("districts");
for (int k = 0; k < areaJsonArray.size(); k++) {
JSONObject areaJsonObject = areaJsonArray.getJSONObject(k);
Integer areaId = areaJsonObject.getInteger("adcode");
BaseCodeArea area = new BaseCodeArea();
area.setCityId(cityId);
area.setAreaId(areaId);
area.setArea(areaJsonObject.getString("name"));
listA.add(area);
}
}
}
}else{
logger.info("获取省市区信息失败,三方接口返回值:", responseJson);
}
// 保存数据
saveInfo(listP, listC, listA);
}catch (Exception e){
logger.error("获取省市区异常!", e.getMessage());
}
return responseJson;
}
/**
* 清空数据
*/
@Transactional
public void deleteByExample(){
provinceMapper.deleteByExample(null);
cityMapper.deleteByExample(null);
areaMapper.deleteByExample(null);
}
/**
* 保存数据
*/
@Transactional
public void saveInfo(List listP, List listC, List listA){
provinceMapper.insertByList(listP);
cityMapper.insertByList(listC);
areaMapper.insertByList(listA);
}
}