天天看点

Spring Boot2 调取高德行政区域数据示例

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<BaseCodeProvince> listP = new ArrayList<BaseCodeProvince>();
        List<BaseCodeCity> listC = new ArrayList<BaseCodeCity>();
        List<BaseCodeArea> listA = new ArrayList<BaseCodeArea>();
        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<String> 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<BaseCodeProvince> listP, List<BaseCodeCity> listC, List<BaseCodeArea> listA){
        provinceMapper.insertByList(listP);
        cityMapper.insertByList(listC);
        areaMapper.insertByList(listA);
    }

}
           

继续阅读