不再有页面刷新:使用 jQuery
在我参与创建的一些 Web 网站应用中,一直存在有对用户理所当然的抱歉:“哦,对不起,我不得不让你经受一些不必要的页面刷新。”哈,这就是我在今年年初听说 jQuery 后,我的脑子里一下闪过的念头。
jQuery 是个强大而非侵入式的 JavaScript 库,但它的名字起得很差劲。它的简洁而高可读性的语法再次激发了我编写 JavaScript 代码的兴趣。它的非侵入性能让它只需要对既有代码做小小的修改,就能很容易为 web 应用添加一些丰富的功能——比如后台表单提交。当你工作在一个很大的代码库,或者扩展性的重构无法取得成效时,非侵入的特性显得尤其重要。我的老板不会给我四周的时间推倒重来,为一个已经存在的网站添加一些视觉效果。但我也许可以有四个小时的时间,而这对 jQuery 来说足够了。
作为一个简单的例子,我们假设有一个汽车搜索功能,它会基于一个交通工具型号来返回结果。向文本框输入文本,点击提交,然后显示结果。JSP 看起来会是这样:
在用户输入名称并点击提交后,在页面刷新时整个屏幕会变白,然后就会显示出结果来。这不是一个好的用户体验。现在,让我们用 jQuery 来改善一下用户的体验,只刷新页面中那部分的确需要改变的部分。对这个既有页面所做的修改是:
- 把搜索表单和搜索结果分成两个单独的 JSP 页面,这样结果也可以独立的显示,而不需要重新渲染搜索的表单。
- 在搜索表单 JSP 上添加一个占位符,来存放搜索的结果。
- 添加一行 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 。
评论