天天看點

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);
    }

}
           

繼續閱讀