最近真不知道干什么好了,想什么都学,但什么都学不好,不过体验了一把Google Maps API感觉不错,Google真的是太强悍了,也许就是我未来的目标吧。
进行GMapAPI开发首先得申请Google Maps API密钥,http://code.google.com/intl/zh-CN/apis/maps/里有详细的入门说明,在获得密钥之后就可以开始开发之旅了,我首先按照Google提供的开发人员指南进行基础知识的学习,然后就照着书上的例子做了个IP地理位置可视化查询系统,虽然很简单但却非常有趣。
首先需要下载IP数据库和相关API,我选择的是MaxMind的免费GeoLiteCity数据库并且有丰富的API支持,GeoLiteCity数据库下载地址为http://www.maxmind.com/download/geoip/database/,选择下载GeoLiteCity.dat.gz并解压,同时下载官方提供的APIhttp://www.maxmind.com/download/geoip/api/,可以选择自己擅长的开发语言,我选择的是Java API,开发环境是MyEclipse6.6。
地图定位查询主要分为两个步骤,第一,获取待查询的IP;第二,利用MaxMind API进行查询并返回查询结果。在MyEclipse中新建一个Web Project,导入下载得到的GeoIPJava-1.2.3 API,同时将IP数据库文件GeoLiteCity.dat放置在WebRoot下。
服务器端使用JSP,以下是search.jsp中<body>元素的Java代码:
<body>
<%
//获得用户请求查询的数据
String queryString = (String)request.getParameter("q");
PrintWriter outWriter;
String ip = "";
//如果查询数据为空则返回主机地址
if (queryString == null || queryString.equals("")) {
ip = InetAddress.getLocalHost().toString();
if (ip == null || ip.equals(""))
System.out.println("Cannot get your IP address!");
}
else {
//用正则表达式检验查询数据是否为有效IP
String pattern = "^(//d{1,3}//.//d{1,3}//.//d{1,3}//.//d{1,3})$";
if (queryString.matches(pattern)) {
ip = queryString;
System.out.println("The IP address is valid.");
}
//如果无效则验证查询数据是否为有效域名
else {
try {
ip = InetAddress.getByName(queryString).toString();
ip = ip.split("/")[1];
if (!ip.matches(pattern)){
System.out.println("Invalid domain!");
response.setContentType("text/xml");
response.setCharacterEncoding("utf-8");
outWriter = response.getWriter();
outWriter.print("alert('Invalid domain!')");
}
}
catch (UnknownHostException e) {
System.out.println("Invalid domain!");
}
}
}
try {
//建立LookupService实例开始查询
LookupService query = new LookupService("./GeoLiteCity.dat", LookupService.GEOIP_STANDARD);
Location location = query.getLocation(ip);
//返回查询结果,包括IP地址位置的国家名称和代码,地区,城市以及经纬度
if (location != null) {
String responseText = "loadGeoInfo('" + queryString + "', '" + ip + "', '"
+ location.countryCode + "', '" + location.countryName + "', '"
+ location.region + "', '" + location.city + "', "
+ location.latitude + ", " + location.longitude + ");";
response.setContentType("text/xml");
response.setCharacterEncoding("utf-8");
outWriter = response.getWriter();
System.out.println(responseText);
outWriter.print(responseText);
}
else {
System.out.println("The information for " + ip + " is not available now.");
}
}
catch (FileNotFoundException e) {
System.out.println("Cannot find the file!");
}
%>
</body>
对于GeoIPJava-1.2.3 API的使用也十分简单,这个库的核心类是LookupService类,可根据需要选择适当的方法。需要注意的是Java本身提供的java.net.InetAddress,java.net.*是网络编程的核心类库,InetAddress提供了互联网协议(IP)地址的相关处理。
客户端程序采用Ajax技术。Google Maps API本身提供了相当便捷的使用Ajax方法,主要有两种异步调用方法,一种是使用GXmlHttp对象,另一种是使用GDownloadUrl()函数。我对两种方法均进行了试验,下面查询页面index.html的代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>GeoIp Seeker</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
<!--导入Google Maps API,注意将API密钥替换成自己的 -->
<script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAvzhO6PilSOgUJFEfrExL3hR957vyFaxVOlU_EF_7ZUt9iexMPhT-MjdYiZc-avowGkYL8tEk8rSwOg&sensor=false" type="text/javascript">
</script>
<script type="text/javascript">
var map; //全局GMap2对象
var marker; //用于标识查询IP的GMarker地标
//初始化
function load() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(39.92, 116.46), 2);
//添加相应Control控件
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
//设定地图类型为混合地图
map.setMapType(G_HYBRID_MAP);
}
}
//相应查询栏的回车
function pressEnter(event, q) {
//如果输入了回车则执行查询
if (event.keyCode == 13 || event.keyCode == 10) {
createRequest(q);
}
}
//查询函数,使用GXmlHttp对象
function createRequest(q){
var request = GXmlHttp.create();
var url = "search.jsp";
//打开GXmlHttp对象,可设置三个参数,第一个为获取方法的类型POST或GET,第二个为发送请求的URL地址,第三个为获取模式,同步为真异步为假
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//表单数据
var formData = "q=" + q;
//定义响应的回调函数,可采用如下闭包形式,也可将回调函数单独提出
request.onreadystatechange = function() {
if(request.readyState == 4){
if(request.status == 200){
//获取服务器端返回的数据
text = request.responseText;
fun = text.split("/n")[0];
alert(fun);
(fun);
}
else{
alert("failed for searching!");
}
}
};
//发送异步请求
request.send(formData);
}
//查询函数,采用GDownloadUrl()方法
function getGeoInfo(q) {
GDownloadUrl("search.jsp?q=" + q, function(data){
fun = data.split("/n")[0];
(fun);
})
}
//在地图上定位目标IP并添加信息窗口显示详细信息
function loadGeoInfo(q, ip, country_code, country, region, city, latitude, longtitude) {
//信息内容,包括查询数据、IP、国家名称、国家代码、省份、城市以及经纬度
var info = "<div align=/"left/" style=/"overflow:X; font-size:12px/">"
+ "<span style=/"font-size:14px/"><strong>" + q + "</strong></span><br/>"
+ "<strong>IP:</strong> " + ip + "<br />"
+ "<strong>国家:</strong> " + country + "<br />"
+ "<strong>代码:</strong> " + country_code + "<br />"
+ "<strong>省份:</strong> " + region + "<br />"
+ "<strong>城市:</strong> " + city + "<br />"
+ "<strong>经度:</strong> " + longtitude + "<br />"
+ "<strong>纬度:</strong> " + latitude + "<br />"
+ "</div>";
var point = new GLatLng(latitude, longtitude);
//移动地图到新的位置
map.panTo(point);
//如果创建了marker地标,则关闭当前的信息窗口并移除地标
if(marker) {
map.closeInfoWindow();
map.removeOverlay(marker);
}
//创建新的地标
marker = new GMarker(point);
map.addOverlay(marker);
//显示信息窗口
marker.openInfoWindowHtml(info);
}
</script>
<style>
td{
text-align:center;
}
</style>
</head>
<body onload="load()" onunload="GUnload()">
<table cellspacing="0" cellpadding="0" width="600" border="0" align="center">
<tbody>
<tr>
<td height="25">
<form onsubmit="return false;">
<label for="q">请输入IP或域名
<input maxlength="50" size="25" name="q" id="q" onkeypress="pressEnter(event, this.value);" />
<input type="button" value="查找" id="search" onclick="getGeoInfo(q.value);" />
</label>
</form>
</td>
</tr>
<tr>
<td>
<div id="map" style="width:750px;height:520px"></div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
其中JavaScript部分关于Google Maps API的使用有详细注释,同时也可参考Google官方的入门指南或者API说明等资料,这里想说明几个问题,也是我在编写过程中遇到的问题。
一个是Ajax的问题。这里我采用了上述提到的两种方法,查询时如果点击查询按钮将会执行getGeoInfo方法使用GDownloadUrl()函数,如果按回车则会执行createRequest方法使用GXmlHttp对象,效果是一样的。其中GXmlHttp对象跟传统的XmlHttpRequest对象基本没有区别,数据和方法也基本一样,包括常用的responseText、onreadystatechange等数据,open()、send()等方法。而GDownloadUrl(url,onload)函数应该说是一个简化版的异步处理函数,只能使用GET方法,不判断加载状态,只是在完全加载后调用回调函数,其中第一个参数为需要用GET方法获取的URL,第二个参数是完全加载后的回调函数。其中的data数据等同于GXmlHttp对象的responseText数据,即服务器返回的查询结果。
第二个是关于回调函数的问题。这里的回调函数都采用了闭包形式的写法,当然也可将回调函数单独提出。据说即将推出的J2SE7.0最新特性就是开始支持闭包,说明Java也开始向Groovy、PHP、JS、Python等优秀的动态或脚本语言学习引入闭包特性。回调函数建议采用()函数,直接执行函数,较为简单,无需再对返回的数据进行解析处理,不过要注意所执行函数中的参数类型,string类的参数一定要加上单引号,我就是弄了很长时间()都没有执行最后才发现是这个问题。
下面是程序演示,出现了几个比较有意思的结果:
上面两张分别是Google和谷歌中国的服务器地址,一个在硅谷,一个在北京,这倒也不奇怪,不过我放大了谷歌中国的域名位置,结果很尴尬:
我又检验了sina的服务器地址,地标同样是很尴尬的落在了北海中央,MaxMind的IP数据库的经纬度看来只能精确到城市了。
不小心查了一下峰哥做的大班论坛的服务器地址,结果却是在我的出生地合肥,峰哥说他只是在外面租了个服务器到底在哪也不知道,看来这只能是一个未解之谜了。
最后再提醒一下,建议使用Google的Chrome浏览器,对Google Maps的支持不是一般的好,原来使用IE时地图老是显示的不太稳定。信谷歌,得永生!