扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
如果对远程方法的工作感到满意,就可以用 DWR 生成的 JavaScript 存根从客户端代码调用服务器端对象。
调用远程对象
远程 Java 对象方法和对应的 JavaScript 存根函数之间的映射很简单。通用的形式是 JavaScriptName.methodName(methodParams ..., callBack),其中 JavaScriptName 是 creator 的 javascript 属性指定的名称,methodParams 代表 Java 方法的 n 个参数,callback 是要用 Java 方法的返回值调用的 JavaScript 函数。如果熟悉 Ajax,可以看出这个回调机制是 XMLHttpRequest 异步性的常用方式。
在示例场景中,我用清单 3 中的 JavaScript 函数执行搜索,并用搜索结果更新用户界面。这个清单还使用来自 DWR 的 util.js 的便捷函数。要特别说明的是名为 $() 的 JavaScript 函数,可以把它当作 document.getElementById() 的加速版。录入它当然更容易。如果您使用过 JavaScript 原型库,应当熟悉这个函数。
清单 3. 从客户机调用远程的 findItems()
/*
* Handles submission of the search form
*/
function searchFormSubmitHandler() {
// Obtain the search expression from the search field
var searchexp = $("searchbox").value;
// Call remoted DAO method, and specify callback function
catalog.findItems(searchexp, displayItems);
// Return false to suppress form submission
return false;
}
/*
* Displays a list of catalog items
*/
function displayItems(items) {
// Remove the currently displayed search results
DWRUtil.removeAllRows("items");
if (items.length == 0) {
alert("No matching products found");
$("catalog").style.visibility = "hidden";
} else {
DWRUtil.addRows("items",items,cellFunctions);
$("catalog").style.visibility = "visible";
}
}
在上面的 searchFormSubmitHandler() 函数中,我们感兴趣的代码当然是 catalog.findItems(searchexp, displayItems);。这一行代码就是通过网络向 DWR servlet 发送 XMLHttpRequest 并用远程对象的响应调用 displayItems() 函数所需要的全部内容。
displayItems() 回调本身是由一个 Item 数组表示调用的。这个数组传递给 DWRUtil.addRows() 便捷函数,同时还有要填充的表的 ID 和一个函数数组。表中每行有多少单元格,这个数组中就有多少个函数。按照顺序使用来自数组的 Item 逐个调用每个函数,并用返回的内容填充对应的单元格。
在这个示例中,我想让商品表中的每一行都显示商品的名称、说明和价格,并在最后一列显示商品的 Add to Cart 按钮。清单 4 显示了实现这一功能的单元格函数数组:
清单 4. 填充商品表的单元格函数数组
/*
* Array of functions to populate a row of the items table
* using DWRUtil's addRows function
*/
var cellFunctions = [
function(item) { return item.name; },
function(item) { return item.description; },
function(item) { return item.formattedPrice; },
function(item) {
var btn = document.createElement("button");
btn.innerHTML = "Add to cart";
btn.itemId = item.id;
btn.onclick = addToCartButtonHandler;
return btn;
}
];
前三个函数只是返回 dwr.xml 中 Item 的 convertor 包含的字段内容。最后一个函数创建一个按钮,把 Item 的 ID 赋给它,并指定在点击按钮时应当调用名为 addToCartButtonHandler 的函数。这个函数是第二个用例的入口点:向购物车中添加 Item。
实现购物车
用户购物车的 Java 表示基于 Map。当 Item 添加到购物车中时,Item 本身作为键被插入 Map。 Map 中对应的值是一个 Integer,代表购物车中指定 Item 的数量。所以 Cart.java 有一个字段 contents,声明为 Map<Item,Integer>。
使用复杂类型作为哈希键给 DWR 带来一个问题 —— 在 JavaScript 中,数组的键必须是标量的。所以,DWR 无法转换 contents Map。但是,对于购物车用户界面来说,用户需要查看的只是每个商品的名称和数量。所以我向 Cart 添加了一个名为 getSimpleContents() 的方法,它接受 contents Map 并根据它构建一个简化的 Map<String,Integer>,只代表每个 Item 的名称和数量。这个用字符串作为键的 map 表示可以由 DWR 的转换器转换成 JavaScript。
客户对 Cart 感兴趣的其他字段是 totalPrice,它代表购物车中所有商品的金额汇总。使用 Item,我还提供了一个合成的成员叫作 formattedTotalPrice,它是金额汇总的格式化好的 String 表示。
DWR 的安全性
DWR 设计时就考虑了安全性。使用 dwr.xml 明确地列出那些想做远程处理的类和方法,可以避免意外地把那些可能被恶意利用的功能公开出去。除此之外,使用调试测试模式,可以容易地审计所有公开到 Web 上的类和方法。
DWR 也支持基于角色的安全性。通过 bean 的 creator 配置,可以指定用户访问特定 bean 所必须属于的 J2EE 角色。通过部署多个 URL 受保护的 DWRServlet 实例,每个实例都有自己的 dwr.xml 配置文件,也可以提供拥有不同远程功能的用户集。
转换购物车
为了不让客户代码对 Cart 做两个调用(一个获得内容,一个获得总价),我想把这些数据一次全都发给客户。为了做到这一点,我添加了一个看起来有点儿怪的方法,如清单 5 所示:
清单 5. Cart.getCart() 方法
/**
* Returns the cart itself - for DWR
* @return the cart
*/
public Cart getCart() {
return this;
}
虽然这个方法在普通的 Java 代码中可能完全是多余的(因为在调用这个方法时,已经有对 Cart 的引用),但它允许 DWR 客户让 Cart 把自己序列化成 JavaScript。
除了 getCart(),需要远程化的另一个方法是 addItemToCart()。这个方法接受目录 Item 的 ID 的 String 表示,把这个商品添加到 Cart 中并更新总价。方法还返回 Cart,这样客户代码在一个操作中就能更新 Cart 的内容并接收购物车的新状态。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者