Dorado 9 : 09. DataProvider

DataProvider用于从Server端转载数据到浏览器中,包含异步和同步两种执行模式。

Pure Client

在Pure Client的开发模式中,我们主要需要关注的是Dorado.AjaxDataProvider这个类。该类内部通过Dorado的Ajax引擎向服务端请求数据,返回的数据格式默认应为JSON形式。

下面的命令定义了一个DataSet,同时设置该DataSet通过AjaxDataProvider来提取数据,数据事实上被保存在服务端data/phones.js文件中。

var dataSet = new Dorado.widget.DataSet({
    dataProvider: new Dorado.AjaxDataProvider("data/phones.js"),
    dataType: "Phone"
});

Dorado.AjaxDataProvider在发送Ajax请求时往往还会在请求中附带一些其他的信息,这取决与相应DataSet和DataType的设置。例如我们为DataSet的parameter属性定义了内容,或者我们声明了DataSet按照分页的方式装载数据。那么这些额外的参数和分页的信息都会附带在请求中被一同发送到服务器端。目前AjaxDataProvider所支持的额外信息包括:

  • parameter - 一组额外的属性。一般是通过DataSet的parameter属性定义的。
  • pageSize - 数据分页装载时每页的记录数。如果不支持数据分页装载,此参数将是0。
  • pageNo - 数据分页装载时当前请求的页号。

Dorado.AjaxDataProvider默认以POST方式发起请求,同时将上述的这些额外信息放置在POST请求的content中。这样,我们在服务器端必须拥有一些相应的支持才能读到这些JSON信息。以Java为例,下面给出了一个可以解析并得到这些JSON信息的Servlet的实例。

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
 
public class ExampleServiceServlet extends HttpServlet {
    private static final String JAVASCRIPT_TOKEN = "javascript";
    private static final int BUFFER_SIZE = 4096;
 
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        ServletInputStream in = request.getInputStream();
        try {
            String contentType = request.getContentType();
            if (contentType.contains(JAVASCRIPT_TOKEN)) {   // 判断contentType以确认客户端是否是以JSON的信息发送POST信息
                StringBuffer buf = new StringBuffer();
                byte[] b = new byte[BUFFER_SIZE];
                for (int n; (n = in.read(b)) != -1;) {
                    buf.append(new String(b, 0, n));
                }
                JSONObject json = JSONObject.fromObject(buf.toString());    // 利用JSONObject工具类解析并得到了客户端发送的JSON信息
                // 此处就可以利用这些JSON信息编写自己的业务逻辑了
            }
        }
        finally {
            in.close();
        }
    }
}

当然,在有些情况下我们可以希望自己来定义这些额外的信息应该如何被传递到Server。这时最好的办法就是派生出一个新的DataProvider,并且复写其中的getLoadOptions方法。

假设我们希望将parameter中的个参数以及pageSize、pageNo全部放到请求的URL参数中,那么我们可以这样来定义派生类:

Dorado.MyDataProvider = $extend(Dorado.AjaxDataProvider, {
    getLoadOptions: function(arg) {
        /* 调用父类中的处理逻辑
         * 由于我们知道原先的逻辑将额外数据都放置在jsonData中。因此我们可以从返回的options的jsonData属性中取得这些信息。 
         */
        var options = $invokeSuper.call(this, arguments);
 
        var jsonData = options.jsonData;
        var parameter = Dorado.Object.apply({}, jsonData.parameter);    // 将jsonData中定义的子属性复制到parameter中
        parameter.pageSize = jsonData.pageSize; // 将pageSize设置到parameter中
        parameter.pageNo = jsonData.pageNo; // 将pageNo设置到parameter中
        options.parameter = parameter;
        delete options.jsonData;    // 清除原先的jsonData
        return options;
    }
});

非Pure Client模式

该模式是指和dorado服务端的代码整合开发的场景。在这种场景下,后台的Ajax请求是由dorado后端的拦截器拦截并转发请求的。

在这种模式下我们可以在view设计器的model节点下看到多种类型的DataProvider:

其中最常用的是DirectDataProvider。

例如我们在Java后台通过annotation技术定义了一个DataProvider:

@Component
public class SimpleCRUD {
    @Resource
    private ProductDao productDao;

    @DataProvider
    public Collection<Product> getAll() throws Exception {
        return productDao.getAll();
    }
    ... 

接下来就可以在model中添加一个DirectDataProvider,并设置其interceptor属性:

这样这个Provider就知道通过interceptor拦截器去获取数据。

该处使用的是spring:的表达式,表示要从后台的spring服务中获取beanId为simpleCRUD的对象中通过getAll方法获取数据。

设置好之后我们再设置DataSet的dataProvider为这个自定义的dataProvider即完成了DataProvider的定义和使用。

当然在日常使用中,可以再度简化这个开发过程,在view中我们可以不用添加DirectDataProvider对象。而是直接在DataSet的dataProvider对象上定义:

这种方式会在dorado的内部自动创建DirectDataProvider对象,这种使用方式更为简洁一些。

当然你在dorado的sample-center中还能看到这种定义方式:

 看,这个地方连spring的id都可以省略。这是基于约定由于配置的一种使用方式,即假设当前View的名称和对应Spring的id的名称一样的情况下,例如本例view的名称为SimpleCRUD.view.xml,而对应的服务bean的名称为"simpleCURD",这种情况下我们就可以直接省略dataProvider属性配置中beanId的编写,直接写#+对应的方法名就可以。