目前,幾乎所有的網站都宣稱 “ 使用 [Browser X] 提供最佳視圖”。現代的 Ajax 庫, 比如 Prototype、Dojo 和 YUI,有效地縮小了 Firefox、Internet Explorer 和 Safari 之間的差距。 但是使用 Nokia、Motorola 或者 Apple 手機的人可能不會喜歡浏覽器的獨立性。即使是最新的呼吁 “支持完整 HTML ” 的移動浏覽器也可以從簡單更改網絡內容中獲益。本文將向您展示如何 優化 Grails 應用程序,使其適用於移動浏覽器。
如果您還在疑慮為什麼非要使網站便於移動浏覽的話,看一看 移動 Web 的使用率正在增長 邊欄裡面 的數字就會明白了。這份全球的統計數字確實讓人過目難忘,但熱衷移動 Web 源於我個人的興趣。我在 2007 年春天買了一個 iPhone,那時它剛剛上市。從那以後,我就一直在尋找可以用它來浏覽的網站。當 然,我可以用它訪問任何的網站(只要不是基於 Flash 或者 Java™ applet 的網站,因為它不支 持)。問題是,適合在分辨率為 800x600 (或更高)的顯示器上顯示的內容,在 3.5 英寸的屏幕上顯示 效果就沒有那麼好了。
我經常訪問的那些帶有 UI 的網站,因為它們符合我的手機的特定限制。我的手機會用 m 代替普通站 點中傳統的 URL www,這就是一個很好的起點。http://m.cnn.com、http://m.yahoo.com 和 http://m.google.com 這樣的頁面就能在我的手機上顯示。有些網站,比如 http://www.twitter.com, 則會做出相應的調整,以輸出合適的內容:在電腦上浏覽,我可以獲得全部功能;而在手機上浏覽時,則 刪剪了一些內容,使它剛好適合我的屏幕。我將向您展示如何實現不改變 URL,但提供最佳 UI。
針對移動 Web 開發人員的技術
作為一個 Java 開發人員,我已經被 “只寫一次,到處 運行(Write Once,Run Anywhere)” 的承諾給寵壞了。我甚至從來沒有考慮過優化 Java 應用程 序使其適合某一特定的操作系統或硬件型號。但是如果是要開發移動 Web 的話,就應該熟悉三種支持不 同型號移動設備的主要技術:
無線標記語言(Wireless Markup Language 1.x,WML 1.x)
WML 2.x 或 Mobile Profile (XHTML-MP)
針對 iPhone 的 HTML 標記
正如我展示的一樣,您可以將 WML 和 XHTML-MP 標記與用 Grails 構建的 Groovy Server Pages(GSPs)結合起來,以生成便於移動的頁面。此外,我還 會向您展示如何修改 Grails 生成的 HTML,使頁面在 iPhone 上顯示得更好。
結合使用 WML 1.x 和 Grails
WML 是一種類似於 HTML 的標記語言,但它並不是真正的 HTML(WML 1.0 於 1998 年 標准化。WML 1.3 為最新版本)。WML 並無法在 Web 浏覽器中查看(至少不借助於仿真器是不行的), 同樣您也無法在 WML 浏覽器中查看 HTML。手機供應商通常都會提供在後台實現 HTML 與 WML 之間相互 轉換的網關。
WML 通過無線訪問協議(Wireless Access Protocol,WAP)傳輸,這和 HTML 通過 HTTP 傳輸很相似。WAP 和 WML 在臨時對話中通常可以相互轉換:手機說明書總是會誇耀該手機帶有 WAP 浏覽器,或者支持 WML 1.x(參閱 參考資料 獲得 WML 和 WAP 規范的官方鏈接)。
如果您針對 的是 Research in Motion 的 BlackBerry 用戶的話,就得提高關於 WML 的知識了。(BlackBerry 大約 占了智能手機市場的 40%,iPhones 和 Windows® Mobile 居於第二和第三位)。雖然很多技術過硬 的用戶也可以下載真正的 Web 浏覽器,比如 Opera Mini(參見 參考資料),但是 BlackBerry 智能手 機還是配備了 WAP 浏覽器。
繼續設計旅行計劃
如果您一直都在關注 精通 Grails 系列文章的話,那麼您可以修改已經熟悉的旅行計劃應用程序,使 它便於在手機上浏覽。在旅行計劃應用程序的 web-app 目錄中創建一個文件,命名為 testwml.gsp,並 輸入清單 1 中的靜態 WML:
清單 1. 靜態 WML
<% response.setContentType("text/vnd.wap.wml") %>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
"http://www.phone.com/dtd/wml11.dtd" >
<wml>
<card id="f1" title="Flight 1">
<p mode="wrap">From: DEN</p>
<p mode="wrap">To: ORD</p>
<p mode="wrap">UAL 1234</p>
<p mode="wrap">Jun 30, 10:30am</p>
<p>
<anchor>Next<go href="#f2"/></anchor>
</p>
</card>
<card id="f2" title="Flight 2">
<p mode="wrap">From: ORD</p>
<p mode="wrap">To: DEN</p>
<p mode="wrap">UAL 9876</p>
<p mode="wrap">Jul 02, 1:15pm</p>
<p>
<anchor>Previous<go href="#f1"/></anchor>
</p>
</card>
</wml>
您用手機訪問 http://www.davisworld.org/testwml.gsp 同樣可以看到這個頁面。您可能習慣於在 GSP 中查看 HTML。但在這裡使用的是 WML。
當從 GSP 中發送出 WML 時,切記要將默認的 MIME 類型 text/html 替換為 text/vnd.wap.wml,如 清單 1 中的第一行所示。如果直接提供靜態 WML,那麼只需賦予文件一個 WML 擴展名,而不是 GSP 擴 展名。大多數 Web 服務器會在這之後自動返回一個正確的 MIME 類型,無需調用 response.setContentType。在 $TOMCAT_HOME/conf/web.xml 中,您會發現 MIME 針對 WML 文件的映射 已經就位。如果您使用的是 Apache HTTPD 的話,那麼您可以在 $APACHE_HOME/conf/mime.types 文件中 找到類似的 WML 文件的映射。清單 2 向展示了 Tomcat 的 MIME 類型映射:
清單 2. 在 Tomcat 中設置 MIME 類型
<mime-mapping>
<!-- WML Source -->
<extension>wml</extension>
<mime-type>text/vnd.wap.wml</mime-type>
</mime-mapping>
回過頭來在看一下 清單 1,接下來需要注意的是 DOCTYPE。包含文檔類型定義(Document Type Definition,DTD)語句可以幫助將 WML 文檔識別為 testwml.gsp。
注意該文件並未打包在常見的 <html> 標記中。它的開頭和結尾為 <wml>。您可能還注 意到 清單 1 中缺少 <head> 和 <body> 部分。每一個 WML 頁面為一個 card,擁有一個獨 立的 id 屬性和便於用戶使用的 title 屬性。
通常情況下,在一個單一文件中可以下載多個頁面/卡片。早期的手機的數據通道非常狹窄,而這種方 法剛好就緩和了這些設備及其網絡的局限性。一次下載得越多,手機與服務器之間的數據轉就越少。因為 一次只能查看一個頁面,這樣就可以有效地提前獲取其余的頁面。對於這種情況,導航只發生在客戶端。
HTML 開發人員一定要熟悉 <p> 標記。WML <anchor> 標記在本質上與 HTML <a> 標記是類似的,即使它們在語法上有所不同(參閱 參考資料 了解更多關於 WML 的信息)。
下面是 WML 的一個小技巧。由於處理的是專用於手機的內容,因此可以創建一個超鏈接,用戶一旦選 定鏈接,就可以撥出電話。清單 3 的中例子可以撥出電話號碼 303-555-1212 :
清單 3. WML 撥號鏈接
<do type="accept">
<go href="wtai://wp/mc;3035551212"/>
</do>
注意該鏈接使用的協議並非常見的 http:// — 而是 wtai://,這是無線電話應用程序界面 (Wireless Telephony Applications Interface)的縮寫。
WML 仿真器
要使這個頁面在個人電腦上顯示,則需要一個 WAP 仿真器(參閱 參考資料,查看文中提到的所有仿 真器的鏈接)。訪問 dotMobi 仿真器,它是一個 Java applet。輸入 URL davisworld.org/testwml.gsp (注意 http:// 前綴已提供在輸入框的左側),您將看到類似於圖 1 的內容:
圖 1. 仿真 WAP 頁面
注意 dotMobi 仿真器有兩種不同的皮膚,它不僅代表著不同設備的外觀和感覺,還代表設備的不同功 能。如果對仿真某個設備感興趣的話,它的硬件制造商通常會提供一個開發者網站,您可以從哪裡下載安 裝所需的仿真器。
從 GSP 發送靜態 WML
第一個 WML 例子為靜態代碼。清單 4 是一個使用常見的 <g:each> 和 <g:if> 標記的 例子:
清單 4. 結合 GSP 和 WML
<% response.setContentType("text/vnd.wap.wml") % >
<%
def flightList = []
flightList << [iata1:"DEN", iata2:"ORD"]
flightList << [iata1:"ORD", iata2:"DEN"]
%>
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
"http://www.phone.com/dtd/wml11.dtd" >
<wml>
<g:each in="${flightList}" var="${flight}" status="i">
<card id="f${i}" title="Flight ${i}">
<p mode="wrap">From: ${flight.iata1}</p>
<p mode="wrap">To: ${flight.iata2}</p>
<g:if test="${flightList.size() > i+1}">
<p>
<anchor>Next<go href="#f${i}"/></anchor>
</p>
</g:if>
</card>
</g:each>
</wml>
注意我僅僅模仿了 HashMap 中的一些機載數據,而不是設置完整的 MVC 基礎設施。重要的是它能保 證了 GSP 標記與 WML 的結合,就像我在 “精通 Grails: 用 Groovy 服務器頁面(GSP)改變視圖” 中 處理 JavaScript 一樣(可以在 http://davisworld.org/testwml2.gsp. 中查看到這個頁面的示例)。
WML 1.x:一個時代的終結
雖然常有人斷言 WML 的生命快到頭了,但僅支持 WML 的手機仍在流通。沒錯!— WML 1.x 正在淡出 江湖。越來越多的現代手機開始避免這種 “分離但平等的” WML 平台,轉而使用真正的 Web 浏覽器。 正如下一節所演示的一樣,要為 WML 2.x 設備或 iPhones 創建一個便於移動的浏覽網站,只需在現存的 HTML 上做些變動,而不是將其轉換成完全不同的標記語言。
結合使用 Grails 與 WML 2.X(或 XHTML-MP)
提到 WML 2.x,WML 更像是一個品牌的名稱,而不是一個獨立的標記語言(WML 1.x 才是)。事實上 ,WML 2.x 只不過是 XHTML 的一個方言:明確地說是 XHTML-MP。
XHTML-MP 嚴格要求創建格式良好的 XML。這就意味必須正確地關閉每一個容器標記 (<p></p>、<li></li>),屬性前後要用引號(<a href="http://somewhere.com">),並且元素名稱只能用小寫字母(<h1> 而不是 <H1> )。
XHTML-MP 是 XHTML-Basic 的一個超集。只要稍作調整,您的網站就遵循 XHTML-Basic 規范。XHTML -MP 不可以使用嵌套的表格或框架。它只支持 gif 和 png 圖像格式。至於其他的最佳實踐(比如指定圖 像大小和替換文本)則是 XHTML-Basic 的要求。很多常見的 HTML 標記(雖然不是全部)都可以找到。 參閱 參考資料 獲得可用於 XHTML-Basic 和 XHTML-MP 的標記的列表鏈接。
要優化網站使其適合較小屏幕,就必須減少針對每個請求發回的數據。Web 網頁(包括 HTML、CSS 和 圖像)最好小於 20KB。並且要使用 Expires 或者 Cache-Control header 來主動緩沖文件。當為移動設 備提供內容時,要將網頁分割為 2 到 3 頁。http://m.cnn.com 在這方面做的就很好,它可以將整篇文 章分成 3 到 4 頁顯示,但也提供了 “整篇文章” 的鏈接,如果您不介意額外開銷的話。
就像使用 WML 1.x 一樣,必須在文件的開始包含正確的 DTD。同時還要修改 <html> 標記,使 其包含 xmlns 屬性,如清單 5 所示:
清單 5. 啟動 XHTML-MP 文件
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
...
</html>
雖然很多移動設備也接受更加通用的 MIME 類型 application/xhtml+xml ,但您仍然要用適當的 MIME 類型 application/vnd.wap.xhtml+xml 將其發送。application/xhtml+xml 可以幫助您在標准桌面 浏覽器中調試代碼。
查看 XHTML-MP
訪問 http://m.yahoo.com 可以查看 XHTML-MP。(雖然它在 Web 浏覽其中看起來很簡樸,但在手機 上的效果卻很好)。選擇 View > Source,就會在文檔頂端看見 XHTML-MP DTD 了。
想要更深入地了解這樣的網站在真機上的效果到底如何,您還需要找到另外一個仿真器。例如, Sandip Chitale 的博客提供了 Firefox 插件,它看來真的很象一個 iPhone(參閱 參考資料)。注意, 這個仿真器要比真機大一些,但是它顯示的網站效果跟在 iPhone 上顯示的效果非常接近。(我將指出一 些更精確的驗證器)。圖 2 展示了用 Chitale 的仿真器仿真的 m.yahoo.com:
圖 2. 使用 iPhone 仿真器查看 Yahoo 移動 web
驗證 XHTML-MP
有幾個在線驗證器可以確保您發出的 XHTML-MP 是格式良好的。您可以嘗試一下 W3C mobileOK Basic Checker 或 ready.mobi 測試工具(參閱 參考資料)。二者都很好,但是 ready.mobi 的仿真器提供的 信息要比 W3C 多得多。
例如,圖 3 展示了 W3C 驗證器所提供的關於 http://m.google.com 的信息:
圖 3. W3C 驗證器提供的有關 Google 的移動 web 的報告
圖 4 為 ready.mobi 工具提供的關於 http://m.yahoo.com 的報告的前一部分:
圖 4. ready.mobi 提供的關於 Yahoo 的移動 web 的報告
它顯示了 Yahoo! 的 4/5。再往下拉一點點,您就可以看到很多不同的可視化器,使您可以看到網頁 的真正顯示效果。圖 5 展示了它在 Nokia N70 的效果:
圖 5. 使用仿真器查看 Yahoo 的移動 web
在頁面的底部,ready.mobi 驗證器展示了一組詳細的測試結果,每一個結果都帶有這樣的標記:通過 (綠色)、失敗(紅色)或警告(黃色)。例如,即使 http://m.yahoo.com 好像在各種設備上都顯示得 不錯,其 XHTML 也不是 100% 遵從的,如圖 6 所示:
圖 6. 查看 XHTML-MP 遵從性錯誤
再往下看,如圖 7 所示,您會看到 Yahoo! 在圖像上遺漏了一些 alt 屬性,而且在某些情況下沒有 指定圖像的大小:
圖 7. 查看具體的錯誤
Grails 與 XHTML-MP
那麼,Grails 已經可以直接用於開發移動 Web 了嗎?圖 8 展示了 ready.mobi 驗證器提供的關於旅 行計劃應用程序的原始清單頁面的信息:
圖 8. Grails 沒有直接遵從 XHTML-MP
那就是說,還需要做一些工作。首先,在 grails-app/controllers/AirportController.groovy 中創 建一個 mlist 閉包。除了會返回 5 個(而不是 10 個)元素外,它與默認的閉包沒什麼不同。創建一個 單獨的閉包保留,您就可以原樣保持 list.gsp,以進行比較,如清單 6 所示:
清單 6. AirportController 中的新閉包
def mlist = {
if(!params.max) params.max = 5
[airportList:Airport.list(params)]
}
現在將 grails-app/views/airport/list.gsp 復制到 mlist.gsp。(一會兒,我將提供一些策略,從 而將移動用戶無縫地重定向到正確的內容。這個強有力的方法目前還能滿足需求)。
驗證器指出網站未返回 XHTML-MP。編輯 mlist.gsp 使它在 <html> 標記中包含有必要的 DTD 和 xmlns 屬性。您還需要禁用 meta 標記,因為它會自動將內容類型設置為 text/html。最後一步:將 grails-app/views/layout/main.gsp 中包含 CSS 的行復制到該文件中。(SiteMesh — Grails 使用的 模板庫 — 配置為只在默認情況下修飾 text/html 文件)。清單 7 展示了 mlist.gsp:
清單 7. 將 GSP 頁面轉變成 XHTML-MP
<% response.setContentType ("application/xhtml+xml")%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<!--meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/-->
<link rel="stylesheet" href="${createLinkTo(dir:'css',file:'main.css')}" />
<meta name="layout" content="main" />
<title>Airport List</title>
</head>
...
</html>
在編輯文件時,也可以簡化表布局。驗證器指出 <thead> 和 <tbody> 標記有誤,所以 需要將其刪除。由於手機屏幕的縱向空間要比橫向空間大,所以清單 8 所示的布局看起來會好一些:
清單 8. 簡化表
<table>
<tr>
<g:sortableColumn property="id" title="Id" />
<g:sortableColumn property="name" title="Name" />
</tr>
<g:each in="${airportList}" status="i" var="airport">
<tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
<td>
<g:link action="show"
id="${airport.id}">${airport.id?.encodeAsHTML()}
</g:link>
</td>
<td>${airport.iata?.encodeAsHTML()}<br/>
${airport.name?.encodeAsHTML()}
</td>
</tr>
</g:each>
</table>
圖 9 展示了新頁面在 iPhone 仿真器中的顯示效果:
圖 9. 為 iPhone 定制的列表頁面
圖 10 展示了此時 ready.mobi 驗證器所提供的信息:
圖 10. 通過驗證的列表頁面
這就好多了!而且針對驗證器的必要更改是很少的。回顧 “精通 Grails: 用 Groovy 服務器頁面 (GSP)改變視圖”,可以通過輸入 grails install-templates 來相應地更改默認模板。
為 iPhone 開發頁面
iPhone 可能就是三種類型的設備中最容易支持的設備。它頁面的開發與普通的 Web 頁面開發完全相 同。iPhone 上的 Safari 浏覽器與桌面浏覽器的代碼庫完全相同,因此,用戶在兩者中所看到的東西是 一樣的。但是您可以去掉一些顯示提示,因為通過 iPhone 查看網站時它們會影響外觀和感覺。
例如,一個 iPhone 的屏幕尺寸為 320x480,但有趣的是,浏覽器設置的網頁的默認寬度為 980 像素 。這使文本在手機的景色模式下不能讀取,並且在肖像模式下會變得很小。但是不用擔心,使用一個簡單 的只有 iPhone 才能識別的 meta 標記,就可以將網頁校正到 “正確的尺寸” 了:viewport 標記允許 為移動 Safari 浏覽器添加提示。清單 9 中的代碼就在很大程度上提高了在 iPhone 上查看的網頁的可 讀性。(不幸的是,基於 Firefox 的 iPhone 仿真器無法識別這個 meta 標記。只有在真正的 iPhone 上才可以看到它的實際運行)。
清單 9. 為 iPhone 設置 viewport
<meta name="viewport" content="initial-scale=1.0" />
inital-scale 的范圍為 0 到 10,且支持分數值。也可以輸入顯式的 width 和 height 值,上限為 10,000 像素(如清單 10 所示):
清單 10. 為 viewport 設置 width 和 height
<meta name="viewport" content="width=600;height=400" />
iPhone 上的超鏈接
說到超鏈接,iPhone 提供了一些特殊的性能。如果使用 tel: 前綴代替 http://,單擊鏈接就可以撥 出一個電話號碼,如清單 11 所示:
清單 11. iPhone 上可用於撥號的鏈接
<p>
telephone number:
<a href="tel:303-555-1212">303-555-1212</a>
</p>
如果使用傳統的 mailto: 前綴的話,單擊鏈接就會運行郵件應用程序,如清單 12 所示:
清單 12. 郵件鏈接
<p>
mail:
<a href="mailto:[email protected]">Scott Davis</a>
</p>
如果您為 Google Map 提供一個鏈接,單擊鏈接就會運行本地 Google Maps 應用程序,而不是將其轉 交到 Safari 中,如清單 13 所示:
清單 13. Google Map 鏈接
<p>
local google maps:
<a href="http://maps.google.com/maps? q=denver+international+airport">DEN</a>
</p>
輸入一個起點和終點,單擊鏈接,它就會為用戶提供駕駛方向,如清單 14 所示:
清單 14. Google Map 駕駛方向
<p>
driving directions:
<a href="http://maps.google.com/maps?daddr=
denver+airport&saddr=coors+field+denver,+co">Directions</a>
</p>
移動 Web 開發策略
您已經知道為三種基本設備創建內容都需要什麼工具,現在的任務是如何根據需要使用它們。有三種 基本的策略可供選擇。
為移動內容創建獨立的、專用的網站
正如前面看到的一樣,m 是許多 Web 站點所采用的策略。Google、Yahoo! 以及 CNN,都設置了一個 m 域,它獨立於主站點,用於提供移動內容。如果改動域名系統(Domain Name System,DNS)的話,可 以創建一個類似 http://mysite.org/mobile 的 URL。您也可以注冊一個移動內容專用的 .mobi 域。
監聽用戶代理
每一個 Web 浏覽器在請求數據時都向服務器表明身份。可以利用這個信息來提供為設備定制的內容。 (http://twitter.com 使用的就是這種技術)。
訪問 http://davisworld.org/echo.gsp。清單 15 中的頁面只用了個簡單的循環,就回應了 HTTP 的 請求:
清單 15. 顯示 Request Header
<h2>Request Headers</h2>
<table border="1">
<tr>
<th>Header</th>
<th>Value</th>
</tr>
<g:each in="${request.headerNames}" var="${name}">
<tr>
<td>${name}</td>
<td>${request.getHeader(name)}</td>
</tr>
</g:each>
</table>
正如您在圖 11 中所看到的,當我打開 http://davisworld.org/echo.gsp 時,Firefox 浏覽器提供 了足夠身份提示:
圖 11. 查看 HTTP header
根據圖 11 中展示的 user-agent 字符串,就可以斷定請求程序通過 Intel CPU 運行 Mac 系統。對 於 OS(10.5)、HTML 呈現引擎(Gecko)、和真實浏覽器(Firefox)的版本,您已經很熟悉了。清單 17 展示了其他常見的用戶-代理字符串:
清單 17. 常見的用戶-代理字符串
BlackBerry7520/4.0.0 Profile/MIDP-2.0 Configuration/CLDC-1.1
UP.Browser/5.0.3.3 UP.Link/5.1.2.12
Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en)
AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)
通過捕獲 request.getHeader("user-agent") 值為請求浏覽器提供適當的內容。
發回浏覽器接受的內容
第三種策略就是滿足浏覽器的所有請求。每一個請求都會包含一個 accept 值和一個 user-agent 值 。Firefox 返回的 accept 值如下:
text/html,application/xhtml+xml,application/xml;
這告訴服務器 Firefox 偏好 text/html。如果服務器不包含 text/html 數據,那麼它可以發送 application/xhtml+xml。如果兩者都沒有的話,服務器會在列表中逐個查找,直到找到一個可以返回的 MIME 類型。
WAP 1.x 浏覽器需要 text/vnd.wap.wml,更現代的手機會需要 application/vnd.wap.xhtml+xml。只 要多加注意,聰明的開發者便可以返回適當的數據。
當然,這三種策略並不是相互排斥的。您可以全部選用,確保您的網站已經准備好為全球 33 億的手 機用戶提供服務了。
結束語
讓 Grails 應用程序便於手機使用的方法有很多種,可以不做任何改動(對於 iPhone 而言)、做很 小的改動(對於 XHTML-MP 設備而言)、或者全部重寫(對於 WML 1.x 設備而言)。借助文中所介紹的 這些仿真器和驗證器,您一定可以實現順利支持移動 Web。
在下一篇文章中,您將會學習如何處理 Grails 中的遺留數據庫。您將學習 Mapping DSL、使用 Hibernate 注釋和 HBM 文件。學會了這些技術,您就可以讓 Grails 使用現有的表和字段名,即使它們 不符合 Grails 標准命名規定。到時候就盡情享受精通 Grails 的帶來的樂趣了。