首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用 JSON 和 Ajax 实现异步 Grails(1)

用 JSON 和 Ajax 实现异步 Grails(1)

为了进行演示,您将组建一个旅行计划页面,在该页面中,用户可以输入出发地机场和目的地机场。当机场显示在一个 Google Map 上时,用户可通过一个链接搜索目的地机场附近的宾馆。图 1 显示了这个页面:
图 1. 旅行计划页面您可以在 1 个 GSP 文件和 3 个控制器中,用大约 150 行代码实现所有这些功能。
Ajax 和 JSON 简史关于本系列Grails 是一种新型 Web 开发框架,它将常见的 Spring 和 Hibernate 等 Java™ 技术与当前流行的约定优于配置等实践相结合。Grails 是用 Groovy 编写的,它不仅可以与遗留的 Java 代码无缝集成,而且提供脚本语言的灵活性和动态性。学习完 Grails 之后,您将彻底改变看待 Web 开发的方式。

在 20 世纪 90 年代中期 Web 首次流行起来的时候,浏览器只允许粗粒度的 HTTP 请求。单击一个超级链接或一个表单提交按钮,就会导致整个页面被清除,并且被新的结果替代。这对于以页面为中心的导航来说本无大碍,但是页面上单个的组件却无法独立地更新。
1999 年,Microsoft® 在 Internet Explorer 5.0 中引入了 XMLHTTP 对象。这个新对象使开发人员可以发出 “微” HTTP 请求,保持周围的 HTML 页面不受影响。虽然这个特性不是基于 World Wide Web Consortium(W3C)标准,但 Mozilla 小组已经意识到它的潜力,并在 2002 年的 Mozilla 1.0 发行版中增加了一个 XMLHttpRequest(XHR)对象。从那以后,它就成了一个事实上的标准,每个主流 Web 浏览器都提供这样的对象。
Ajax 资源中心请访问 ,这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。

2005 年,Google Maps 终于发布。对异步 HTTP 请求的广泛使用使得它与当时的其他 Web 映射站点形成鲜明的对比。在浏览 Google Map 时,不再是单击一下,然后等待整个页面重新装载,而是可以用鼠标顺畅地滚动地图。Jesse James Garrett 在一个 blog 帖子中使用简单易记的 Ajax 描述在 Google Maps 中使用的各种技术,从那以后这个名称就一直沿用下来(参见 )。
近年来,Ajax 已成为用于 “Web 2.0” 应用程序的一个涵盖性术语,而不是一组特定的技术。请求通常是异步的,并且以 JavaScript 发出,但是响应并非总是 XML。在基于浏览器的应用程序的开发中,XML 缺乏本地的、易于使用的 JavaScript 解析器。当然,也可以使用 JavaScript DOM API 解析 XML,但是对初学者而言这并不容易。因此,Ajax Web 服务常常返回纯文本、HTML 片段或 JSON 格式的结果。
2006 年 7 月,Douglas Crockford 将描述 JSON 的 RFC 4627 提交到 Internet Engineering Task Force(IETF)。当年年末,Yahoo! 和 Google 等主要服务提供商将 JSON 输出作为 XML 的替代品(请参阅 )。(在本文的后面您将使用 Yahoo! 的 JSON Web 服务)。
JSON 的优点在 Web 开发方面,JSON 与 XML 相比主要有两个优点。首先,它更加简洁。JSON 对象是一系列以逗号分隔的 name:value 对,最外面有一对花括号。相反,XML 则使用重复的开始和结束标记包装数据值。因此,与相应的 JSON 相比,这样便产生了两倍的元数据开销,所以 Crockford 将 JSON 趣称为 “XML 的无脂替代品”(请参阅 )。当处理 Web 开发的 “细管道” 时,每次减少一些字节都可以带来实在的性能好处。
清单 1 显示了 JSON 和 XML 如何组织相同的信息:
清单 1. 比较 JSON 和 XML
1
2
3
4
5
6
7
{"city":"Denver", "state":"CO", "country":"US"}

<result>
  <city>Denver</city>
  <state>CO</state>
  <country>US</country>
</result>




对于 Groovy 程序员来说,JSON 对象看上去应该更熟悉:如果将花括号换成方括号的话,在 Groovy 中就是定义一个 HashMap。说起方括号,定义 JSON 对象数组的方式与定义 Groovy 对象的方式是完全一样的。一个 JSON 数组就是一个以逗号分隔的系列,外面以方括号包围,如清单 2 所示:
清单 2. 一个 JSON 对象列表
1
2
[{"city":"Denver", "state":"CO", "country":"US"},
{"city":"Chicago", "state":"IL", "country":"US"}]




当解析和处理 JSON 时,就突出了 JSON 的第二个优点。将 JSON 装载到内存只需一个 eval() 调用。装载后,就可以通过名称直接访问任何字段,如清单 3 所示:
清单 3. 装载 JSON 和调用字段
1
2
3
var json = '{"city":"Denver", state:"CO", country:"US"}'
var result = eval( '(' + json + ')' )
alert(result.city)




Groovy 的 XmlSlurper 也允许直接访问 XML 元素。(您已经在 “” 中使用过 XmlSlurper)。如果现代 Web 浏览器支持客户端 Groovy,我就不会对 JSON 这么感兴趣。不幸的是,Groovy 完全是一个服务器端解决方案。就客户机-服务器开发而言,JavaScript 是唯一选项。所以我选择在服务器端使用 Groovy 处理 XML,而在客户端则使用 JavaScript 处理 JSON。在这两种情况下,我都可以最轻松地得到数据。
至此,您已粗略地了解了 JSON,接下来可以通过 Grails 应用程序生成 JSON。
在 Grails 控制器中呈现 JSON在 “” 中,您首先从一个 Grails 控制器返回 JSON。清单 4 中的闭包类似于您当时创建的闭包。不同之处在于,这个闭包是通过一个友好的 Uniform Resource Identifier(URI)访问的,这已在 “” 中讨论。它还使用您在 “” 中首次见到的 Elvis 操作符。
将一个名为 iata 的闭包添加到您在 “” 中创建的 grails-app/controllers/AirportMappingController.groovy 类中,记得在文件顶部导入 grails.converters 包,如清单 4 所示:
清单 4. 将 Groovy 对象转换成 JSON
1
2
3
4
5
6
7
8
9
10
11
import grails.converters.*
class AirportMappingController {
    def iata = {
      def iata = params.id?.toUpperCase() ?: "NO IATA"
      def airport = AirportMapping.findByIata(iata)
      if(!airport){
        airport = new AirportMapping(iata:iata, name:"Not found")
      }
      render airport as JSON
    }
}




在浏览器中输入 http://localhost:9090/trip/airportMapping/iata/den 进行测试。应该可以看到清单 5 中所示的 JSON 结果:
清单 5. JSON 中的一个有效的 AirportMapping 对象
1
2
3
4
5
6
7
{"id":328,
"class":"AirportMapping",
"iata":"DEN",
"lat":"39.858409881591797",
"lng":"-104.666999816894531",
"name":"Denver International",
"state":"CO"}




也可以输入 http://localhost:9090/trip/airportMapping/iata 和 http://localhost:9090/trip/airportMapping/iata/foo,以确认是否返回 “Not Found”。清单 6 显示了返回的无效的 JSON 对象:
清单 6. JSON 中的一个无效的 AirportMapping 对象
1
2
3
4
5
6
7
{"id":null,
"class":"AirportMapping",
"iata":"FOO",
"lat":null,
"lng":null,
"name":"Not found",
"state":null}




当然,这样的 “考验” 不能替代真正的测试。
返回列表