需求:使用腾讯地图api,将百度地图经纬度转换为腾讯地图经纬度。

文档地址:腾讯地图坐标转换api文档地址 功能:实现从其它地图供应商坐标系或标准GPS坐标系,批量转换到腾讯地图坐标系。 需求:因为需要批量转换的经纬度数量过多,需要在后端分段请求接口,再拼接返回给前端。

//HTTP GET 请求 : 只支持1000字节
String url = "https://apis.map.qq.com/ws/coord/v1/translate?";

//格式:纬度前,经度后,纬度和经度之间用",“分隔,每组坐标之间使用”;"分隔;
String locations = "locations=39.12,116.83;30.21,115.43";	
String type = "&type=3";	//输入的locations的坐标类型范围:0-6。3为baidu经纬度
String key = "&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77";	//开发密钥(Key)在我的应用中获得
// 请求示例
String url = https://apis.map.qq.com/ws/coord/v1/translate?locations=lng1,lat1;lng2,lat2&type=3&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77

//响应示例
{
"status": 0,
"message": "转换成功",
"locations": [
    {
        "lng": 116.8234023,
        "lat": 39.11428542
    },
    {
        "lng": 115.42357111,
        "lat": 30.20378632
    }
]

}

1.申请密钥

(1)登陆后,进入应用管理——我的应用——创建应用——获得密钥

(2)进入配额管理——我的配额,可以看到各个接口的每日最高调用量和并发量额度。

Tips:
(1)限制每秒请求次数:每秒最高的请求并发量是5次
(2)限制请求大小:批量支持坐标个数以HTTP GET方法请求上限为准:1000字节

2.处理方法

//计算字节大小
byte[]  buff = xqRange.getBytes();            
int i = buff.length;
System.out.println(i);

//经过测试,大概40组经纬度可以进行一次请求不会失败。

使用的类对象:

// 提取经纬度的类
public class xxxVO {

    private String lng;		// 经度
    
    private String lat;		// 纬度
    
}
//接收坐标转换接口返回的参数类
public class HttpsResponseVO {
    // 状态
    private Integer status;		

   // 信息
    private String message;		

    // 转换后的地址
    private JSONArray locations;		
}

转换方法1:

只处理了请求的数据量,未考虑每秒最大请求数。在需要请求的次数 > 5 时,会出现请求不到数据的情况

public String baidu2tencent1() {

try {
	//## 配置请求字符串
	String url = "https://apis.map.qq.com/ws/coord/v1/translate?locations=";
	String type = "&type=3";  //baidu地图
    String key = "&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77";
	
	String range1 = "";		//保存拼接值
	String range2 = "";		//保存返回结果

	//Spring3.0开始支持的一个 HTTP 请求工具,用于在代码中请求第三方接口
	RestTemplate restTemplate = new RestTemplate();
	
	//## 处理用于请求转换的经纬度数组字符串:
	String range = 
	"[{"lng":110.355443,"lat":20.038738}
	,{"lng":110.358749,"lat":20.037388}
	,{"lng":110.360217,"lat":20.036845}
	,{"lng":110.360968,"lat":20.03648}]";
	
	
	//先转为jsonArray对象,在转为目标对象xxxVO集合
	JSONArray objects = JSONUtil.parseArray(range);		//hutool工具方法:JSONUtil
	List<xxxVO> xxxVOList = JSONUtil.toList(objects, xxxVO.class);
	
	// 计算数组大小
	int size = xxxVOList.size();
	if (size > 40) {
		//需要将经纬度数组,分成多个40组的集合,分段请求多次	
		int requestNum = size / 40;
		int add = size % 40;
		if (add > 0) {
			requestNum ++;
		}
		System.out.println("总共需要请求 = " + requestNum + "次");
		
		//保存分段请求集合
		List<List<xxxVO>> splitList = new ArrayList<List<xxxVO>>();   //分段请求的集合
		int loc = 40;	//记录每次分段的末尾经纬度位置
		for(int i = 0; i < requestNum ; i++) {
			if(loc > size) {
				loc = size;
			}
			System.out.println("起始位置 = " + i * 40 + " —— 结束位置 = " + loc);
			List<xxxVO> spList = xxxVOList.subList(i * 40 , loc);//截取集合部分
			splitList.add(spList);
			loc = loc + 40;		//末尾位置后移
		}

		//遍历截取的集合,组合每段请求的参数
		for(List<xxxVo> voList : splitList) {
			System.out.println("组合参数 " + " 》》》》》》");
			String rangeParam = "";		//保存请求的经纬度locations字段
			for (xxxVo childVo : voList) {
				//遍历集合,组合请求参数
				rangeParam = rangeParam + childVo.getLat() + "," + childVo.getLng() + ";"
			}
			
			// 遍历结束后,切割掉末尾的";"
			rangeParam = rangeParam.substring(0, rangeParam.length() - 1);
			//拼接请求url
			String requestUrl = url + rangeParam + type + key;
			//请求接口
			HttpsResponseVo forObject = restTemplate.getForObject(requestUrl, HttpsResponseVO.class);
			//获取转换后的经纬度
			String local = "" + forObject.getLocations();	// "[{"lng": 116.8234023,"lat": 39.11428542},{"lng": 115.42357111,"lat": 30.20378632}]"
			range1 = range1 + local.substring(1, local.length() - 1) + ","	// "{"lng": 116.8234023,"lat": 39.11428542},{"lng": 115.42357111,"lat": 30.20378632},"
		}
		//所有的集合遍历结束后,拼接需要返回的字符串
		range2 = "[" + range1.substring(0, range1.length() - 1) + "]";
		System.out.println("最终返回的经纬度数组 = " + range2);
	} else {
		//只需要请求一次
		for (xxxVO vo : xxxVOList) {
			range1 = range1 + vo.getLat() + "," + vo.getLng() + ";";
		}
		xqRange = xqRange.substring(0, xqRange.length()-1);
		String requestUrl2 = url + range1 + type + key;
		HttpsResponseVO forObject = restTemplate.getForObject(url3, HttpsResponseVO.class);
		range2 = "" + forObject.getLocations();
	}
	
	return range2;
} catch (exception e) {
	e.printStackTrace();
}
}

转换方法2:

当一秒内请求次数大于5时,使用@Async进行异步调用处理

在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

// 基于Java配置的启用方式:在启动项添加注解
@EnableAsync
public class IxxxProgram extends SpringBootServletInitializer {
	...
}

使用@Async注解的方法,返回值的数据类型为Future,具体结果类型为AsyncResult

public String main() throws ExecutionException, InterruptedException {
	//## 处理用于请求转换的经纬度数组字符串:
	String range = 
	"[{"lng":110.355443,"lat":20.038738}
	,{"lng":110.358749,"lat":20.037388}
	,{"lng":110.360217,"lat":20.036845}
	,{"lng":110.360968,"lat":20.03648}]";
	
	
	//先转为jsonArray对象,在转为目标对象xxxVO集合
	JSONArray objects = JSONUtil.parseArray(range);		//hutool工具方法:JSONUtil
	List<xxxVO> xxxVOList = JSONUtil.toList(objects, xxxVO.class);
	
	Future<String> stringFuture = baidu2tencent2(xxxVOList);
	//获得返回的字符串
	String res = stringFutrue.get();

	return res;
}

@Async
public Future<String> baidu2tencent2(List<xxxVO> xxxVOList) {

try {
	//## 配置请求字符串
	String url = "https://apis.map.qq.com/ws/coord/v1/translate?locations=";
	String type = "&type=3";  //baidu地图
    String key = "&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77";
	
	String range1 = "";
	String range2 = "";

	//Spring3.0开始支持的一个 HTTP 请求工具,用于在代码中请求第三方接口
	RestTemplate restTemplate = new RestTemplate();

	// 计算数组大小
	int size = xxxVOList.size();
	if (size > 40) {
		//需要将经纬度数组,分成多个40组的集合,分段请求多次	
		int requestNum = size / 40;
		int add = size % 40;
		if (add > 0) {
			requestNum ++;
		}
		System.out.println("总共需要请求 = " + requestNum + "次");
		
		//保存分段请求集合
		List<List<xxxVO>> splitList = new ArrayList<List<xxxVO>>();   //分段请求的集合
		int loc = 40;	//记录每次分段的末尾经纬度位置
		for(int i = 0; i < requestNum ; i++) {
			if(loc > size) {
				loc = size;
			}
			System.out.println("起始位置 = " + i * 40 + " —— 结束位置 = " + loc);
			List<xxxVO> spList = xxxVOList.subList(i * 40 , loc);//截取集合部分
			splitList.add(spList);
			loc = loc + 40;		//末尾位置后移
		}

		//遍历截取的集合,组合每段请求的参数
		for(List<xxxVo> voList : splitList) {
			System.out.println("组合参数 " + " 》》》》》》");
			String rangeParam = "";		//保存请求的经纬度locations字段
			for (xxxVo childVo : voList) {
				//遍历集合,组合请求参数
				rangeParam = rangeParam + childVo.getLat() + "," + childVo.getLng() + ";"
			}
			
			// 遍历结束后,切割掉末尾的";"
			rangeParam = rangeParam.substring(0, rangeParam.length() - 1);
			//拼接请求url
			String requestUrl = url + rangeParam + type + key;
			//请求接口
			HttpsResponseVo forObject = restTemplate.getForObject(requestUrl, HttpsResponseVO.class);

			//因为一秒内超过请求次数,无法获得转换数据,等待一秒后在请求一次
			if (forObject.getLocations() == null) {
                        Thread.sleep(1000);    //请求失败,等一秒
                        forObject = restTemplate.getForObject(requestUrl, HttpsResponseVO.class);
             }

			//获取转换后的经纬度
			String local = "" + forObject.getLocations();	// "[{"lng": 116.8234023,"lat": 39.11428542},{"lng": 115.42357111,"lat": 30.20378632}]"
			range1 = range1 + local.substring(1, local.length() - 1) + ","	// "{"lng": 116.8234023,"lat": 39.11428542},{"lng": 115.42357111,"lat": 30.20378632},"
		}
		//所有的集合遍历结束后,拼接需要返回的字符串
		range2 = "[" + range1.substring(0, range1.length() - 1) + "]";
		System.out.println("最终返回的经纬度数组 = " + range2);
	} else {
		//只需要请求一次
		for (xxxVO vo : xxxVOList) {
			range1 = range1 + vo.getLat() + "," + vo.getLng() + ";";
		}
		xqRange = xqRange.substring(0, xqRange.length()-1);
		String requestUrl2 = url + range1 + type + key;
		HttpsResponseVO forObject = restTemplate.getForObject(url3, HttpsResponseVO.class);
		range2 = "" + forObject.getLocations();
	}
	
	return new AsyncResult<String>(range2);
} catch (exception e) {
	e.printStackTrace();
}
}

参考链接:Spring中@Async用法详解及简单实例.RestTemplate 用法详解.