当前位置: 代码迷 >> Web前端 >> DWR与EXT调整
  详细解决方案

DWR与EXT调整

热度:109   发布时间:2012-10-28 09:54:44.0
DWR与EXT整合
据不完全统计,从事Ajax开发的Java程序员有一大半都使用DWR。我们下面来介绍一下如何在EXT中使用DWR与后台交互。

因为DWR在前台的表现形式和普通的JavaScript完全一样,所以我们不需要特地去做些什么,直接使用EXT调用DWR生成的JavaScript函数即可。以Grid为例,比如现在我们要显示一个通讯录的信息,后台记录的数据有:id、name、sex、email、tel、addTime和descn。编写对应的POJO,代码如下所示。

public class Info {

    long id;

    String name;

    int sex;

    String email;

    String tel;

    Date addTime;

    String descn;

}

然后编写操作POJO的manager类,代码如下所示。

public class InfoManager {

    private List infoList = new ArrayList();

    public List getResult() {

        return infoList;

    }

}

代码部分有些删减,我们只保留了其中的关键部分,就这样把这两个类配置到dwr.xml中,让前台可以对这些类进行调用。

下面是EXT与DWR交互的关键部分,我们要对JavaScript部分做如下修改,如代码清单10-7所示。

代码清单10-7 使用EXT调用DWR

var cm = new Ext.grid.ColumnModel([

    {header:'编号',dataIndex:'id'},

    {header:'名称',dataIndex:'name'},

    {header:'性别',dataIndex:'sex'},

    {header:'邮箱',dataIndex:'email'},

    {header:'电话',dataIndex:'tel'},

    {header:'添加时间',dataIndex:'addTime'},

    {header:'备注',dataIndex:'descn'}

]);

var store = new Ext.data.JsonStore({

    fields: ["id","name","sex",'email','tel','addTime','descn']

});

// 调用DWR取得数据

infoManager.getResult(function(data) {

    store.loadData(data);

});

var grid = new Ext.grid.GridPanel({

    renderTo: 'grid',

    store: store,

    cm: cm

});

注意,执行infoManager.getResult()函数时,DWR就会使用Ajax去后台取数据了,操作成功后调用我们定义的匿名回调函数。在这里我们只做一件事,那就是将返回的data直接注入到ds中。

DWR返回的data可以被JsonStore直接读取,我们需要设置对应的fields参数,以告诉JsonReader需要哪些属性。

在这里,EXT和DWR两者之间没有任何关系,将它们任何一方替换掉都可以。实际上它们只是在一起运行,并没有整合。我们给出的这个示例也是说明了一种松耦合的可能性,实际操作中完全可以使用这种方式。

要结合使用EXT和DWR,不需要对后台程序进行任何修改,可以直接让前后台数据进行交互。不过还要考虑很多细节,比如Grid分页、刷新、排序、搜索等常见的操作。EXT的官方网站上已经有人放上了DWRProxy,借助它可以让DWR和 EXT连接得更加紧密。不过,需要在后台添加DWRProxy所需要的Java类,这可能不是最好的解决方案。但我们相信,通过对它的内在实现的讨论,我们可以有更多的选择和想象空间。

注意     这个DWRProxy.js一定要放在ext-base.js和ext-all.js后面,否则会出错。

我们现在就用DWRProxy来实现一个分页的示例。除了准备好插件DWRProxy.js 外,还要在后台准备一个专门用于分页的封装类。因为不仅要告诉前台显示哪些数据,还要告诉前台一共有多少条数据。现在我们来重点看一下 ListRange.java,如下面的代码所示。

public class ListRange {

    Object[] data;

    int totalSize;

}

其实ListRange非常简单,只有两个属性:提供数据的data和提供数据总量的totalSize。再看一下InfoManager.java,为了实现分页,我们专门编写了一个getItems方法,代码如下所示。

public ListRange getItems(Map conditions) {

    int start = 0;

    int pageSize = 10;

    int pageNo = (start / pageSize) + 1;

    try {

        start = Integer.parseInt(conditions.get("start").toString());

        pageSize = Integer.parseInt(conditions.get("limit").toString());

        pageNo = (start / pageSize) + 1;

    } catch (Exception ex) {

        ex.printStackTrace();

    }

    List list = infoList.subList(start, start + pageSize);

    return new ListRange(list.toArray(), infoList.size());

}

getItems()的参数是Map,我们从中获得需要的参数,比如start和 limit。不过HTTP里的参数都是字符串,而我们需要的是数字,所以要对类型进行相应的转换。根据start和limit两个属性从全部数据中截取一部分,放进新建的ListRange中,然后把生成的ListRange返回给前台,于是一切都解决了。

重头戏要上演了,我们就要使用传说中的Ext.data.DWRProxy了,还有Ext.data.List- RangeReader。通过这两个扩展,EXT完全可以支持DWR的数据传输协议。实际上,这正是EXT要把数据和显示分离设计的原因,这样你只需要添加自定义的proxy和reader,不需要修改EXT的其他部分,就可以实现从特定途径获取数据的功能。后台还是DWR,所以至少在Grid部分,我们可以很好地使用它们的结合,主要代码如下所示。

var store = new Ext.data.Store({

    proxy: new Ext.data.DWRProxy(infoManager.getItems, true),

    reader: new Ext.data.ListRangeReader({

        totalProperty: 'totalSize',

        root: 'data',

        id: 'id'

    }, info),

    remoteSort: true

});

与我们上面说的一样,我们修改了proxy,也修改了reader,其他地方都不需要进行修改,Grid已经可以正常运行了。需要提醒的是DWRProxy的用法,其中包括两个参数:第一个是dwr- Call,它把一个DWR函数放进去,它对应的是后台的getItems方法;第二个参数是paging- AndSort,这个参数控制DWR是否需要分页和排序。

ListRangeReader部分与后台的ListRange.java对应。 totalProperty表示后台数据总数,我们通过它指定从ListRange中读取totalSize属性的值来作为后台数据总数。还需要指定 root参数,以告诉它在ListRange中的数据变量的名称为data,随后DWRProxy会从ListRange中的data属性中获取数据并显示到页面上。如果不想使用我们提供的ListRange.java类,也可以自己创建一个类,只要把totalProperty和data两个属性与之对应即可。

我们现在来尝试一下让树形也支持DWR。有了前面的基础,整合DWR和tree就更简单了。在后台,我们需要树形节点对应的TreeNode.java。目前,只要id、text和leaf三项就可以了。

public class TreeNode {

    String id;

    String text;

    boolean leaf;

}

id是节点的唯一标记,知道了id就能知道是在触发哪个节点了。text是显示的标题,leaf比较重要,它用来标记这个节点是不是叶子。

这里还是用异步树,TreeNodeManager.java里的getTree()方法将获得一个节点的id作为参数,然后返回这个节点下的所有子节点。我们这里没有限制生成的树形的深度,你可以根据自己的需要进行设置。 TreeNodeManager.java的代码如下所示。

public List getTree(String id) {

    List list = new ArrayList();

    String seed1 = id + 1;

    String seed2 = id + 2;

    String seed3 = id + 3;

    list.add(new TreeNode(seed1, "" + seed1, false));

    list.add(new TreeNode(seed2, "" + seed2, false));

    list.add(new TreeNode(seed3, "" + seed3, true));

    return list;

}

上面的代码并不复杂,它实现的效果与在Java中使用List或数组是相同的,因为返回给前台的数据都是JSON格式的。前台使用JavaScript处理返回信息的部分更简单,先引入DWRTree- Loader.js,然后把TreeLoader替换成DWRTreeLoder即可,如下面的代码所示。

var tree = new Ext.tree.TreePanel('tree', {

    loader: new Ext.tree.DWRTreeLoader({dataUrl: treeNodeManager.getTree})

});

参数依然是dataUrl,它的值treeNodeManager.getTree代表的是一个DWR函数,我们不需要对它进行深入研究,它的内部会自动处理数据之间的对应关系。DWR有时真的很方便。

DWRProxy既然可以用在Ext.data.Store中,那么它也可以为ComboBox服务,如代码清单10-8所示。

代码清单10-8 DWRProxy与ComboBox整合

var info = Ext.data.Record.create([

    {name: 'id', type: 'int'},

    {name: 'name', type: 'string'}

]);

var store = new Ext.data.Store({

    proxy: new Ext.data.DWRProxy(infoManager.getItems, true),

    reader: new Ext.data.ListRangeReader({

        totalProperty: 'totalSize',

        root: 'data',

        id: 'id'

    }, info)

});

var combo = new Ext.form.ComboBox({

    store: store,

    displayField: 'name',

    valueField: 'id',

    triggerAction: 'all',

    typeAhead: true,

    mode: 'remote',

    emptyText: '请选择',

    selectOnFocus: true

});

combo.render('combo');

我们既可以用mode:'remote'和triggerAction:'all'在第一次选择时读取数据,也可以设置mode:'local',然后手工操作store.load()并读取数据。

DWR要比Json-lib方便得多,而且DWR返回的数据可以直接作为JSON使用,使用Json-lib时还要面对无休无止的循环引用。

这次的示例稍微复杂一些,因为包括依赖jar包、class、XML和JSP,所以示例单独放在10.store/dwr2/下,请将它们复制到tomcat的webapps下,然后再使用浏览器访问。
  相关解决方案