将 Google Maps 与 Oracle 数据库混搭

AI旅行规划与实时导航智能体:架构设计与工程实践 AI Agent(人工智能智能体)作为当前AI应用的核心范式,通过感知、决策与执行闭环,将大语言模型(LLM)的能力延伸至复杂任务场景。其技术原理在于整合多模态输入(如语音、位置)、外部工具调用(如地图API、数据库)与持续学习机制,实现动态环境下的自主交互。这一架构在提升服务自动化与个性化水平方面具有显著价值,尤其在需要实时响应与多源信息融合的领域。AI旅行规划与实时导航正是其典型应用场景,它要求智能体在行前规划阶段理解用户偏好并生成可行行程,在落地执行阶段结合实时位置、交通数据与上下文进行动态调整与语音 阅读详情

作者: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 onload="initMap()"
 onunload="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 ,它混搭了卫星图像和地理数据。最后,向地图添加两个控件:GLargeMapControl 和 GMapTypeControl ,前者是缩放控件的大版本,后者允许用户在不同的地图类型(Map 、Satellite 、Hybrid 、Traffic 等)之间切换。

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

Has pool: Beach access: Price: Region:

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

<form action="#" onsubmit="showHotels(); return false"> 
<p>
Has pool:<input type="checkbox" id="pool " onclick="togglePool() "/> 
Beach access:<input type="checkbox" id="beach " onclick="toggleBeach() "/> 
Price:
<select id="price " onchange="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 " onchange="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>

表单包含四个不同的输入值:pool 、beach 、price 和 region ,每个输入域都随附一个相应的 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 全局变量 pool 、beach 等的值以“?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 流中提取其他域(例如,name 、description 等),然后在 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 类 XMLGenerator 和 XMLServlet 分别执行从 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) 一书。

Unity项目包体优化:Build Report Tool深度解析与实战瘦身策略 在游戏开发中,包体大小是影响用户体验和项目成功的关键性能指标。其核心原理在于构建管线对项目资源的收集、处理和打包过程,任何未被优化的资源都会直接导致最终应用体积膨胀。从技术价值看,有效的包体管理不仅能降低用户下载门槛和存储成本,还能提升应用商店的曝光率与留存率。常见的应用场景包括移动端游戏、应用分发以及任何对安装包大小敏感的项目。针对这一需求,Unity社区的Build Report Tool插件提供了详尽的构建后分析能力,它能精确诊断出纹理、音频等资源的体积占比,帮助开发者定位冗余资产。通过结合纹理压缩、 阅读详情

相关推荐

Mythos大模型:自主漏洞挖掘与攻防能力跃迁的技术解析

大语言模型正从代码理解迈向自主攻防决策,其核心在于对软件工程逻辑与红蓝对抗范式的双重建模。这类模型不再依赖人工提示引导,而是基于上下文直觉与动态攻击图谱,完成从漏洞发现、逆向分析到利用验证的全链路闭环。技术价值体现在对真实生产环境(如Linux内核、Nginx定制模块、Oracle RAC)的深度语义理解与跨栈状态感知能力;应用场景覆盖金融系统安全加固、开源组件风险治理及CTF级复杂渗透模拟。Mythos作为典型代表,标志着AI安全能力从辅助工具升维为可定义‘找bug’标准的自主智能体。

weixin_30384217的博客 305

Redis 与其他数据库的混合架构如何设计

Redis 与其他数据库(如关系型数据库 MySQL、PostgreSQL 或非关系型数据库 MongoDB 等)的混合架构设计,通常是为了利用 Redis 的高性能读写和数据结构操作能力,同时保留传统数据库的数据持久性和复杂查询功能。综上所述,设计 Redis 与其他数据库的混合架构需要结合业务需求和技术特点,精心规划各个组件的角色和交互方式,从而达到最佳性能和可靠性。

Pmyx_wyh的博客 354

Unity安卓应用签名:从Keystore创建到团队安全管理的完整指南

在安卓应用开发中,数字签名是确保应用完整性和开发者身份认证的核心安全机制。其原理基于非对称加密技术,通过私钥签名、公钥验证的方式,为每个应用提供唯一的“数字身份证”。这项技术的核心价值在于防止应用被篡改、确保更新来源可信,是应用商店上架和用户数据安全的基石。在Unity引擎开发安卓游戏或应用时,签名通过Keystore文件实现,它管理着私钥和证书链。对于团队协作项目,Keystore的安全管理尤为重要,需要避免将其直接提交到Git等版本控制系统,而应通过环境变量或密钥管理服务集成到CI/CD自动化构建流程中

weixin_33766805的博客 352

大数据时代数据库混合部署方案探究

 大数据时代数据库混合部署方案探究   引言 在大数据时代,“多种架构支持多类应用”成为数据库行业应对大数据的基本思路,数据库行业出现互为补充的三大阵营,适用于事务处理应用的OldSQL、适用于数据分析应用的NewSQL和适用于互联网应用的NoSQL。但在一些复杂的应用场景中,单一数据库架构都不能完全满足应用场景对海量结构化和非结构化数据的存储管理、复杂分析、关联查询、实时性处理和

DZT的专栏 3849

Ubuntu 16.04搭建Webmin+Virtualmin全栈服务器管理平台

Linux服务器管理平台是支撑网站托管、域名解析与邮件服务的核心基础设施,其本质是多个系统服务(如Web服务器、DNS、邮件传输代理)在统一内核下的协同运行。理解服务依赖关系、端口绑定原理、权限隔离机制(如AppArmor/systemd约束)及配置一致性校验,是实现稳定运维的关键技术基础。尤其在长期支持但已进入ESM阶段的Ubuntu 16.04上,Webmin与Virtualmin的版本兼容性、BIND的chroot初始化、Postfix的inet_interfaces配置等细节,直接决定DNS响应、S

weixin_33947521的博客 525

【信息科学与工程学】【数据中心】第三十五篇 云计算数据中心的学科知识04

编号学科(课程)核心知识点在云计算/云存储/云网络/云安全/云MaaS中的作用代表教材/资料/论文 + 数学方程式列表工业界应用D1421​云原生数据库:TiDB​HTAP(混合事务/分析处理)、分布式SQL、水平扩展、强一致(Raft)、自动故障恢复、与MySQL兼容、TiFlash列式引擎提供弹性扩展的分布式数据库;支撑高并发在线交易与实时分析教材:《TiDB in Action》PingCAP(2020) 论文:《TiDB: A Raft-based HTAP Database》(2017)

weixin_49199313的博客 401

使用 Oracle Spatial 创建地图混搭

转自:http://www.oracle.com/technology/global/cn/pub/articles/rubio-mashup.html 开发人员:Ajax 下载 Oracle 数据库(企业版安装选项) 示例代码 关键词 spatial,

fjfdszj的专栏 978

【信息科学与工程学】计算机科学与技术——第七十七篇 系统架构设计02

编号类型模型配方企业资本运作的方法/规则/条件/依据及所有的步骤(​风险处理/异常处理/危机应对关联知识法律法规和裁决依据​​由发起人(通常是知名投资人、投行或产业资本)先设立一个只有现金、无实际业务的特殊目的收购公司(SPAC),通过IPO募集资金并在交易所上市。然后在规定时间内(通常24个月)寻找一家非上市公司进行合并(De-SPAC),使目标公司迅速实现上市,规避传统IPO的复杂流程和不确定性。1.:在开曼或特拉华注册空壳公司,注入少量种子资金。2.

weixin_49199313的博客 309

Pro Oracle Spatial for Oracle Database 11g

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出版、作者信息和本声明。否则将追究法律责任。http://blog.youkuaiyun.com/topmvp - topmvpPro Oracle Spatial for Oracle Database 11g shows how to take advantage of Oracle Databases builtCin feature s

TopMVP 632

Google Maps 完整偏移数据库([offset.dat] 解包75M)

用于计算谷歌地图 Google Maps 经纬度偏移的数据库,具体转换方式请搜索资料,本篇暂不提供,只提供数据库。

115.工业相机海康SDK开发指南(阅读)

包含初始化SDK和反初始化SDK接口。(由于看不到函数内部的具体实现,因此以下的解释仅代表个人的理解)

weixin_63779802的博客 5993

关于google earth KML,自动编码设计生成

我们知道googleearth 中我们可以将自己的坐标信息进行共享,其中使用的方式就是通过kml实现的。    什么是KML呢?KML全称:Keyhole Markup Language,是基于XML(eXtensible Markup Language,可扩展标记语言)语法标准的一种标记语言(markup language),采用标记结构,含有嵌套的元素和属性。关于kml的编写标准我就不多

B10090120的专栏 3358

从零构建知识图谱:本体工程与知识建模实战指南

本文是一份从零构建知识图谱的实战指南,重点阐述了知识建模与本体工程的核心地位。文章详细介绍了如何使用Protégé工具进行本体设计,包括定义领域、复用现有本体、构建类层次与属性约束,并讲解了如何利用D2RQ工具将关系数据库数据转换为RDF三元组,最终通过Apache Jena Fuseki搭建SPARQL端点进行知识查询与推理,让知识图谱真正“活”起来。

weixin_29057695的博客 568

2010.04.08(2)———FusionChartsFree与google map结合

2010.04.08(2)———FusionChartsFree与google map结合 把前一段时间的技术研究整合一下 ========================= sql.txt =========================== [code="java"]create table cp_gongcheng ( id varchar2(6) primary k...

183

Kettle Web版部署指南

看到以上的日志则表示启动成功。

2401_89221867的博客 1718

考虑风和浪的影响的旋筒帆船航线优化方法研究

针对旋筒帆船进行航线优化的实现方法,包括升阻力系数的数值模拟、升阻力系数的多元非线性回归建模、旋筒帆船6DOF摇荡运动建模分析以及考虑风、浪影响的旋筒帆船的航线优化研究。

m0_63225885的博客 1163

针对AppleiPhone进行的开发之三

 导航栏  导航栏为 iPhone 应用程序提供了主要的导航机制。在前面的示例中,导航栏位于屏幕的顶部,提供了可打开另一视图的单击按钮。以下将详细介绍导航栏:  导航栏的代码如下所示: rendered="true" action="toAgent"/> rendered="true" action="backtoIntro"/> 同样,有关 listingImage 等样式

5686

FD.io/VPP — VPP 的实现原理解析

目录 文章目录目录VPPVPP 的关键创新技术数据报文的矢量处理标量报文处理方式I-cache miss 问题矢量数据报文处理方式标量 v.s. 矢量报文处理流程Packet Processing Graph(数据报文处理图)Packet Processing Graph 的处理流程Graph Node Plugin 机制 VPP WIKI:https://wiki.fd.io/view/VPP Docs:https://fd.io/docs/vpp/master/index.html Github:ht

烟云的计算 2593

csdnbloggers (updating)

深之JohnChen的专栏http://blog.youkuaiyun.com/byxdaz/(2006-2-7)陈鹏的专栏http://blog.youkuaiyun.com/feifei1018/(2006-2-7)艺术编程http://blog.youkuaiyun.com/fatalerror99/(2006-2-7)非常技术的。以 cpp 为主。Effective c++ 3e 系列翻译,相当不错。

LongAway 的 CyberLog 3402

多物理场光学仿真软件:Lumerical_(15).多物理场耦合仿真案例分析

在多物理场光学仿真中,Lumerical 软件提供了强大的工具来模拟复杂的光学系统,包括光子学、热学、力学和电学等多物理场的耦合。本节将通过具体的案例分析,展示如何在 Lumerical 中进行多物理场耦合仿真的开发和实现。我们将从简单的热光效应仿真入手,逐步深入到更复杂的多物理场耦合场景,如光电效应和光力学效应。每个案例都将包括详细的原理说明和具体的代码示例,帮助读者更好地理解和应用这些技术。

kkchenjj的博客 1022

一文吃透 SAP HANA SDA:把分散数据当作本地数据来用的那把钥匙

摘要:SAP HANA SDA(Smart Data Access)技术详解:150字精要 SAP HANA SDA是一种数据虚拟化技术,允许在不复制数据的情况下访问远端数据源。核心功能包括: 通过Remote Source定义连接配置 创建Virtual Table作为本地代理 支持谓词下推优化查询性能 与SDI技术协同工作扩展数据集成能力 典型应用场景包括: 跨系统联邦查询 冷热数据分层管理 混合云数据整合 远程表复制(RTR)实现近实时数据同步 实施要点: 需关注适配器能力差异 合理运用查询下推优化

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 320

GeoServer 的系统总体结构总结

[size=medium]GeoServer 的系统总体结构 GeoServer 是开源项目, 这就意味着你可以免费使用GeoServer, 并具有自行修改、复制以及再分发的权利。同时, GeoServer还有众多的优点: ( 1) 用JAVA 语言编写、标准的J2EE架构、基于servlet 和STRUTS 框架、支持高效的Spring 框架开发; ( 2) 兼容WMS和WFS特性、支持W...

技术交流 501

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

AI Orchestration:企业级大模型集成的中枢设计与落地实践

AI Orchestration(AI编排)是面向企业多系统环境的智能调度范式,其核心在于解耦数据流动、语义理解与业务执行——通过标准化接口协调异构系统与大语言模型协同工作。它基于事件驱动与协议适配原理,实现跨CRM、ERP、数据库等系统的实时数据聚合、动态工具调用与安全合规封装,技术价值体现在降低模型集成复杂度、保障数据主权、支撑高可用AI服务交付。典型应用场景覆盖销售智能体、设备预测性维护、临床试验患者筛选等强流程约束领域。本文聚焦MuleSoft与LangChain双脑架构的职责边界划分、黄金分割点设

weixin_34208185的博客 431

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

【Zabbix】开源分布式监控系统---Zabbix理论介绍

Zabbix是一款出色的企业级运维监控平台,可用于监控从服务器、网络设备到Web应用程序和数据库的性能和可用性的一切;它可以安装在 Linux、AIX、Windows、Solaris、MacOS X、FreeBSD、OpenBSD 等系统上使用,具有非常良好的适配能力。

weixin_43892251的博客 1219

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

AngularJS+PHP实现Mapcode数字地址生成器

数字地址是一种将地理坐标映射为短字符串的地理编码技术,其核心原理是基于球面网格划分与混合进制编码,具备全球唯一、长度固定、可逆解码等特性。该技术显著提升地址存储效率、降低系统耦合度,并在物流调度、政企内网、低带宽场景中展现出独特工程价值。本文聚焦于使用 AngularJS 与 PHP 落地 Mapcode 标准的轻量级实现,深入解析大小写敏感索引、MySQL 表碎片治理、幂等生成逻辑等生产级细节,尤其适配存量系统改造与自主可控部署需求。

cihongmo6452的博客 379
上一篇: cfengine概述
下一篇: 高性能 Oracle JDBC 编程
leminsky
博客等级 码龄22年 43粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值