InfoQ

InfoQ

文章

我的书签

登录注册 以永久保存书签。

该内容已经被标记书签!

标记书签错误,请重试!

你的第一杯Web 2.0 —— 快速浏览jQuery、Spring MVC和XStream/Jettison

作者 Joel Confino 译者 张凯峰 发布于 2008年12月12日

领域
架构 & 设计,
企业架构,
语言 & 开发
主题
Java ,
Web 2.0 ,
JavaScript
标签
XStream ,
jQuery

不再有页面刷新:使用jQuery

在我参与创建的一些Web网站应用中,一直存在有对用户理所当然的抱歉:“哦,对不起,我不得不让你经受一些不必要的页面刷新。”哈,这就是我在今年年初听说jQuery后,我的脑子里一下闪过的念头。

jQuery是个强大而非侵入式的JavaScript库,但它的名字起得很差劲。它的简洁而高可读性的语法再次激发了我编写JavaScript代码的兴趣。它的非侵入性能让它只需要对既有代码做小小的修改,就能很容易为web应用添加一些丰富的功能——比如后台表单提交。当你工作在一个很大的代码库,或者扩展性的重构无法取得成效时,非侵入的特性显得尤其重要。我的老板不会给我四周的时间推倒重来,为一个已经存在的网站添加一些视觉效果。但我也许可以有四个小时的时间,而这对jQuery来说足够了。

作为一个简单的例子,我们假设有一个汽车搜索功能,它会基于一个交通工具型号来返回结果。向文本框输入文本,点击提交,然后显示结果。JSP看起来会是这样:

在用户输入名称并点击提交后,在页面刷新时整个屏幕会变白,然后就会显示出结果来。这不是一个好的用户体验。现在,让我们用jQuery来改善一下用户的体验,只刷新页面中那部分的确需要改变的部分。对这个既有页面所做的修改是:

  1. 把搜索表单和搜索结果分成两个单独的JSP页面,这样结果也可以独立的显示,而不需要重新渲染搜索的表单。
  2. 在搜索表单JSP上添加一个占位符,来存放搜索的结果。
  3. 添加一行jQuery代码,来在后台使用AJAX提交搜索表单内容,并把结果存放在占位符 中。

修改后的代码是这样的:



当用户输入名称并点击了提交时,只有搜索结果的会刷新。这样用户体验就得到了改善,而我们也不需要编写太多的JavaScript代码。让我们来深入一点研究下这段jQuery脚本:

这段代码的意思是:

第2行——“当页面加载完成时……”

第3行——“找到一个id为searchForm的表单,并让它变成具备AJAX功能的表单(在后台提交)”

第4行——“使用POST方法而不是GET”

第5行——“把搜索的结果放在一个id为searchResults的DIV中”

这几行jQuery代码以$()开始,并总是会选择某个元素来进行操作,比如“document”或者“#searchForm”。jQuery就像是个装饰器,可以让你为元素添加各种各样有趣的行为,比如具备AJAX提交功能的表单、可视化效果、拖拽等等。

这个例子演示出几行代码所包含的众多功能,也表达了为什么我会喜欢jQuery:使用装饰器方法来增强既有的web应用,是非常理想而完美的。不需要重写既有的HTML,你使用jQuery就可以添加新的行为。

使用Spring MVC和XStream/Jettison返回数据而不是HTML

第一个例子中,jQuery是用在了客户端,而在服务器端没有什么显著的变化。我们仍然保留基本的流程,用户在浏览器上点击某个元素,创建一个服务器请求,然后返回HTML内容。当如果服务器端能返回JSON或者XML格式的数据,而不是HTML,会怎样呢?

返回数据而不是可以展现的HTML,这可以让客户端缓存结果,从而减少服务器请求的次数。数据本身要比HTML简洁很多——这样也减小了返回结果的尺寸。请看下面的这个例子:

在标准的流程中,三次用户与浏览器的交互会带来三次服务器请求。现在让我们看看一个优化过后,服务器只返回数据而不是HTML的流程:

在优化后的流程中,三次用户交互只会产生一次服务器请求。

还有许多潜在的可以由服务器返回的数据格式。具体选择哪种,可以根据情况而定。下面是一些选项以及选择的原因:

服务器请求格式 何时使用 使用频率
完整HTML页面 初始页面加载
HTML片段 在服务器端展现更加容易而且有必要。比如使用流行的标签库来显示一个table。
JSONB

{
  "car": {
      "id": "5",
      "make": "Acura",
      "model": "MDX"
  }
}
在大多数服务器响应中都可以使用的数据格式。简洁,并且很容易跟JavaScript配合工作。
XML


     Acura
     MDX

复杂的无法轻松使用JSON表示的数据。XML的结果包括元素和属性,而JSON只包含元素。

让我们来看一个服务器返回JSON数据到浏览器的例子。我们把原来的汽车型号搜索页替换成一个新的页面,它包含一个制造商(make)和型号(model)的下拉列表。当用户选择制造商时,对应那个制造商的所有模型就会自动更新。如果用户选择了一个型号,下面就会显示一张列满该可用型号年代的表格。

由服务器端开始,我们会看到我们如何使用Spring MVC以及XStream和Jettison来创建JSON数据。首先我们会构建一个Spring MVC控制器:

第1行——@Controller注解告诉Spring MVC把这个类用作一个控制器。

第4行——@RequestMapping注解将请求URL映射到处理方法上。

第6行——创建ModelAndView对象,其中view名称为carselector,它将会映射到carselector.jsp。

第7行——使用键值makeList将一个制造商(Make)列表添加到ModelAndView中。这个对象可以在JSP中通过${makeList}来取到。

第11行——再一次,@RequestMapping注解将请求URL映射到处理方法上。

第12行——@RequestParam将一个请求参数对应到一个方法参数上。

第13行——通过我写的叫做JsonView的JSON视图类来创建ModelAndView对象。Spring MVC让编写自定义视图类变得非常简单,而JsonView中就包含了XStream的逻辑。

第14行——使用JsonView所期望的键值将型号(Model)的列表添加到ModelAndView。

总的来说,控制器会响应两个URL,“carselector.html”和“models.html”。它通过一个标准的JSP视图针对 “carselector.html”返回一个HTML页面。让我们来看看JsonView类,它针对“models.html”返回JSON结果:

第4行——使用JettisonMappedXmlDriver来初始化XStream,从而输出JSON而不是XML。

第6行——Spring MVC视图类必须实现render()方法。

第9行——从model中取出之前由控制器创建的数据。

第11行——实际生成JSON(尽管方法叫做toXML)。

它就是那么简单。XStream库也包含一套注解,你可以将其放在你自己的域中或者传输对象上,来提示如何展现JSON,但一般来说这个库基本不需要什么配置。

现在服务器端就生成了JSON,但客户端如何使用它呢?针对这个问题,我们需要再次来利用jQuery。请记住,我们需要处理两个事件:从“制造商(make)”下拉列表中选择数值会更新“型号(model)”下拉列表中的数据。而选择型号(model)下拉列表中的数值会填充型号(model)年代表格中的数据。下面是用jQuery的ready方法来绑定事件处理方法:

“select[name^=make]”表达式看起来非常像CSS选择器,那是因为jQuery选择器是CSS选择器的一个超集(就好像CSS和 Regex有一个共同的孩子)。这些表达式相当强大,可以用来同时选择一个或多个对象。在这个例子中,表达式的意思是,“选择一个名字叫‘make’ 的select元素,并把loadModels函数绑定到它的change事件上”。每次用户从这个下拉列表中选择数值时,浏览器就会产生change事件,然后loadModels函数就会被调用。

让我们来看一下其中一个事件处理器:

第2行——getJSON方法将会执行AJAX请求,并期望从服务器返回JSON数据。它需要三个参数:请求的URL,任何请求参数,以及一个一旦得到服务器响应就被调用的回调函数。

第4行——回调函数是个闭包。JavaScript中的闭包类似于Java中的匿名内部类,它们可以很方便地作为回调函数来使用。要注意,这个函数期望从服务器返回的JSON数据是作为一个参数传入的。

第6行——在这一点上,我们需要了解一点我们使用到的JSON的结构。在这个简单的例子中,model数据的结构是:

第6行的代码意思是,“针对每一个型号(model)……”

第7和第8行——从每一个型号(model)构建一个元素

第10行——选择name=model的select元素,并使用刚刚构建的options来代替select元素的option列表。

只需少量的JavaScript代码,我们就可以做到:

  • 注册一个事件处理器
  • 异步获取JSON数据
  • 基于JSON数据更新下拉列表的选项

这就是其强大之处,也是我非常喜爱jQuery的原因之一。那关于缓存呢?你可以简单地在getJSON调用之前添加一个“if”语句来检查结果是否已经存在了。另外也有一个很好的叫做jCache的jQuery插件你可以使用。

结论

jQuery + Spring MVC + XStream/Jettison提供了一个很棒的快速开发web应用的全栈式框架,可以清晰地分离数据和表现层,为用户提供更加友好的体验,并潜在地提 升性能。还有其他什么高质量框架可以帮你做到这些吗?当然也许有,但我喜欢jQuery、Spring MVC和XStream/Jettison的组合,而且我认为它们都是各自领域的佼佼者。

你可以从这下载到完整的范例代码

关于作者

自从他的第一份Java工作——使用Java 1.02打印报表开始,Joel Confino就一直与Java技术为伍。过去的十年来,他曾经参与过的工作包括分布式系统、不同的网络架构以及JEE设计和编程。Confino也曾经 担任许多大型金融服务和药品公司的咨询,并帮助他们使用Java来扩展他们的业务,以及通过复杂的基于web的系统来连通他们的客户。他目前是 Chariot Solutions的Java架构师。

关于Chariot Solutions有限公司

Chariot Solutions是一家专注于使用Java和开源技术进行应用开发和系统集成的IT咨询公司。Chariot咨询师包括一些这个国家顶尖的软件架构师, 他们所有人都具备极其深厚的技术经验、行业领域知识以及对所从事事业的热爱。Chariot的咨询团队已经使公司在设计、开发、部署、集成、支持和关键任 务系统调优方面,成为各种类型公司最理想的合作伙伴。Chariot的网址是www.chariotsolutions.com

例子代码在这里 发表人 Lee Vincent 发表于
我的例子运行错误 发表人 0 eudemon 发表于
Re: 我的例子运行错误 发表人 谢 斌 发表于
Re: 我的例子运行错误 发表人 朱 志欧 发表于
策略上的转变 发表人 xuechen wang 发表于
例子太简单了,就是个 tutorial 发表人 Lai Jason 发表于
Re: 例子太简单了,就是个 tutorial 发表人 Lee Vincent 发表于
Re: 例子太简单了,就是个 tutorial 发表人 刘 申 发表于
  1. 返回顶部

    例子代码在这里

    发表人 Lee Vincent

  2. 返回顶部

    我的例子运行错误

    发表人 0 eudemon

    显示:输入框中的表达式没有解析成功
    Car Search (also check out Car Selector)

    Model Name: ${param.model}

  3. 返回顶部

    Re: 我的例子运行错误

    发表人 谢 斌

    感觉就像 2=1+1,呵呵。。

  4. 返回顶部

    策略上的转变

    发表人 xuechen wang

    这样一次要发送以前三次的内容,其实是一样的,不过有效降低了对服务器的交互,以流量换CPU使用率

  5. 返回顶部

    Re: 我的例子运行错误

    发表人 朱 志欧

    技术都提到了,就是简单了点。

  6. 返回顶部

    例子太简单了,就是个 tutorial

    发表人 Lai Jason

    不过 jQuery 确实非常赞,我几个 web 项目都用到了它。

    借助 jQuery 选择器的强大威力,完全可以写出非常干净的 HTML 代码。我个人对于像 onXXX="/* JS code here */" 这样的 HTML 感觉不是很舒服,一点是不太方便美工做设计,另外就是在 script 加载失败后,这样的代码也会让控制台出现错误。把 jQuery 引入之后,HTML 就可以成为纯粹的页面元素和结构的描述模板了。

  7. 返回顶部

    Re: 例子太简单了,就是个 tutorial

    发表人 Lee Vincent

    文章显示不全了

  8. 返回顶部

    Re: 例子太简单了,就是个 tutorial

    发表人 刘 申

    已经修改过了!

深度内容

应用云平台的可用性——从新浪SAE看云平台设计

云计算平台的可用性,相比传统互联网服务而言,更加复杂和困难,也更具有挑战性。本文借助新浪SAE云平台为读者讲述了云平台可用性的定义、如何打造高可用的平台,以及对云计算的用户提出了建议。

JVM定制改进 @ 淘宝

淘宝高度重视Java平台的健康发展,组建了一个团队专注于Java平台的底层部分的性能、功能与稳定性改进;工作主要基于OpenJDK中的HotSpot VM开展,其中一些通用的功能随后也会逐渐反馈给OpenJDK社区。希望能与使用Java平台开发应用的大家交流经验。
本次演讲视频录制于QCon杭州2011

"伤得起"的云计算应用——对云端应用之架构的思考

2011年4月21日至22日是值得云计算从业者纪念的日子。Amazon的IaaS服务出现故障,导致许多商业网站的服务中断,影响非常严重。作为云计算用户,我们需要思考的是,如何保证即便在云服务不可用的情况,我们的应用架构仍然能够屹立不倒?本文正是站在云计算用户的角度试图探讨这一问题。

让交付的速度跟上思考的速度

12人的技术团队,4组刀片服务器,每月20亿的访问量,每日1次准时部署,99.9%的可用性。这可能吗?当然。想知道如何做的吗?百姓网将与您分享他们在DevOps实践过程中的经验和技巧。
本次演讲视频录制于QCon杭州2011

架构之路——穿行在产品和业务之间

篱笆作为一家起源于社区的电子商务公司,反映到技术层面就是同时要面对产品和业务,以及经营战略的变化调整。如何在产品和业务的夹缝之间完成技术架构的抽象与平衡,寻找更有效的价值定位,这当中有些经验教训和个人感悟愿与众人分享。
本次演讲视频录制于QCon杭州2011

特性注入:成功三部曲

本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。

解析JDK 7的动态类型语言支持

随着JDK 7的发布,字节码指令集终于迎来了第一位新成员——invokedynamic指令。这条新增加的指令是JDK 7实现“动态类型语言(Dynamically Typed Language)”支持而进行的改进之一,也是为JDK 8可以顺利实现Lambda表达式做技术准备。在这篇文章中,我们将去了解JDK 7这项新特性的出现前因后果和它的意义。

Java Remoting远程服务(下)

随着互联网应用的发展,Java分布式远程服务技术受到越来越多的关注,本文将对各种相关实现以示例的形式逐一介绍,并总结其中的优缺点,使读者能够在技术选型时有所准备。这是文章的下篇。