将 Google Maps 与 Oracle 数据库混搭

作者:Chris Schalk

轻松构建一个混搭应用程序,以使用 Oracle XML DB 将 Oracle 数据与 Google Maps API 集成。

2007 年 8 月发布

正如您知道的那样,许多年以前,Oracle 就能够从数据库即时生成 XML。除了从 Oracle 数据库生成 XML,还可以使用多种语言(如 Java Servlets 和 JDBC)将生成的数据 XML 发布到 Web。

您可能尚未看到从 Oracle 数据库获得动态生成的 XML 数据并使用 Google Maps API 将其与 Web 页混搭在一起是多么容易。例如,如果您的 Oracle 数据库填充了与地理相关的有趣数据,则可以非常轻松地将该数据与 Google 的 JavaScript Maps API 集成在一起。

在本文中,我将演示如何使用 Oracle 的 XML DB 特性和 Java 构建一个混搭应用程序,以便将 Oracle 数据库中的数据与 Google Maps API 集成(使用的是 Oracle JDeveloper 10g ;从这里 获得示例项目文件)。

全球 ACME 宾馆定位应用程序简介

为了让您了解能够将 Oracle 数据库的功能与 Google Maps API 相结合的可能应用程序类型,下面提供了一个简单的应用程序,通过该应用程序,您可以查询全球的宾馆位置并在 Google Map 上查看结果。当您首次访问应用程序的 Web 页时,将看到 Google Map 并且顶部有一个简单的表单,可以输入查询参数。

图 1:ACME 全球宾馆定位程序

正如您在图 1 中看到的那样,指定的查询条件是“Beach access”、“under 400$”以及在“Americas”区域内,并单击了“Find Hotels”按钮。这返回了一组 Miami、Acapulco 和 Rio de Janeiro 的宾馆结果。单击图中的标记将在一个弹出窗口中显示宾馆的详细信息。您还可以看到,宾馆级别是 4 星,并且平均价格约为 293 美元。还显示了一个“Book it!”链接,从而允许您轻松转到该宾馆的 Web 站点以便预订房间。

要体验该应用程序的动态特性,我们假设您要搜索一个带有游泳池、价格在 400 美元以下并且位于欧洲的 ACME 宾馆。该搜索将显示以下结果:

图 2:具有价格限制的欧洲宾馆搜索

您在这里可以看到,查询结果中显示了一个位于罗马中心、带有游泳池、令人愉悦且价格合适的宾馆。这次,另一个没有指定游泳池、但价格限制在 100 美元以下且位于欧洲的限制成本的查询将显示一个位于伦敦中心的 3 星伦敦快捷酒店。

图 3:一个价格在 100 美元以下、位于伦敦的 3 星宾馆。仅供演示使用!

正如您在本例中看到的那样,只需切换到 Google Maps 窗口上的“Map”选项,即可确切了解宾馆位于城市的哪个地方。其他查询可以生成许多您感兴趣的全球宾馆组合。

图 4:ACME 宾馆定位应用程序生成的各种结果

该应用程序的“酷”因素之一是,它具有极高的易用性,这是大部分 Google Maps 应用程序所具有的共同点。

构建 ACME 宾馆定位应用程序

在深入该应用程序背后的代码之前,我们先快速了解一下体系结构。正如您在图 5 中看到的那样,应用程序的体系结构包括一个在应用程序背后提供实际数据的 Oracle 数据库,以及一个运行 Java servlet 的应用服务器,该 servlet 可以使用 Oracle XML DB 与数据库通信并以 XML 格式检索数据。

图 5:ACME 宾馆应用程序的体系结构

实际的 Java servlet (XmlServlet ) 利用一个特殊的类 XmlGenerator ,该类可以使用 JDBC 发出查询并检索宾馆数据的 XML 流。该数据随后会返回到 servlet,而 servlet 又会将该数据发送到 html Web 客户端 (acme_hotels.html ),然后客户端将使用 Google Maps API 显示数据。实际的 Map 图像或图块专门由 Google 提供。简单来说,这就是实质上的体系结构。下面,让我们详细研究一下代码。

数据库表 — Hotels

对于这个简单的应用程序,实际上需要的全部内容只是一个表“hotels”,该表包含的一组列包含了每个宾馆的所有相关信息。以下是创建 hotels 表的脚本。

REM Create a Geocoded Hotels Table 

CREATE TABLE HOTELS (
ID NUMBER NOT NULL,
NAME VARCHAR2(500) NOT NULL,
DESCRIPTION VARCHAR2(500),
THUMB_IMG_URL VARCHAR2(500),
WEB_ADDRESS VARCHAR2(500),
ADDRESS VARCHAR2(1000),
CITY VARCHAR2(500),
POSTAL_CODE VARCHAR2(500),
STATE VARCHAR2(500),
COUNTRY VARCHAR2(500),
REGION VARCHAR2(100),
STARS NUMBER,
BEACH VARCHAR2(1),
AVE_PRICE_USD DOUBLE PRECISION,
POOL VARCHAR2(1),
LATITUDE DOUBLE PRECISION,
LONGITUDE DOUBLE PRECISION );


ALTER TABLE HOTELS
ADD CONSTRAINT HOTELS_PK PRIMARY KEY ( ID ) ENABLE;

除了明显的列(例如,name、description 等),请注意 latitude 和 longitude 列。这就是每个宾馆的确切地理位置,该地理位置将被提供给 Google Maps API 以便在地图上定位宾馆。

使用“Spatial”选项或基本表列。 在 Oracle 数据库中存储地理信息的另一个方式是使用 Oracle Spatial 选项。利用 Spatial 选项(而非只是将经度和纬度坐标加载到它们自己的列中),您可以将它们加载到名为 SDO_GEOMETRY 的对象中。这个对象演示了 Oracle Spatial 的功能;它实际上可以支持大量地理信息,而不只是地理点。这些信息包括直线、曲线、多边形、多行、多重多边形等。但是对于 ACME 宾馆应用程序,目前实际所需的所有信息就是经度和纬度坐标,因此只需要两个双精度列就足够了。升级该应用程序以使用 Spatial 选项是一个简单过程,并且只需对表和 SQL 查询进行少量更新以插入和检索地理数据。

研究了数据库结构之后,下面我们来看一下在应用服务器上运行并查询数据的 Java 代码。

以 XML 格式查询数据

为了检索 hotels 表中的数据,ACME 应用程序使用在 Oracle Containers for Java (OC4J)(即 Oracle 应用服务器中的企业 Java 引擎)中运行的 Java servlet。Java servlet (XmlServlet ) 本身只是充当 Web 客户端与查询数据库的代码之间的中间媒介。当最终用户单击“Find Hotels”按钮时,程序将对以 XML 格式从数据库请求宾馆地理数据的 servlet 进行一个 Ajax 调用。

它的工作方式是怎样的?servlet 先处理从 Web 客户端发送的查询参数,然后将其传送到另一个 Java 类 XmlGenerator ,该类的作用是使用 JDBC 连接到数据库,并根据 servlet 发送的查询返回 XML 数据流。程序将使用 Oracle XML DB 自动生成 XML 内容。

下面让我们来详细了解该应用程序的体系结构,您可以在该体系结构中看到 Web 客户端如何与 XmlServlet 通信,而后者又如何使用 XmlGenerator 类以 XML 格式提取宾馆数据。

图 6:公开的 Acme 宾馆应用程序体系结构

正如您看到的那样,Web 客户端对 servlet 进行了一个调用,该 servlet 使用的 Google Maps API GDownloadUrl ( ) 函数带有指定是否需要游泳池或靠近海滩或在要求的价格范围内之类的参数。顺便说一句,GDownloadUrl( ) 使用 XMLHttpRequest 在后台发出 Ajax 请求。由于该函数还可以进行浏览器兼容性检查以及错误处理,因此它可以充当一个方便函数,如果使用本机的 XMLHttpRequest ,您可能需要编写自己的代码。下面,我们来看一下处理该请求的 Java servlet 中的代码。

Java Servlet:XmlServlet

Java servlet XmlServlet 是一个简单的 servlet,它可以响应针对宾馆数据的 Ajax Http 请求,然后使用另一个 Java 类 XmlGenerator 通过 XML DB 选项查询数据库。下面,我们来详细研究一下代码。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.http.*;
import com.xml.XmlGenerator;
 public class XmlServlet extends HttpServlet {
private static final String CONTENT_TYPE = "text/xml";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
 public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
   response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
   XmlGenerator xgen = new XmlGenerator(createWhereClause(request));
   // Return XML data as an Http Response
String xmlResponse = xgen.getXmlResponse();
out.println(xmlResponse);
out.close();
}
public String createWhereClause(HttpServletRequest request) {
// Create where clause based on request arguments
...
return wc;
}
}

除了是一个相当典型的 Java servlet 之外,您将注意到 CONTENT_TYPE 被设置为“text/xml”。与 HTML 不同,这是必需的,因为该 servlet 将仅以 XML 格式进行响应。进一步研究代码,查看 doGet 方法,您可以看到 XmlGenerator 类使用返回的结果(组装在本地方法 createWhereClause( ) 中)进行实例化。不必显示该方法的每一行,只要知道只需将 HttpRequest 参数从

"?pool=yes&beach=yes&price=400" 

格式转换为可以追加到数据库查询的 whereclause 字符串就足够了,例如:

 "WHERE BEACH = 'Y' AND POOL = 'Y' AND AVE_PRICE_USD < 400" 

XmlGenerator 类

XmlGenerator 类的代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import oracle.xml.sql.query.OracleXMLQuery;
public class XmlGenerator {
public String xmlResponse;
  // Customize as needed
private static String jdbcURL = "jdbc:oracle:thin:@your-host:1521:orcl";
private static String user = "geo";
private static String passwd = "geo";
 public XmlGenerator() {
}
 public XmlGenerator(String wc) {
 String tabName = "hotels";
Connection conn = null;

try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
conn = DriverManager.getConnection(jdbcURL, user, passwd);
} catch (SQLException e) {
e.printStackTrace();
}
 String strqry =
"select name, description, thumb_img_url, web_address, address, city,
postal_code, state, country, region" +
"stars, beach, ave_price_usd, pool, latitude, longitude from " + tabName + wc;
 OracleXMLQuery qry = new OracleXMLQuery(conn, strqry);

// Structure the generated XML document
qry.setRowIdAttrName(null);
qry.setMaxRows(50);
qry.setRowsetTag("hotels"); // set the root document tag
qry.setRowTag("hotelinfo"); // sets the row separator tag
 // Get the XML document in string format
String xmlString = qry.getXMLString();
setXmlResponse(xmlString);
}
 public void setXmlResponse(String xmlResponse) {
this.xmlResponse = xmlResponse;
}
 public String getXmlResponse() {
return xmlResponse;
}
}

XmlGenerator 类中的代码是可以使用 XML DB 选项的相当标准的 JDBC 代码。注意,除了标准的 JDBC 包,还导入了 XML DB 包 oracle.xml.sql.query.OracleXMLQuery 。该类遵循标准的 Java Bean 方法,并具有一个属性:XmlResponse ,其 getter 和 setter 方法位于类的末尾。顺便说一下,该属性将包含从数据库检索的 XML 响应。设置 JDBC 连接之后,代码的关键部分是:

OracleXMLQuery qry = new OracleXMLQuery(conn, strqry);

这将创建一个新的 OracleXMLQuery 对象,其连接和查询字符串已经指定。创建完成后,可以应用其他几个设置,包括 RowsetTag ,该设置可指定“hotels”作为 XML 数据的根元素。RowTag 设置为“hotelinfo”,并充当每个返回记录的重复元素。得到的 XML 数据格式如下:

<?xml version = '1.0'?>
<hotels>
<hotelinfo>
<NAME>ACME Luxury Acapulco</NAME>
<DESCRIPTION>The ACME Luxury Acapulco is a luxurious beautiful
beach front with all the amenities that a 4 star hotel
is expected to have.</DESCRIPTION>
<THUMB_IMG_URL>images/acapulco-sm.jpg</THUMB_IMG_URL>
<WEB_ADDRESS>http://acmeluxuryhotelacapulco-bogus.com</WEB_ADDRESS>
<ADDRESS>2322 La Sienna</ADDRESS>
<CITY>Acapulco</CITY>
<POSTAL_CODE>38432</POSTAL_CODE>
<COUNTRY>MX</COUNTRY>
<STARS>4</STARS>
<BEACH>Y</BEACH>
<AVE_PRICE_USD>375.95</AVE_PRICE_USD>
<POOL>Y</POOL>
<LATITUDE>16.850548</LATITUDE>
<LONGITUDE>-99.920654</LONGITUDE>
</hotelinfo>
<hotelinfo>
<NAME>ACME Luxury San Francisco</NAME>
<DESCRIPTION>...</DESCRIPTION>
...
</hotelinfo>
<hotelinfo>
...
</hotelinfo>
...
</hotels>

现在,我们已经探究了 Java servlet 及其 XML 生成代码,下面来看一下 HTML Web 客户端,该客户端的职责是显示 Google Map、处理表单值以及发出对 servlet 的 Ajax 请求。

HTML Web 客户端:acme_hotels.html

回想一下,客户端 Web 页实际上只包含一个 HTML 表单和一个 Google Map。表单包含复选框、一个下拉列表和一个提交按钮。Google Map 以中性状态启动,并显示全球视图。在探究表单代码之前,我们先探究一下呈现最初的 Google Map 的少量 JavaScript 代码。

    
// Initialize map - called when page is loaded
function initMap(){
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map" ));
map.setCenter(new GLatLng(2, -55), 1);
map.enableScrollWheelZoom();
map.setMapType(G_HYBRID_TYPE);
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
}
}

正如您看到的那样,该代码封装在名为 initMap( ) 的函数中,并且也指定为在使用以下语句加载页面时执行:

<body οnlοad="initMap()"
 οnunlοad="GUnload()">;

顺便说一下,GUnload( ) 函数是 Google Maps 提供的函数,用于在用户离开页面时清除任何内存中对象。您在 initMap( ) 函数中可以看到,创建了一个新的 GMap2 对象。其构造函数的参数是现有 HTML <DIV> 标记的 id ,该参数在页面主体的末尾定义:

...
<div id="map" style="width:700px; height:500px"></div>
</body>

您可以看到,地图的维度在容器 DIV 的样式属性中定义。

返回到 initMap( ) ,其余行只是地图的选项。对于该地图,将中心设置为经度为 2、维度为 -55,并且启用了鼠标滚轮缩放选项。最初的地图类型是 G_HYBRID_TYPE ,它混搭了卫星图像和地理数据。最后,向地图添加两个控件:GLargeMapControlGMapTypeControl ,前者是缩放控件的大版本,后者允许用户在不同的地图类型(MapSatelliteHybridTraffic 等)之间切换。

初始化地图之后,它将呈现一个通用地图,并且 Web 页将等待进一步输入。此时,用户可以在表单中输入搜索条件:

Has pool: Beach access: Price: Region:

这些都位于地图上方。该表单的代码很简单:

<form action="#" οnsubmit="showHotels(); return false"> 
<p>
Has pool:<input type="checkbox" id="pool " οnclick="togglePool() "/> 
Beach access:<input type="checkbox" id="beach " οnclick="toggleBeach() "/> 
Price:
<select id="price " οnchange="togglePrice() ">
<option value="">any price</option>
<option value="100">Below $100</option>
<option value="200">Below $200</option>
<option value="400">Below $400</option>
<option value="600">Below $600</option>
<option value="800">Below $800</option>
</select>

Region:
<select id="region " οnchange="toggleRegion() ">
<option value="">any region</option>
<option value="americas">Americas</option>
<option value="europe">Europe</option>
<option value="mideast-asia">MidEast-Asia</option>
<option value="africa">Africa</option>
</select>
<input type="submit" value="Find Hotels" />
</p>
</form>

表单包含四个不同的输入值:poolbeachpriceregion ,每个输入域都随附一个相应的 JavaScript 函数,并且将在选中复选框或更改选择菜单时执行。以下是其中一个输入域监听器函数 togglepool( ) 的示例。

function togglePool() {
if (document.getElementById('pool').checked) {
haspool = true;
} else {
haspool = false;
}
}

togglePool( ) 函数的职责是检查 pool 输入域是否被选中,以及相应地更新布尔全局变量 haspool 。对于下拉选择菜单,代码只是将选择菜单的值应用到宾馆价格的全局变量 hotelprice

 function togglePrice() {
hotelprice = document.getElementById('price').value;
}

启动一个查询。 一旦用户通过设置输入域指定了查询条件,他/她就可以通过单击“Find Hotels”按钮(启动 showHotels( ) 函数的执行)来执行查询。该函数将使用 clearMap( ) 清除任何以前的地图,并调用 loadHotelLocations( )

function showHotels(){
clearMap();
loadHotelLocations();
}

clearMap( ) 函数使用 Google Maps API 调用 map.clearOverlays( ) 来清除任何现有的地图叠加 。您很快就能了解到,Google Maps 叠加 是您在地图顶端添加额外可视内容的方式,例如,绘制一条直线或者添加一个弹出窗口,这实际上正是该应用程序所作的事情。

loadHotelLocations( ) 函数是应用程序的实际“劳力”。它组装在表单上指定的查询参数,然后使用 Google Maps API 调用 GDownloadUrl( ) 进行 Ajax 调用,以根据查询下载包含相应宾馆信息的 XML 流。下面是完整的函数:


function loadHotelLocations() {
var ajaxParms = generateRequestArgs();

// Make Ajax request to get Hotel data using Google Maps GDownloardUrl()
GDownloadUrl("/ACME-Hotel-Locator/xmlservlet" + ajaxParms, function(data, responseCode) {
var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName("hotelinfo");

if (markers.length == 0){
alert("Your query returned no results.Please broaden your search criteria
and try again.");
} else {

for (var i = 0; i < markers.length; i++) {
var point = new GLatLng(parseFloat(markers[i].getElementsByTagName("LATITUDE")[0].firstChild.nodeValue),
parseFloat(markers[i].getElementsByTagName("LONGITUDE")[0].firstChild.nodeValue));

var hotelName = markers[i].getElementsByTagName("NAME")[0].firstChild.nodeValue;
var hotelDescription = markers[i].getElementsByTagName("DESCRIPTION")[0].firstChild.nodeValue;
var hotelStars = markers[i].getElementsByTagName("STARS")[0].firstChild.nodeValue;
var hotelImg = markers[i].getElementsByTagName("THUMB_IMG_URL")[0].firstChild.nodeValue;
var hotelWebAddress = markers[i].getElementsByTagName("WEB_ADDRESS")[0].firstChild.nodeValue;
var hotelStars = markers[i].getElementsByTagName("STARS")[0].firstChild.nodeValue;
var avgPrice = markers[i].getElementsByTagName("AVE_PRICE_USD")[0].firstChild.nodeValue;

// Generate rating stars HTML DIV
var ratingHtml = generateRatingHtml(hotelStars);

point.name = "<div class='info-window'><b>" + hotelName + "</b><br/><table><tr><td><img src='" +
hotelImg + "' height='100'></td><td>" + ratingHtml + "<br/>Ave. Price:$"+ avgPrice +
" (USD)<br/> <a href='" + hotelWebAddress + "'>Book it!</a></td></tr><tr><td colspan='2'>" +
hotelDescription + "</td></tr></table><br/></div>";

mapMarkers.push(createHotelMarker(point));
}
showMap();
}
});
}

要注意的第一部分代码是对 generateRequestArgs( ) 函数的调用。该函数将构建一个查询字符串,并根据 JavaScript 全局变量 poolbeach 等的值以“?pool=true&beach=true&price=400&region=europe ”格式返回。该字符串将被指定给 ajaxParms 字符串,ajaxParms 字符串随后被追加到 GDownloadUrl( ) 的第一个参数,该参数是指向 Java Servlet“/ACME-Hotel-Locator/xmlservlet ”的 URL,/ACME-Hotel-Locator/xmlservlet 将返回 XML 数据:

GDownloadUrl("/ACME-Hotel-Locator/xmlservlet" + ajaxParms
, function(data, responseCode) {...} );

GDownloadUrl( ) 调用中的第二个参数是回调函数 ,它的工作是处理从 Ajax 请求接收的传入数据。

您在第二个参数/回调函数中可以看到,第一个参数是从查询返回的实际 XML 数据 。在回调函数的主体中,我们调用了 GXml.parse(data) 以分析传入的 XML 数据,并将用作一个文档对象模型 (DOM) 对象,以便使用 JavaScript 来迭代值和管理数据。

var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName("hotelinfo");

在建立表示 XML 数据的 DOM 对象的句柄之后,将一个名为 markers 的变量指定给 getElementsByTagName ( )(即,对应于父标记“hotelinfo”的元素数组)的返回值。如果从查询检索到数据,代码将迭代不同的元素,并在地图上为每个相应的宾馆添加点(标记)。以下是执行此操作的循环代码:

for (var i = 0; i < markers.length; i++) {
var point = new GLatLng(parseFloat(markers[i].getElementsByTagName
("LATITUDE")[0].firstChild.nodeValue),
parseFloat(markers[i].getElementsByTagName("LONGITUDE")[0].firstChild.nodeValue));

var hotelName = markers[i].getElementsByTagName("NAME")[0].firstChild.nodeValue;
var hotelDescription = markers[i].getElementsByTagName("DESCRIPTION")[0].firstChild.nodeValue;
var hotelStars = markers[i].getElementsByTagName("STARS")[0].firstChild.nodeValue;
...

// Generate rating stars HTML DIV
var ratingHtml = generateRatingHtml(hotelStars);

point.name = "<div class='info-window'><b>" + hotelName + "</b><br/>
<table><tr><td><img src='" + hotelImg + "' height='100'></td><td>" + ratingHtml +
"<br/>Ave. Price:$"+ avgPrice + " (USD)<br/> <a href='" + hotelWebAddress + "'>Book it!</a>
</td></tr><tr><td colspan='2'>" + hotelDescription + "</td></tr></table><br/></div>";

mapMarkers.push(createHotelMarker(point));
}

进一步检查之后,您将看到代码使用 Google Maps GLatLng 类构造函数(使用经度和纬度值作为参数)创建了一个新的 point 对象。这些值都是使用 DOM getElementsByTagName 调用从 markers 数组中提取的:

markers[i].getElementsByTagName("LATITUDE")[0].firstChild.nodeValue

在作为参数发送给 GLatLng 构造函数之前,系统将使用原生 JavaScript parseFloat( ) 将该值分析为 JavaScript 浮点数。

一旦创建了新的 GLatLng 点,剩余步骤就是将附加宾馆信息添加到点的 name 域。为此,需要使用同一个 DOM 方法从 XML 流中提取其他域(例如,namedescription 等),然后在 HTML 中将它们一起连接到 name 域。您可能还注意到,ratingHtml 值是使用另一个函数 generateRatingHtml( ) 生成的,该函数用于提取 XML 流返回的星级信息,并生成 HTML 中包含星星图形的一小部分。

 function generateRatingHtml(stars){
var starsHtml = "<div style='white-space:nowrap;'>";

for (i=0; i<5; i++){
if (i < stars )
starsHtml += "<img src='images/star-rating-on.jpg'>";
else
starsHtml += "<img src='images/star-rating-off.jpg'>";
}
starsHtml += "</div>";

return starsHtml;
}

返回到循环代码,一旦整个 point.name 域都填充了宾馆信息,系统将使用 createHotelMarker( ) 函数在新的点上创建一个新的 Google Maps 标记 (GMarker ),并将其推送到全局 mapMarkers 数组中。

顺便说一下,createHotelMarker( ) 函数是应用程序中最重要的函数之一,因为它可以根据所提供的 point 对象创建新的标记 (GMarker ) ,并建立在标记上监听鼠标单击事件的“click”监听器。(注:使用其他图标创建您自己的自定义标记也相对比较简单,但此内容超出了本文的讨论范围。)

 function createHotelMarker(point) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
var opts = {pixelOffset:new GSize(32,5), maxWidth:280};
marker.openInfoWindowHtml( point.name, opts);
});
return marker;
}

对于标记上的每个鼠标单击操作,将使用 marker.openInfoWindowHtml( ) 弹出一个新窗口 (GInfoWindow) 。注意,在对 openInfoWindowHtml ( ) 的调用中,第一个参数是 point.name 属性,该属性包含了宾馆的 HTML 内容。第二个参数只是一个选项参数,指定窗口宽度不应超过 280 像素,并且窗口显示的位置应该距离标记水平方向 32 像素、垂直方向 5 像素。

在使用所有宾馆信息填充全局标记数组 mapMarkers 之后,就可以使用 showMap( ) 函数在地图上显示宾馆点了。以下是 showMap( ) 的代码:

 function showMap(){
// Find boundary points of hotel location
var bounds = new GLatLngBounds();
for (var i=0;i < mapMarkers .length;i++) {
map.addOverlay(mapMarkers[i]);
bounds.extend(mapMarkers[i].getPoint());
}

// Reset center and zoom level based on queried hotel locations
map.setCenter(bounds.getCenter());
map.setZoom(map.getBoundsZoomLevel(bounds));


http://www.oracle.com/technology/global/cn/pub/articles/schalk-googlemaps.html
}

showMap( ) 函数将遍历 mapMarkers 数组,并将其添加到地图中(以叠加方式)。它还可以决定标记的外边界,以便地图可以适当地重新调整中心和缩放。

结论

如您所见,构建该应用程序相对比较简单。两个 Java 类 XMLGeneratorXMLServlet 分别执行从 Web 页客户端响应 Ajax 请求、然后将其转换为数据库查询的任务。随后,使用 XMLServlet 通过 HTTP 将结果重新流入 XML 流,从而允许 Web 页中的 Google Maps 应用程序轻松分析 XML,并将其显示在地图上。就这样!有了 Oracle XML DB,生成 XML 数据非常轻松。在 Oracle JDeveloper 中创建 Java 类以及 HTML Web 页客户端也很轻松。


Chris Schalk 是 Google 开发提倡者,致力于推动 Google 的 Ajax API 和技术。在加入 Google 之前,Chris 是 Oracle Java 开发工具小组的首席产品经理和技术推广者。Chris 最近还与他人合著了《JavaServer Faces, The Complete Reference》 (McGraw-Hill/Osborne) 一书。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值