在实际业务开发中,可能需要使用到 打卡,签到等功能,则 就需要调用第三方地图API。
百度WebAPI地址:http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad
高德WebAPI地址:https://lbs.amap.com/api/webservice/guide/api/georegeo
代码说明:
默认使用的时百度API,可以通过修改参数的方式他调整。代码中使用到的经纬度均为百度API对应的经纬度,
如果切换为高德API,在代码中有将 百度 经纬度转成为 高德 经纬度,特此说明。
配置文件XXX.yml
map:
# 根据经纬度转换地址的百度API的url
getAddressByLngAndLat: https://api.map.baidu.com/geocoder/v2/?location=
# 根据实际地址转换经纬度的百度API的URL
getLngAndLatByAddress: https://api.map.baidu.com/geocoder/v2/?address=
# 根据实际地址转换经纬度的高德API 使用的 KEY
KEY_1: XXXXXXXXXXX
# 高德地图API
GdMapUrl: https://restapi.amap.com/v3/geocode/
# 高德地图API 使用的key
KEY_2 : XXXXXXXXXXX
# 调整使用的地图API 开关 false->使用百度 true->使用高德
useGd : true
#网络代理信息
http:
proxy:
enable: true
host: 0.0.0.0
port: 8080
工具类:
方法简单说明:
getGeocoderLatitude(String) :返回输入地址的经纬度坐标 key lng(经度),lat(纬度)
getAdd(String log, String lat) :根据经纬度信息 获取实际的地理位置
GetDistance(double lat1, double lng1, double lat2, double lng2):计算两个经纬度之间的距离 计算结果单位:米
工具类代码:
/**
* 打卡、签到 用到的 XY坐标和地理位置之前的转换、两组经纬度之间计算距离
*/
@Configuration
public class MapUtil {
private static final Logger logger = LoggerFactory.getLogger(MapUtil.class);
/**
* 百度API 根据实际地址转换经纬度的API 使用的 KEY
*/
public static String KEY_1;
private static double EARTH_RADIUS = 6371.393;
/**
* 百度API 根据经纬度转换地址的API的url
*/
private static String getAddressByLngAndLat;
/**
* 百度API 根据实际地址转换经纬度的API的URL
*/
private static String getLngAndLatByAddress;
/**
* 高德API 使用 的 地图 PAI地址
*/
private static String gdMapUrl;
/**
* 高德API 使用 的 key
*/
private static String KEY_2;
/**
* 调整使用的地图API 开关 false->使用百度 true->使用高德
*/
private static Boolean useGd;
private static boolean proxyEnable = false;
private static String proxyhost;
private static int proxyPort = 80;
private static double rad(double d) {
return d * Math.PI / 180.0;
}
public static String getKEY_1() {
return KEY_1;
}
@Value("${map.KEY_1}")
public void setKEY_1(String kEY_1) {
MapUtil.KEY_1 = kEY_1;
}
public static String getGetAddressByLngAndLat() {
return getAddressByLngAndLat;
}
@Value("${map.getAddressByLngAndLat}")
public void setGetAddressByLngAndLat(String getAddressByLngAndLat) {
MapUtil.getAddressByLngAndLat = getAddressByLngAndLat;
}
public static String getGetLngAndLatByAddress() {
return getLngAndLatByAddress;
}
@Value("${map.getLngAndLatByAddress}")
public void setGetLngAndLatByAddress(String getLngAndLatByAddress) {
MapUtil.getLngAndLatByAddress = getLngAndLatByAddress;
}
public static boolean isProxyEnable() {
return proxyEnable;
}
@Value(value = "${http.proxy.enable:false}")
public void setProxyEnable(boolean proxyEnable) {
MapUtil.proxyEnable = proxyEnable;
}
public static String getProxyhost() {
return proxyhost;
}
@Value(value = "${http.proxy.host}")
public void setProxyhost(String proxyhost) {
MapUtil.proxyhost = proxyhost;
}
public static int getProxyPort() {
return proxyPort;
}
@Value(value = "${http.proxy.port:80}")
public void setProxyPort(int proxyPort) {
MapUtil.proxyPort = proxyPort;
}
public static String getGdMapUrl() {
return gdMapUrl;
}
@Value("${map.GdMapUrl}")
public void setGdMapUrl(String gdMapUrl) {
MapUtil.gdMapUrl = gdMapUrl;
}
public static String getKEY_2() {
return KEY_2;
}
@Value("${map.KEY_2}")
public void setKEY_2(String kEY_2) {
KEY_2 = kEY_2;
}
public static Boolean getUseGd() {
return useGd;
}
@Value("${map.useGd}")
public void setUseGd(Boolean useGd) {
MapUtil.useGd = useGd;
}
/**
* 返回输入地址的经纬度坐标 key lng(经度),lat(纬度)
*/
public static Map<String, String> getGeocoderLatitude(String address) {
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->入参,address=" + address);
BufferedReader in = null;
try {
// 将地址转换成utf-8的16进制
address = URLEncoder.encode(address, "UTF-8");
String getGeocoderLatitudeUrl = getGeocoderLatitudeMapUrl(address);
URL tirc = new URL(getGeocoderLatitudeUrl);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) openConnection(tirc);
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String res;
StringBuilder sb = new StringBuilder("");
while ((res = in.readLine()) != null) {
sb.append(res.trim());
}
String str = sb.toString();
return dealReturnJson(str);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
try {
in.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
return null;
}
/**
* 根据配置的开关 获取地图 根据地址计算经纬度的API 对应的 url
* @return
*/
public static String getGeocoderLatitudeMapUrl(String address) {
if(useGd) {//使用高德地图API
return gdMapUrl + "geo?address=" + address + "&output=json&key="+KEY_2+"";
}else {//默认使用百度API
return getLngAndLatByAddress + address + "&output=json&ak=" + KEY_1+"&s=1";
}
}
/**
* 解析 逆向请求 返回地址信息
* @param str
* @return
*/
public static Map<String, String> dealReturnJson(String str){
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->str="+str);
JSONObject jsonObject = JSON.parseObject(str);
Map<String, String> map = null;
String status = jsonObject.getString("status");
if(useGd) {//使用高德
logger.info("use 高德API------");
if("1".equals(status)){// 1 表示查询成功
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->实际的物理地址转经纬度转换成功,status="+status);
JSONArray arr = JSON.parseArray(jsonObject.getString("geocodes"));
JSONObject obj = JSON.parseObject(arr.getString(0));
String location = obj.getString("location");
map = new HashMap<String, String>();
map.put("lng", location.split(",")[0]);
map.put("lat", location.split(",")[1]);
return map;
}else if(!"1".equals(status)){
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->实际的物理地址转经纬度转换,失败 status="+status);
return null;
}
}else {//默认使用百度
logger.info("use 百度API------");
if("0".equals(status)){// 0 表示查询成功
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->实际的物理地址转经纬度转换成功,status="+status);
JSONObject result_obj = JSON.parseObject(jsonObject.getString("result"));
String confidence = result_obj.getString("confidence");
String location_obj = result_obj.getString("location");
JSONObject location_ = JSON.parseObject(location_obj.toString());
map = new HashMap<String, String>();
map.put("lng", location_.getString("lng"));
map.put("lat", location_.getString("lat"));
map.put("confidence", confidence);
return map;
}else if(!"0".equals(status)){
logger.info("\n【返回输入地址的经纬度坐标】getGeocoderLatitude----->实际的物理地址转经纬度转换,失败 status="+status);
return null;
}
}
return null;
}
/**
* 计算两个经纬度之间的距离 计算结果单位:米
*
* @param lat1
* 纬度1
* @param lng1
* 经度1
* @param lat2
* 纬度2
* @param lng2
* 经度2
* @return
*/
public static double GetDistance(double lat1, double lng1, double lat2, double lng2) {
if(useGd) { //使用高德地图API
double[] arr1 = LngLonUtil.bd09_To_Gcj02(lat1, lng1);
double[] arr2 = LngLonUtil.bd09_To_Gcj02(lat2, lng2);
lat1 = arr1[0];
lng1 = arr1[1];
lat2 = arr2[0];
lng2 = arr2[1];
} else { //默认使用百度API
}
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.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 log
* 经度
* @param lat
* 纬度
* @return
*/
public static String getAdd(String log, String lat) {
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->入参,log={},lat={}", log, lat);
String urlString = getAddUrl(log, lat);
String res = "";
try {
URL url = new URL(urlString);
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->调用获取位置的百度API地址,urlString={},经纬度:log={},lat={}",
urlString, log, lat);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) openConnection(url);
conn.setDoOutput(true);
conn.setRequestMethod("GET");
java.io.BufferedReader in = new java.io.BufferedReader(
new java.io.InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
res += line + "\n";
}
in.close();
} catch (Exception e) {
logger.error("\n【根据经纬度信息获取实际的地理位置】getAdd----->异常信息:" + e.getMessage(), e);
}
return dealReturnAddJson(res);
}
/**
* 获取经纬度转地点的url
* @param log
* @param lat
* @return
*/
public static String getAddUrl(String log, String lat) {
if(useGd) {//使用高德地图API
double[] arr1 = LngLonUtil.bd09_To_Gcj02(Double.parseDouble(lat), Double.parseDouble(log));
return gdMapUrl + "regeo?output=json&location="+ arr1[1] +"," + arr1[0] + "&key="+ KEY_2 +"&radius=1000&extensions=base";
} else { //默认使用百度API
return getAddressByLngAndLat+lat+","+log+"&output=json&pois=0&ak="+KEY_1+"&s=1";
}
}
/**
* 解析 根据经纬度换算的 地址信息
* @param res
* @return
*/
public static String dealReturnAddJson(String res) {
if(useGd) {//使用高德地图API
if(res!=null && !"".equals(res)){
JSONObject jsonObject = JSON.parseObject(res);
String status = jsonObject.getString("status");
if("1".equals(status)){
JSONObject jsonObject_ = JSON.parseObject(jsonObject.getString("regeocode"));
String formatted_address = jsonObject_.getString("formatted_address");
return formatted_address;
}else {
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->根据经纬度转换实际的物理地址失败,status="+status);
return "";
}
}else{
return "";
}
} else { //默认使用百度API
if(res!=null && !"".equals(res)){
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->调用百度API返回的json,getAdd--->res="+res);
JSONObject jsonObject = JSON.parseObject(res);
String status = jsonObject.getString("status");
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->调用百度API是否成功(0表示成功),status="+status);
if("0".equals(status)){
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->根据经纬度转换实际的物理地址成功,status="+status);
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->result="+JSON.parseObject(jsonObject.getString("result")));
String formatted_address = "";
JSONObject jsonObject_ = JSON.parseObject(jsonObject.getString("result"));
formatted_address = jsonObject_.getString("formatted_address");
if(jsonObject_.containsKey("poiRegions")) {
JSONArray poiRegions = (JSONArray) jsonObject_.get("poiRegions");
if(poiRegions.size()>0) {
JSONObject jobj = (JSONObject) poiRegions.get(0);
if(jobj.containsKey("name")) {
String name = (String) jobj.get("name");
formatted_address +=" "+name;
}
}else {
formatted_address+=" "+jsonObject_.get("sematic_description");
}
}
return formatted_address;
}else if(!"0".equals(status)){
logger.info("\n【根据经纬度信息获取实际的地理位置】getAdd----->根据经纬度转换实际的物理地址失败,status="+status);
return "";
}
return "";
}else{
return "";
}
}
}
private static URLConnection openConnection(URL url) throws IOException {
if (proxyEnable) {
logger.info("\n【请求目标URL】openConnection----->启用代理:proxyEnable={},proxyhost={},proxyPort={}", proxyEnable, proxyhost, proxyPort);
Proxy proxy = new Proxy(Proxy.Type.DIRECT.HTTP, new InetSocketAddress(proxyhost, proxyPort));
return url.openConnection(proxy);
} else {
logger.info("\n【请求目标URL】openConnection----->没有启用代理");
return url.openConnection();
}
}
}
百度经纬度 和 高德经纬度 相互转换代码:
/**
* 百度 == 》 高德
* @param lat
* @param lon
*/
public static double[] bd09_To_Gcj02(double lat, double lon) {
double x = lon - 0.0065, y = lat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
double tempLon = z * Math.cos(theta);
double tempLat = z * Math.sin(theta);
double[] gps = {retain6(tempLat),retain6(tempLon)};
return gps;
}
/**
* 高德 == 》 百度
* @param lat
* @param lon
*/
public static double[] gcj02_To_Bd09(double lat, double lon) {
double x = lon, y = lat;
double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
double tempLon = z * Math.cos(theta) + 0.0065;
double tempLat = z * Math.sin(theta) + 0.006;
double[] gps = {tempLat,tempLon};
return gps;
}
献丑了……