java实现调用百度接口将大量数据库中保存的地址转换为经纬度(下)

(7)所有代码如下:

package com.forceclouds.crm.local;
 
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.text.csv.CsvWriter;
import com.google.common.collect.Maps;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import org.springframework.web.client.RestTemplate;
 
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
 
/*
 *@create by jiankang
 *@date 2020/6/3 time 14:59
 */
 
public class GPSTest {
    private static String URL = "http://api.map.baidu.com/geocoding/v3/?address={address}&key=SkSf";
    private static RestTemplate restTemplate = new RestTemplate();
 
    public static void main(String[] args) {
        List<ResultBean> datas = new ArrayList<>();
        ResultBean title = new ResultBean("external_id", "address", "longitude", "latitude");
        datas.add(title);
        String sourcePath = "C:\\Users\\ForceClouds\\Desktop\\aaa.csv";
        String goalPath = "C:\\Users\\ForceClouds\\Desktop\\jiangkang0905.csv";
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("经纬度转换运行程序");
        readCSV(datas, sourcePath);
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());
        writeCSV(datas, goalPath);
    }
 
    public static void writeCSV(List<ResultBean> datas, String goalPath) {
        CsvWriter csvWriter = new CsvWriter(new File(goalPath));
        for (ResultBean data : datas) {
            csvWriter.write(new String[]{data.getExternal_id(), data.getAddress(), data.getLongitude(), data.getLatitude()});
        }
        csvWriter.close();
    }
 
    public static void readCSV(List<ResultBean> datas, String sourcePath) {
        List<ResultBean> failData = new ArrayList<>();
        try (CSVReader csvReader = new CSVReaderBuilder(new BufferedReader(new InputStreamReader(new FileInputStream(new File(sourcePath)), "utf-8"))).build()) {
            Iterator<String[]> iterator = csvReader.iterator();
            //导出文件有标题行,去掉标题行,没有就不需要
            iterator.next();
            while (iterator.hasNext()) {
                String[] next = iterator.next();
                String address = next[1].replaceAll("\\s*", "");
                ResultBean resultBean = new ResultBean(next[0], address, null, null);
 
                //百度接口地址转换经纬度方法
                try{
                    getLngLat(datas, failData, resultBean);
                }catch (Exception e){ }
            }
 
            //失败数据再次请求百度接口,最多循环一千次,防止失败数据出现程序永不停止
            int i = 1000;
            while (failData.size() > 0 && i > 0) {
                List<ResultBean> tempFailData = new ArrayList<>(failData);
                failData.clear();
                for (ResultBean resultBean : tempFailData) {
                    try{
                    getLngLat(datas, failData, resultBean);
                }catch (Exception e){ }
                }
                i--;
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("fail record:" + failData.size());
        }
    }
 
 
    private static void getLngLat(List<ResultBean> datas, List<ResultBean> failData, ResultBean resultBean) {
        Map<String, String> map = Maps.newHashMap();
        map.put("address", resultBean.getAddress());
        String response = restTemplate.getForObject(URL, String.class, map);
        if (response.contains("GeocoderSearchResponse")) {
            GeocoderSearchResponse g = JAXB.unmarshal(new StringReader(response), GeocoderSearchResponse.class);
            if (g.status.equals("OK")) {
                resultBean.setLatitude(g.result.location.lat);
                resultBean.setLongitude(g.result.location.lng);
                datas.add(resultBean);
            } else {
                failData.add(resultBean);
            }
        } else {
            failData.add(resultBean);
        }
    }
 
 
    @XmlRootElement(name = "GeocoderSearchResponse")
    static class GeocoderSearchResponse {
        private String status;
 
        private Result result;
 
 
        public String getStatus() {
            return status;
        }
 
        public void setStatus(String status) {
            this.status = status;
        }
 
        public Result getResult() {
            return result;
        }
 
        public void setResult(Result result) {
            this.result = result;
        }
    }
 
    @XmlRootElement
    static class Result {
        private Location location;
 
 
        public Location getLocation() {
            return location;
        }
 
        public void setLocation(Location location) {
            this.location = location;
        }
    }
 
    @XmlRootElement
    static class Location {
        private String lat;
        private String lng;
 
        public String getLat() {
            return lat;
        }
 
        public void setLat(String lat) {
            this.lat = lat;
        }
 
        public String getLng() {
            return lng;
        }
 
        public void setLng(String lng) {
            this.lng = lng;
        }
    }
 
 
    static class ResultBean {
 
        private String external_id;
        //百度经纬度
        private String longitude;
        private String latitude;
 
        //address
        private String address;
 
        public ResultBean(String external_id, String address, String longitude, String latitude) {
            this.external_id = external_id;
            this.longitude = longitude;
            this.latitude = latitude;
            this.address = address;
        }
 
        public String getExternal_id() {
            return external_id;
        }
 
        public String getAddress() {
            return address;
        }
 
 
        public String getLongitude() {
            return longitude;
        }
 
        public String getLatitude() {
            return latitude;
        }
 
        public void setExternal_id(String external_id) {
            this.external_id = external_id;
        }
 
        public void setLongitude(String longitude) {
            this.longitude = longitude;
        }
 
        public void setLatitude(String latitude) {
            this.latitude = latitude;
        }
 
        public void setAddress(String address) {
            this.address = address;
        }
    }
}

2、实现返回json格式并解析获取经纬度

Ⅰ、  第一种比较简单,只需要把上面完整代码中url改一下,并且getLngLat方法换一下就可以了

(1)请求百度api加一个output=json的参数。

 private static String URL = "http://api.map.baidu.com/geocoding/v3/?address={address}&output=json&key=SkSf";

(2)通过new JacksonJsonParser()对返回值进行解析,注意判断返回值是否为html形式的内容,是的话需要收集重新请求。代码如下。

    private static void getLngLat(List<ResultBean> datas, List<ResultBean> failData, ResultBean resultBean) {
        Map<String, String> map = Maps.newHashMap();
        map.put("address", resultBean.getAddress());
//        restTemplate.getMessageConverters().add(new MyMappingJackson2HttpMessageConverter());
        String response = restTemplate.getForObject(URL, String.class, map);
        if (response != null && response.contains("lng") && response.contains("lat")) {
            final Map<String, Object> geocoderResult = new JacksonJsonParser().parseMap(response);
            Map location = (Map) ((Map) geocoderResult.get("result")).get("location");
            Double lng = (Double) location.get("lng");
            System.out.println(lng);
            Double lat = (Double) location.get("lat");
            System.out.println(lat);
            ResultBean bean = new ResultBean(resultBean.getExternal_id(), resultBean.getAddress(), String.valueOf(lng), String.valueOf(lat));
            datas.add(bean);
        } else {
            failData.add(resultBean);
        }
    }

Ⅱ、另一种解析json方式是我们根据返回值,封装一个bean对象使用RestTemplate的getForObject直接转换为bean类型

(1)封装的bean如下:

    static class GeocoderResult implements Serializable {
        String status;
        Map result;
 
        public String getStatus() {
            return status;
        }
 
        public void setStatus(String status) {
            this.status = status;
        }
 
        public Map getResult() {
            return result;
        }
 
        public void setResult(Map result) {
            this.result = result;
        }
 
        @Override
        public String toString() {
            return super.toString();
        }
    }

(2)、请求百度api接口如下:

    private static void getLngLat2(List<ResultBean> datas, List<ResultBean> failData, ResultBean resultBean) {
        Map<String, String> map = Maps.newHashMap();
        map.put("address", resultBean.getAddress());
        restTemplate.getMessageConverters().add(new MyMappingJackson2HttpMessageConverter());
        try {
            GeocoderResult  geocoderResult = restTemplate.getForObject(URL, GeocoderResult.class, map);
            if (geocoderResult.status.equals("OK")) {
                Map location = (Map) geocoderResult.getResult().get("location");
                Double lng = (Double) location.get("lng");
                Double lat = (Double) location.get("lat");
                ResultBean bean = new ResultBean(resultBean.getExternal_id(), resultBean.getAddress(), String.valueOf(lng), String.valueOf(lat));
                datas.add(bean);
            } else {
                failData.add(resultBean);
            }
        } catch (RestClientException e) {
            failData.add(resultBean);
        }
    }

(3)上面方法中我们对restTemplate加了一个自定义的MyMappingJackson2HttpMessageConverter实例,之所以自定义一个,是因为restTemplate不支持接口返回MediaType类型为text/javascript以及为text/html类型的返回值的转换,不加会报错信息:UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class GPSTest2$GeocoderResult] and content type [text/javascript;charset=utf-8],同时当返回html这种错误值时,会转换失败进入catch代码块中,我们需要收集起来,下次继续请求。MyMappingJackson2HttpMessageConverter类代码如下


    static class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
 
        public MyMappingJackson2HttpMessageConverter() {
            List<MediaType> mediaTypes = new ArrayList<>();
            mediaTypes.add(new MediaType("text", "javascript"));
            mediaTypes.add(new MediaType("text", "html"));
            setSupportedMediaTypes(mediaTypes);
        }
    }

五、成果展示及总结

不论是请求百度接口返回xml类型获取经纬度还是返回json类型获取经纬度,都会得到同样的结果,程序正确执行完成。

1、控制台输出

java实现调用百度接口将大量数据库中保存的地址转换为经纬度(下)

2、同时生成一个csv结果文件,使用excel打开部分结果如下

java实现调用百度接口将大量数据库中保存的地址转换为经纬度(下)

将拿到的结果文件导入数据库的新表中,写一个sql语句通过主键条件更新源表的经纬度字段就顺利完成任务。以上就是对地址转换经纬度的一点总结和分享,觉得不错的话,欢迎关注java基础笔记。

上一篇:java获取mac地址-屏蔽ip封mac地址


下一篇:最适合 Java 开发者使用的 IDE 插件——Cloud Toolkit