高德官方地址
/**
* @author 周坤
* @date Create in 10:51 2022/4/18
* 高德地理位置信息
* 地理/逆地理编码 :https://lbs.amap.com/api/webservice/guide/api/georegeo
* 地理编码:将详细的结构化地址转换为高德经纬度坐标。且支持对地标性名胜景区、建筑物名称解析为高德经纬度坐标。
* 逆地理编码:将经纬度转换为详细结构化的地址,且返回附近周边的POI、AOI信息。
*/
@Slf4j
public class GeoLocation {
// 高德秘钥
private static final String APP_CODE_GAODE = "44aa4b2a7772504960b691cfb9802";
/**
* 地理编码
* 根据地址获取经纬度,调用量上限:300000
*
* @param address 填写结构化地址信息:省份+城市+区县+城镇+乡村+街道+门牌号码 例[北京市朝阳区阜通东大街6号]
* @param city 市,可选 例如[北京]
* @return java.lang.String
*/
public static String GetLocationByAddress(String address, String city) {
log.info("地理编码:address=" + address + ",currentCity=" + city);
try {
HashMap<String, Object> parameters = new HashMap<>(3);
parameters.put("address", address);
parameters.put("city", city);
parameters.put("key", APP_CODE_GAODE);
// 高德获取地理信息
String response = HttpUtil.get("https://restapi.amap.com/v3/geocode/geo", parameters);
JSONObject responseJson = JSONUtil.parseObj(response);
String status = responseJson.get("status").toString();
if (!"1".equals(status)) {
log.error("列表信息获取失败,关键字:" + address + "城市:" + city);
return null;
}
JSONArray geocodes = responseJson.getJSONArray("geocodes");
return JSONUtil.parseObj(geocodes.get(0)).get("location").toString();
} catch (Exception ex) {
log.error("调用接口失败!" + ex.getMessage());
return null;
}
}
/**
* 逆地理编码
* 根据经纬度获取地址,调用量上限:300000
*
* @param location 经纬度:经度在前,纬度在后,经纬度间以“,”分割
* @return java.lang.String
*/
public static String GetAddressByLocation(String location) {
log.info("逆地理编码:location=" + location);
try {
HashMap<String, Object> parameters = new HashMap(16);
parameters.put("location", location);
parameters.put("key", APP_CODE_GAODE);
// 高德获取地理信息
String response = HttpUtil.get("https://restapi.amap.com/v3/geocode/regeo", parameters);
JSONObject responseJson = JSONUtil.parseObj(response);
String status = responseJson.get("status").toString();
if (!"1".equals(status)) {
log.error("列表信息获取失败,经纬度:" + location);
return null;
}
JSONObject regeocode = responseJson.getJSONObject("regeocode");
return regeocode.get("formatted_address").toString();
} catch (Exception ex) {
log.error("调用接口失败!" + ex.getMessage());
return null;
}
}
}
/**
* @author 周坤
* @date Create in 11:44 2022/4/18
*/
@Slf4j
public class DistanceUtils {
/**
* 地球半径,单位 km
*/
private static final double EARTH_RADIUS = 6378.137;
/**
* 基于余弦定理求两经纬度距离
* Math.pow(x,y) //这个函数是求x的y次方
* Math.toRadians //将一个角度测量的角度转换成以弧度表示的近似角度
* Math.sin //正弦函数
* Math.cos //余弦函数
* Math.sqrt //求平方根函数
* Math.asin //反正弦函数
*/
public static double getDistanceStr(String lng1, String lat1, String lng2, String lat2) {
return getDistance(new Double(lng1), new Double(lat1), new Double(lng2), new Double(lat2));
}
/**
* 根据经纬度计算两点间的距离
* 基于余弦定理求两经纬度距离
*
* @param longitude1 第一个点的经度
* @param latitude1 第一个点的纬度
* @param longitude2 第二个点的经度
* @param latitude2 第二个点的纬度
* @return 返回距离 单位千米
*/
public static double getDistance(double longitude1, double latitude1, double longitude2, double latitude2) {
log.info("经纬度距离:longitude1=" + longitude1 + ",latitude1=" + latitude1 + ",longitude2=" + longitude2 + ",latitude2=" + latitude2);
// 纬度
double lat1 = Math.toRadians(latitude1);
double lat2 = Math.toRadians(latitude2);
// 经度
double lng1 = Math.toRadians(longitude1);
double lng2 = Math.toRadians(longitude2);
// 纬度之差
double a = lat1 - lat2;
// 经度之差
double b = lng1 - lng2;
// 计算两点距离的公式
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
// 弧长乘地球半径, 返回单位: 千米
s = s * EARTH_RADIUS;
return s;
}
/**
* 根据经纬度,计算两点间的距离
* 由于三角函数中特定的关联关系,Haversine公式的最终实现方式可以有多种,比如借助转角度的函数atan2:
*
* @param longitude1 第一个点的经度
* @param latitude1 第一个点的纬度
* @param longitude2 第二个点的经度
* @param latitude2 第二个点的纬度
* @return double
*/
public static double getDistance2(double longitude1, double latitude1,
double longitude2, double latitude2) {
double latDistance = Math.toRadians(longitude1 - longitude2);
double lngDistance = Math.toRadians(latitude1 - latitude2);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(Math.toRadians(longitude1)) * Math.cos(Math.toRadians(longitude2))
* Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return c * EARTH_RADIUS;
}
}
/**
* @author 周坤
* @date Create in 11:45 2022/4/18
*/
@Slf4j
public class GeoDistance {
/**
* 根据位置计算距离
*
* @param origin 出发点,市区与详细地址中间用逗号拼接,例如:南京市,仙林中心
* @param destination 目的地,与出发点相同
* @return double
*/
public static double getDistance(String origin, String destination) {
if (StringUtils.isEmpty(origin) || StringUtils.isEmpty(destination)) {
log.info("出发点或者目的地为空!");
return 0;
}
String[] originList = origin.split(",");
String[] destinationList = destination.split(",");
// 获取经纬度
String originLocation = GeoLocation.GetLocationByAddress(originList[1], originList[0]);
String destinationLocation = GeoLocation.GetLocationByAddress(destinationList[1], destinationList[0]);
// 根据经纬度计算距离
double distance = DistanceUtils.getDistanceStr(originLocation.split(",")[0], originLocation.split(",")[1], destinationLocation.split(",")[0], destinationLocation.split(",")[1]);
BigDecimal bg = BigDecimal.valueOf(distance);
double f1 = bg.setScale(2, RoundingMode.HALF_UP).doubleValue();
log.info("两地距离: " + f1 + "KM");
return distance;
}
}
@Test
public void test1() {
String s = GeoLocation.GetLocationByAddress("陕西省西安市雁塔区", "西安");
String s1 = GeoLocation.GetLocationByAddress("广东省深圳市光明区", "深圳");
assert s != null;
String[] split = s.split(",");
assert s1 != null;
String[] split1 = s1.split(",");
Console.log(s);
Console.log(s1);
double distance = GeoDistance.getDistance("西安,陕西省西安市雁塔区东八里村新村一巷", "深圳,广东省深圳市光明区");
Console.log(distance);
}