扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
另一方面,现在我需要为每个不同视图创建一个新 JSP,而不能仅仅把需要的对象图组织起来并序列化它。从设计的角度来说,许多人可能会有争议,认为这无论如何是件好事,因为这意味着正式地考虑服务器要生成的文档类型。而且,因为我现在要处理通用的模板环境,而不是特定于 XML 的 API,所以确保标记匹配、元素和属性的顺序正确以及 XML 实体(例如 < 或 &)正确转义就成了我的责任。JSP 的核心 out 标记使后面这项工作变得很容易,但是不是所有的模板技术都提供了这样的机制。最后,没有方便的途径可以在服务器端根据方案检验生成的 XML 文档的正确性,但这毕竟不是要在生产环境中做的事,可以方便地在开发期间处理它。
不用 XML 的响应数据
迄今为止,我介绍的所有技术都用 XML 文档的形式生成服务器响应。但是,XML 有一些问题。其中一个就是延迟。浏览器不能立即解析 XML 文档并生成 DOM 模型,所以这会降低某些 Ajax 组件需要的“迅捷”感,特别是在较慢的机器上解析大型文档的时候更是如此。“现场搜索”就是一个示例,在这种搜索中,当用户输入搜索术语时,就会从服务器提取搜索结果并显示给用户。对于现场搜索组件来说,迅速地响应输入是非常重要的,但是同时它还需要迅速而持续地解析服务器的响应。
延迟是一个重要的考虑因素,但是避免使用 XML 的最大原因是差劲的客户端 DOM API。清单 5 显示了使用跨浏览器兼容的方式通过 DOM 得到某个值的时候,通常不得不面对的困难。
清单 5. 在 JavaScript 中导航 XML 响应文档
// Find name of first item in customer's last order
var orderHistoryDoc = req.responseXML;
var orders = orderHistoryDoc.getElementsByTagName("order");
var lastOrder = orders[orders.length - 1];
var firstItem = lastOrder.getElementsByTagName("item")[0];
var itemNameElement = firstItem.firstChild;
var itemNameText = itemNameElement.firstChild.data;
当元素中间存在空白时,情况就变得更加复杂,因为每个元素的 firstChild 经常是个空白文本节点。现在有 JavaScript 库可以缓解处理 XML 文档的麻烦。这些库包括 Sarissa 和 Google-ajaXSLT,这两个库都把 XPath 功能添加到了大多数浏览器中。
但是,想想替代方案还是值得的。除了 responseXML 之外,XMLHttpRequest 对象还提供了名为 responseText 的属性,这个属性只是以字符串的方式提供服务器的响应体。
responseText 属性
当服务器需要向客户机发送非常简单的值时,responseText 特别方便,它可以避免 XML 导致的带宽支出和处理支出。例如,简单的 true/false 响应可以由服务器以纯文本方式返回,可以是逗号分隔的简单的名称或数字列表。但是,一般来说,最好不要在同一个应用程序中把 XML 响应和纯文本响应混合使用;保持单一数据格式可以让代码抽象和重用更加简单。
responseText 与 XML 响应数据结合时也会有用。在只需要从响应文档中提取单一值的场景中,“欺骗性”地把 XML 当作文本字符串,而不把它当作结构化的文档对待,会更方便。例如,清单 6 显示了如何用正则表达式从顾客的订单历史中提取第一笔订单的日期。不过,这实际是种花招,一般不应当依赖 XML 文档的词汇表达。
清单 6. 用正则表达式处理 XMLHttpRequest 的 responseText 对象
var orderHistoryText = req.responseText;
var matches = orderHistoryText.match(/<date>(.*?)<\/date>/);
var date = matches[1];
在某些情况下,采用即时方式使用 responseText 会比较方便。但是,理想情况下,应当有种途径,可以用一种能够让 JavaScript 轻松导航、却没有 XML 处理支出的格式表示复杂的结构化数据。幸运的是,确实存在这样一种格式。
JavaScript 对象标注
实际上,JavaScript 对象的大部分都由联合数组、数字索引数组、字符串、数字或者这些类型的嵌套组合而成。因为所有类型都可以用 JavaScript 直接声明,所以可以在一条语句中静态地定义对象图。清单 7 使用 JSON 语法声明了一个对象,并演示了如何访问这个对象。大括号表示联合数组(即对象),它的键 -值组合由逗号分隔。方括号表示数字索引数组。
清单 7. 用 JSON 在 JavaScript 中直接声明一个简单对象
var band = {
name: "The Beatles",
members: [
{
name: "John",
instruments: ["Vocals","Guitar","Piano"]
},
{
name: "Paul",
instruments: ["Vocals","Bass","Piano","Guitar"]
},
{
name: "George",
instruments: ["Guitar","Vocals"]
},
{
name: "Ringo",
instruments: ["Drums","Vocals"]
}
]
};
// Interrogate the band object
var musician = band.members[3];
alert( musician.name
+ " played " + musician.instruments[0]
+ " with " + band.name );
既然 JSON 是一个有趣的语言特性,那么它对 Ajax 有什么意义呢?妙处在于可以用 JSON 在 Ajax 服务器响应中通过网络发送 JavaScript 对象图。这意味着在客户端可以避免使用笨拙的 DOM API 对 XML 进行导航 —— 只需要分析 JSON 响应,就会立即得到可以访问的 JavaScript 对象图。但是,首先需要把 JavaBean 变成 JSON。
从 Java 类产生 JSON
不同 XML 生成技术所具有的优缺点也适用于 JSON 的产生。而且可以证明,存在需要再次使用表示模板技术的情况。但是,使用 JSON 在理念上更接近于在应用层之间传递序列化的对象,而不是创建应用程序状态的视图。我将介绍如何用 org.json 这个 Java API 在 Java 类上创建 toJSONObject() 方法。然后,就可以把 JSONObject 简单地序列化成 JSON。清单 8 反映了 清单 1 讨论的 XML,显示了 Order 类的 toJSONObject() 实现。
清单 8. Order 类的 toJSONObject() 方法实现
public JSONObject toJSONObject() {
JSONObject json = new JSONObject();
json.put("id",id);
json.put("cost",getFormattedCost());
json.put("date",date);
JSONArray jsonItems = new JSONArray();
for (Iterator<Item> iter =
items.iterator() ; iter.hasNext() ; ) {
jsonItems.put(iter.next().toJSONObject());
}
json.put("items",jsonItems);
return json;
}
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者