在做一个电商项目过程中,需要获取设备地理信息,包括经纬度定位,附近地址等,于是写了一个工具类方便使用。
1.在使用百度地图API使,首先要获取官方授权,在http://lbsyun.baidu.com/index.php?title=androidsdk页面获取秘钥,然后按照要求申请即可,需要手机和百度账号及邮箱认证。激活后可看到后台页面,现在可以开始创建应用了,这里请求校验方式有两种,一种是白名单IP,另一种是SN校验(旁边有计算的说明),我选择SN校验:
计算sn:
** * Description:获取百度地理编码的sn的工具类 **/ public class BaiDuGeocodingSnCalUtil { private static final String HEADER = "/geocoder/v2/?"; public static String getSnCalString(String paramsStr) { String tempStr = null; try { // 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk String wholeStr = HEADER + paramsStr + Constants.BaiDu.SK; // 对上面wholeStr再作utf8编码 tempStr = URLEncoder.encode(wholeStr, Constants.UTF_8); tempStr = MD5(tempStr); } catch (Exception e) { Logger.debug(e.getMessage()); } return tempStr; } /** * 对Map内所有value作utf8编码,拼接返回结果 */ public static String toQueryString(Map<?, ?> data) throws UnsupportedEncodingException { StringBuilder queryString = new StringBuilder(); for (Map.Entry<?, ?> pair : data.entrySet()) { queryString.append(pair.getKey()); queryString.append("="); queryString.append(URLEncoder.encode((String) pair.getValue(), Constants.UTF_8)); queryString.append("&"); } if (queryString.length() > 0) { queryString.deleteCharAt(queryString.length() - 1); } return queryString.toString(); } /** * 来自stackoverflow的MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制 */ public static String MD5(String md5) { try { java.security.MessageDigest md = java.security.MessageDigest .getInstance("MD5"); byte[] array = md.digest(md5.getBytes()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < array.length; ++i) { sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100) .substring(1, 3)); } return sb.toString(); } catch (java.security.NoSuchAlgorithmException e) { Logger.debug(e.getMessage()); } return null; } }
发送请求也简单封装了一个http工具类:
public class SimulationRequestUtil { public static final int SUCCESS = 200; private SimulationRequestUtil() { } /** * get请求 * * @param url 请求路径 * @return 返回参数 */ public static String doGet(String url) { CloseableHttpClient client = null; try { client = HttpClients.createDefault(); //发送get请求 HttpResponse response = client.execute(new HttpGet(url)); //请求发送成功,并得到响应 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { //读取服务器返回过来的json字符串数据 return EntityUtils.toString(response.getEntity()); } } catch (IOException e) { Logger.warn(e.getMessage()); } finally { if (client != null) { try { client.close(); } catch (Exception e) { Logger.warn(e.getMessage()); } } } return null; } /** * post请求(用于key-value格式的参数) * * @param url 请求路径 * @param params 参数 * @return 返回数据 */ @SuppressWarnings("unchecked") public static String doPost(String url, Map params) { CloseableHttpClient client = null; BufferedReader in = null; try { // 定义HttpClient client = HttpClients.createDefault(); // 实例化HTTP方法 HttpPost request = new HttpPost(); request.setURI(new URI(url)); //设置参数 List<NameValuePair> nvps = new ArrayList<>(); for (Iterator<Map.Entry<Object, Object>> iterator = params.entrySet().iterator(); iterator.hasNext();) { Map.Entry<Object, Object> entry = iterator.next(); String name = (String) entry.getKey(); String value = String.valueOf(entry.getValue()); nvps.add(new BasicNameValuePair(name, value)); } request.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8)); HttpResponse response = client.execute(request); int code = response.getStatusLine().getStatusCode(); if (code == SUCCESS) { //请求成功 in = new BufferedReader(new InputStreamReader(response.getEntity() .getContent(), StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); String line = ""; String nl = System.getProperty("line.separator"); while ((line = in.readLine()) != null) { sb.append(line); sb.append(nl); } return sb.toString(); } else { return null; } } catch (Exception e) { Logger.warn(e.getMessage()); return null; } finally { if (in != null) { try { in.close(); } catch (Exception e) { Logger.warn(e.getMessage()); } } if (client != null) { try { client.close(); } catch (Exception e) { Logger.warn(e.getMessage()); } } } } /** * post请求(用于请求json格式的参数) * * @param url 请求路径 * @param params 参数 * @return 返回数据 */ public static String doPost(String url, String params) throws Exception { CloseableHttpClient httpclient = HttpClients.createDefault(); // 创建httpPost HttpPost httpPost = new HttpPost(url); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-Type", "application/json"); String charSet = "UTF-8"; StringEntity entity = new StringEntity(params, charSet); httpPost.setEntity(entity); CloseableHttpResponse response = null; try { response = httpclient.execute(httpPost); StatusLine status = response.getStatusLine(); int state = status.getStatusCode(); if (state == HttpStatus.SC_OK) { HttpEntity responseEntity = response.getEntity(); return EntityUtils.toString(responseEntity); } else { Logger.warn("请求返回:" + state + "(" + url + ")"); } } finally { if (response != null) { try { response.close(); } catch (IOException e) { Logger.warn(e.getMessage()); } } try { httpclient.close(); } catch (IOException e) { Logger.warn(e.getMessage()); } } return null; } }
2.准备就绪之后就是最重要的就是访问api接口获取想要的信息,可根据官方文档调整参数,http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
public class CityLatitudeAndLongitudeUtil { private static double EARTH_RADIUS = 6371.393; private static double rad(double d) { return d * Math.PI / 180.0; } /** * 根据地址获取经纬度信息 * @param area 区域 * @param location 地址 * @return CityLatitudeAndLongitudeBean 城市经纬度信息 */ public static CityLatitudeAndLongitudeBean getLatitudeAndLongitude(String area, String location) { CityLatitudeAndLongitudeBean result = null; try { StringBuilder url = new StringBuilder("http://api.map.baidu.com/geocoder/v2/?"); LinkedHashMap<String, String> paramsMap = new LinkedHashMap<>(); paramsMap.put("address", area + (StringUtils.isNotEmpty(location) ? location : StringUtils.EMPTY)); paramsMap.put("output", "json"); paramsMap.put("ak", Constants.BaiDu.AK); // 调用下面的toQueryString方法,对LinkedHashMap内所有value作utf8编码,拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak String paramsStr = BaiDuGeocodingSnCalUtil.toQueryString(paramsMap); url.append(paramsStr); String sn = BaiDuGeocodingSnCalUtil.getSnCalString(paramsStr); url.append("&sn="); url.append(sn); result = JSON.parseObject(SimulationRequestUtil.doGet(url.toString()), new TypeReference<CityLatitudeAndLongitudeBean>() { }); if (result == null || result.getStatus() == null || result.getStatus() != 0) { return null; } } catch (Exception e) { Logger.debug(e.getMessage()); } return result; } /** * 根据经纬度获取地址及周边信息 * @param lat 纬度 * @param lng 经度 * @return ProvinceBean 城市信息 */ public static ProvinceBean getProvince(String lat, String lng) { ProvinceBean result = null; try { StringBuilder url = new StringBuilder("http://api.map.baidu.com/geocoder/v2/?"); LinkedHashMap<String, String> paramsMap = new LinkedHashMap<>(); paramsMap.put("location", lat+","+lng); String put = paramsMap.put("output", "json"); paramsMap.put("pois", "1"); paramsMap.put("latest_admin", "1"); paramsMap.put("ak", Constants.BaiDu.AK); String paramsStr = BaiDuGeocodingSnCalUtil.toQueryString(paramsMap); url.append(paramsStr); String sn = BaiDuGeocodingSnCalUtil.getSnCalString(paramsStr); url.append("&sn="); url.append(sn); String json = SimulationRequestUtil.doGet(url.toString()); System.out.println(json); result = JSON.parseObject(json, new TypeReference<ProvinceBean>() { }); if (result == null || result.getStatus() == null || result.getStatus() != 0) { return null; } } catch (Exception e) { Logger.debug(e.getMessage()); } return result; } /** * 计算两个经纬度之间的距离 * * @param lat1 * @param lng1 * @param lat2 * @param lng2 * @return */ public static double getDistance(double lat1, double lng1, double lat2, double lng2) { double radLat1 = rad(lat1); double radLat2 = rad(lat2); double a = radLat1 - radLat2; double b = rad(lng1) - rad(lng2); double s = 2 * Math.asin(Math.sqrt(Math.abs(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)))); s = s * EARTH_RADIUS; s = Math.round(s * 1000); return s; } /** * 测试 * @param args */ public static void main(String []args){ System.out.println(getLatitudeAndLongitude("福州","福州")); System.out.println(getProvince("26.080429420698079","119.30346983854001")); } }
3.返回结果是json数据,可以自行封装需要的数据,在此附上我的信息封装类:
@Data是引入了lombok插件,简化开发,不理解的可自行百度。 其余是一些swagger注解。
/** * Description:城市经纬度 **/ @Data public class CityLatitudeAndLongitudeBean implements Serializable { private static final long serialVersionUID = 9112556610655198188L; private Integer status; private Result result; }
/** * Description:城市经纬度的结果 **/ @Data public class Result implements Serializable { private static final long serialVersionUID = 5142442006448398929L; private Location location; private String precise; private String confidence; private String level; }
/** * Description:经纬度城市 **/ @Data @ApiModel(value = "经纬度城市") public class ProvinceBean implements Serializable { private static final long serialVersionUID = 9112556610655198166L; private Integer status; private ProvinceLocation result; }
/** * Description:经纬度城市 **/ @Data @ApiModel(value = "经纬度城市") public class ProvinceLocation implements Serializable { private static final long serialVersionUID = 1570896924286528777L; @ApiModelProperty(value = "纬度") private String lng; @ApiModelProperty(value = "经度") private String lat; @ApiModelProperty(value = "地址信息") private AddressComponent addressComponent; @ApiModelProperty(value = "附近地址") private List<AddressPois> pois; }
** * Description:城市 **/ @Data public class AddressComponent implements Serializable { private static final long serialVersionUID = 1570896924286528788L; private String country; private String province; private String city; private String district; private String street; }
/** * Description:城市周边信息 **/ @Data @ApiModel(value = "城市周边信息") public class AddressPois implements Serializable { private static final long serialVersionUID = 1570896924286528755L; @ApiModelProperty(value = "地址") private String addr; @ApiModelProperty(value = "名称") private String name; @ApiModelProperty(value = "经纬度") private ProvincePoint point; @ApiModelProperty(value = "类型") private String poiType; @ApiModelProperty(value = "标签") private String tag; }
4.测试结果
CityLatitudeAndLongitudeBean(status=0, result=Result(location=Location(lng=119.30346983854001, lat=26.080429420698079), precise=0, confidence=10, level=城市))
ProvinceBean(status=0, result=ProvinceLocation(lng=null, lat=null, addressComponent=AddressComponent(country=中国, province=福建省, city=福州市, district=鼓楼区, street=乌山路), pois=[AddressPois(addr=福州市鼓楼区乌山路96号, name=福州市人民政府, point=ProvincePoint(x=119.30289474335273, y=26.0805464063163), poiType=政府机构, tag=政府机构;各级政府), AddressPois(addr=光禄新坊2座1楼16号店面, name=中国工商银行(福州灵响支行), point=ProvincePoint(x=119.30390084552356, y=26.080724886227349), poiType=金融, tag=金融;银行), AddressPois(addr=乌山路92, name=福州市机关事务管理局, point=ProvincePoint(x=119.30403559135002, y=26.08070866079226), poiType=政府机构, tag=政府机构;行政单位), AddressPois(addr=福建省福州市鼓楼区乌山路92号, name=市委大院, point=ProvincePoint(x=119.30382898108279, y=26.080789787944974), poiType=房地产, tag=房地产;住宅区), AddressPois(addr=乌山路59, name=福建移动通信大厦, point=ProvincePoint(x=119.30229287866124, y=26.079353828941117), poiType=房地产, tag=房地产;写字楼), AddressPois(addr=福州市鼓楼区加洋路26号, name=协和公寓, point=ProvincePoint(x=119.30431406605801, y=26.078940074737014), poiType=房地产, tag=房地产;住宅区), AddressPois(addr=福州市鼓楼区乌山路53号福建黎明大酒店, name=中国工商银行(福州南门支行营业室), point=ProvincePoint(x=119.30562559210215, y=26.0808790277473), poiType=金融, tag=金融;银行), AddressPois(addr=福州市鼓楼区加洋路23号, name=福建煤田地质博物馆, point=ProvincePoint(x=119.30494287991479, y=26.079004977455033), poiType=旅游景点, tag=旅游景点;博物馆), AddressPois(addr=福州市鼓楼区乌山路80号, name=山水知音, point=ProvincePoint(x=119.30537406655944, y=26.081665957572313), poiType=购物, tag=购物;商铺), AddressPois(addr=鼓楼区乌山路53号(市政府对面), name=海通商务酒店(斗西路), point=ProvincePoint(x=119.30562559210215, y=26.080294911429247), poiType=酒店, tag=酒店;二星级)]))