精通 Grails: Grails 与移动 Web,M 是新型的 WWW

 前,几乎所有的网站都宣称 “ 使用 [Browser X] 提供最佳视图”。现代的 Ajax 库,比如 Prototype、Dojo 和 YUI,有效地缩小了 Firefox、Internet Explorer 和 Safari 之间的差距。但是使用 Nokia、Motorola 或者 Apple 手机的人可能不会喜欢浏览器的独立性。即使是最新的呼吁 “支持完整 HTML ” 的移动浏览器也可以从简单更改网络内容中获益。本文将向您展示如何优化 Grails 应用程序,使其适用于移动浏览器。

移动 Web 的使用率正在增长

据 Internet World Stats 称,目前 Internet 用户为 14 亿 — 约为全球总人口的 20%(请参阅 参考资料)。在北美洲,有 3/4 的人都是使用移动互联网。

在全球 66 亿人口当中,就有一半的人拥有手机。在北美洲,手机与 Internet 的市场占有率几乎相等,但在其他的地方则有所不同。在香港,手机的市场占有率为 140%,而在欧盟的部分国家(立陶宛,意大利和卢森堡公国)其市场占有率已高达 150%。的确,在某些地方手机比人还要多。

IDG Communications 的 Colin Crawfordsays 说到了要点(参见 参考资料):“在接下来的几年里,手机会作为上网的主要设备而逐步取代个人电脑。现在,通过手机访问互联网的比例已达到 30%,而在某些国家(比如日本)这个比例已高达 70%”。

如果您还在疑虑为什么非要使网站便于移动浏览的话,看一看 移动 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 之间相互转换的网关。

关于本系列

Grails 是一种新型 Web 开发框架,它将常见的 Spring 和 Hibernate 等 Java 技术与当前流行的实践(比如约定优于配置)相结合。在加入脚本语言的灵活性和动态性的同时,用 Groovy 编写的 Grails 可以无缝地集成遗留的 Java 代码。学习完 Grails 之后,您将改变看待 Web 开发的方式。

WML 通过无线访问协议(Wireless Access Protocol,WAP)传输,这和 HTML 通过 HTTP 传输很相似。WAPWML 在临时对话中通常可以相互转换:手机说明书总是会夸耀该手机带有 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

  1. <% response.setContentType("text/vnd.wap.wml") %>
  2. <?xml version="1.0"?>
  3. <!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
  4.    "http://www.phone.com/dtd/wml11.dtd" >
  5. <wml>
  6.   <card id="f1" title="Flight 1">
  7.     <p mode="wrap">From: DEN</p>
  8.     <p mode="wrap">To: ORD</p>
  9.     <p mode="wrap">UAL 1234</p>
  10.     <p mode="wrap">Jun 30, 10:30am</p>
  11.     <p>
  12.       <anchor>Next<go href="#f2"/></anchor>
  13.     </p>  
  14.   </card>
  15.   <card id="f2" title="Flight 2">
  16.     <p mode="wrap">From: ORD</p>
  17.     <p mode="wrap">To: DEN</p>
  18.     <p mode="wrap">UAL 9876</p>
  19.     <p mode="wrap">Jul 02, 1:15pm</p>
  20.     <p>
  21.       <anchor>Previous<go href="#f1"/></anchor>
  22.     </p>  
  23.   </card>
  24. </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

  1. <% response.setContentType("text/vnd.wap.wml") %>
  2. <%
  3. def flightList = []
  4. flightList << [iata1:"DEN", iata2:"ORD"]
  5. flightList << [iata1:"ORD", iata2:"DEN"]
  6. %>
  7. <?xml version="1.0"?>
  8. <!DOCTYPE wml PUBLIC "-//PHONE.COM//DTD WML 1.1//EN"
  9.    "http://www.phone.com/dtd/wml11.dtd" >
  10. <wml>
  11.   <g:each in="${flightList}" var="${flight}" status="i">
  12.     <card id="f${i}" title="Flight ${i}">
  13.       <p mode="wrap">From: ${flight.iata1}</p>
  14.       <p mode="wrap">To: ${flight.iata2}</p>      
  15.       <g:if test="${flightList.size() > i+1}">
  16.         <p>
  17.           <anchor>Next<go href="#f${i}"/></anchor>
  18.         </p>  
  19.       </g:if>  
  20.     </card>
  21.   </g:each>  
  22. </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,且支持分数值。也可以输入显式的 widthheight 值,上限为 10,000 像素(如清单 10 所示):


清单 10. 为 viewport 设置 widthheight

                
<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:scott@aboutgroovy.com">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

  1. <h2>Request Headers</h2>
  2. <table border="1">
  3.   <tr>
  4.     <th>Header</th>
  5.     <th>Value</th>
  6.   </tr>
  7.   
  8.   <g:each in="${request.headerNames}" var="${name}">
  9.     <tr>
  10.       <td>${name}</td>
  11.       <td>${request.getHeader(name)}</td>
  12.     </tr>
  13.   </g:each>
  14. </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 的带来的乐趣了。

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值