(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、控制台输出
2、同时生成一个csv结果文件,使用excel打开部分结果如下
将拿到的结果文件导入数据库的新表中,写一个sql语句通过主键条件更新源表的经纬度字段就顺利完成任务。以上就是对地址转换经纬度的一点总结和分享,觉得不错的话,欢迎关注java基础笔记。