百度地图API初体验和偏移纠正方法
最近的项目想做一个在可以通过手持设备获取经纬度,然后在地图上进行标注显示的功能,因为还在技术调研阶段,所以决定先使用百度地图或Google Maps的API来做Demo。通过网上的一些资料和自己对于Google和百度地图的使用,对这两个地图做了一些简单的对比,结论是很明显的——Google在技术水平和成熟度上都要比百度高很多,可以说完全不在一个档次上,但是鉴于Google和中国政府的微妙关系加上中国特色的互联网管理方式,实在是没有信心使用随时可能被墙的产品,所以最终还是无奈地选择了百度地图。
有那么几点罗列一下:
- Google地图能够放大到比百度地图更加细致的比例尺,而且在地图标注上也比百度的详细很多。
- 百度地图在道路的绘制上可能比Google Maps更加详细些,具体来说是某些小的道路,Google Maps并不显示,而会在百度地图上看到。
- 两者的免费版都不允许商业应用,并且Google Maps API按IP进行限制,貌似是15K每天,如果超过这个限额就会返回错误,不过可以发邮件给Google说这个问题,添加白名单之类。百度暂时没有发现存在这个限制。
- 企业版费用,Google Maps API如果是商业应用的话,貌似是最少10000美元每年的费用,百度问了一下是15万人民币的年费。
- GPS经纬度坐标偏移问题。这个是由于中国要求对经纬度进行加密导致的,所以百度和Google的地图上都存在这个问题,即使用手持设备或者导航设备获取到的经纬度在地图上定位发现并不是对应的位置,而存在很大的偏移。Google地图的位置纠正网上有很多资料,我这里就不说了,可以自己去查,后面会讲下百度地图偏移问题的解决方法。
- API性能对比。这个网上有一些对比,我自己做的实验也不具有代表性,因此此处不说了,结论是Google的相对较好些,有个链接可以稍微参考下:http://www.cnblogs.com/milkmap/archive/2011/02/09/1950142.html
百度地图API的使用主要是JavaScript的方式,参考资料只能是百度地图官网的API说明和示例,基本也够用了,我此处做的例子就是直接拷贝的它的代码进行了简单的综合,非常的简单,一个从url传入经纬度值,进行以此坐标为中心显示一定比例尺的地图,加入地图漫游、缩放、鱼骨和比例尺控件功能,添加右键事件响应菜单,获取所点击点的坐标传递给一个url的过程。仅仅粘贴代码如下,包括一些url参数提取的函数和api的注释都是网上的,不能算是完全的原创。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>百度地图API Demo</title> <style type="text/css"> html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } #container { height: 100% } </style> <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.1&services=true"></script> </head> <body> <div id="container"></div> </body> <script type="text/javascript"> function GetRequest() { var url = location.search; //获取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strs = str.split("&"); for ( var i = 0; i < strs.length; i++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } var Request = new Object(); Request = GetRequest(); var xLocation, yLocation; xLocation = Request['xLocation']; yLocation = Request['yLocation']; var map = new BMap.Map("container"); // 创建地图实例 var point = new BMap.Point(xLocation, yLocation); // 创建点坐标 map.centerAndZoom(point, 18); // 初始化地图,设置中心点坐标和地图级别 map.enableScrollWheelZoom(); // 启用滚轮放大缩小。 map.enableKeyboard(); // 启用键盘操作。 map.addControl(new BMap.NavigationControl()); // 添加平移缩放控件 map.addControl(new BMap.ScaleControl()); // 添加比例尺控件 map.addControl(new BMap.OverviewMapControl()); //添加缩略地图控件 var marker = new BMap.Marker(point); // 创建标注 map.addOverlay(marker); // 将标注添加到地图中 var menu = new BMap.ContextMenu(); var txtMenuItem = [ { text : '传递坐标', callback : function(p) { //window.location.href='MyJsp.jsp?x=' + p.lng; window.open('MyJsp.jsp?lng=' + p.lng + '&lat=' + p.lat); } } ]; for ( var i = 0; i < txtMenuItem.length; i++) { menu.addItem(new BMap.MenuItem(txtMenuItem[i].text, txtMenuItem[i].callback, 100)); } map.addContextMenu(menu); </script> </html>
下面简单介绍下经纬度坐标偏移问题的解决方法,这个官方说法是因为百度在国家标准的加密算法的基础上又进行了一次加密导致的,解决方案需要询问百度。这里有一个百度hi群的群号:1306508,有问题的可以加群里问,不过一般也会被告知这个需要合作伙伴才可以告诉,很郁闷。
我是发邮件给mapapi@baidu.com才获得了解决方法,也是通过一个网址,将待转换的经纬度以url参数的形式传递进去,打开的页面是经过了Base64形式的校正经纬度坐标,实验了一下还挺准确的。之前在互联网上查到过一个网址,不过都说已经被百度停止服务了,不过对比了一下和百度给我的网址,发现并没有停止服务,而是对参数名称进行了改变。。。具体的网址我就不便多说了(其实是掩耳盗铃),跟百度沟通应该就可以获取得到~
由于我做的程序不能直接使用那个转换服务进行转换,因此我使用JAVA写了一个程序,模仿HTTP发送请求,然后解析返回的页面信息。具体的代码如下:
package tools; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; public class BaiduAPIConverter { public static void testPost(String x, String y) throws IOException { URL url = new URL( "XXXXX"); URLConnection connection = url.openConnection(); /** * 然后把连接设为输出模式。URLConnection通常作为输入来使用,比如下载一个Web页。 * 通过把URLConnection设为输出,你可以把数据向你个Web页传送。下面是如何做: */ connection.setDoOutput(true); OutputStreamWriter out = new OutputStreamWriter(connection .getOutputStream(), "utf-8"); // remember to clean up out.flush(); out.close(); // 一旦发送成功,用以下方法就可以得到服务器的回应: String sCurrentLine; String sTotalString; sCurrentLine = ""; sTotalString = ""; InputStream l_urlStream; l_urlStream = connection.getInputStream(); BufferedReader l_reader = new BufferedReader(new InputStreamReader( l_urlStream)); while ((sCurrentLine = l_reader.readLine()) != null) { if (!sCurrentLine.equals("")) sTotalString += sCurrentLine; } System.out.println(sTotalString); sTotalString = sTotalString.substring(1, sTotalString.length()-1); String[] results = sTotalString.split("\\,"); if (results.length == 3){ if (results[0].split("\\:")[1].equals("0")){ String mapX = results[1].split("\\:")[1]; String mapY = results[2].split("\\:")[1]; mapX = mapX.substring(1, mapX.length()-1); mapY = mapY.substring(1, mapY.length()-1); mapX = new String(Base64.decode(mapX)); mapY = new String(Base64.decode(mapY)); System.out.println(mapX); System.out.println(mapY); } } } public static void main(String[] args) throws IOException { testPost("116.31500244140287", "40.006434917448786"); } }
结果我使用了Apache的Base64包进行转码,如果你想代码跑起来需要去下载这个包,或者你可以输出转码前的字符串~哦,对了,Base64编码的坐标信息可以直接传递给百度地图的API进行使用。
总体来说,百度地图API做得还算简单,使用还算方便,但是和Google Maps比起来还是有一定的差距的,希望本文可以对使用的人有所帮助~祝好运。