Dorado 5 : 5.05.flushData(动态数据更新) (RF1)

flushData是dataset提供的客户端方法。该方法的主要作用是重新从服务器端下载数据集的数据来填充当前dataset。执行此方法时dataset中原有的记录将被全部清除。flushData在dorado开发当中是一种非常重要的AJAX请求,也是复杂页面开发中的重要处理技巧。
在客户端可以直接调用flushData()方法向服务器发出请求:

datasetEmployee.parameters().setValue("dept_id", "D11");datasetEmployee.flushData();

flushData方法执行时,允许通过dataset的parameters参数集合向Server传递参数信息。以上范例就是利用dataset的flushData()方法,上传dept_id参数信息。
而在Server端如何接受flushData方法的请求,以及如何获取客户端上传的parameters参数,以下按照常用的服务器端接受处理技术分类说明。

利用视图模型实现类响应flushData

flushData()方法执行时默认会自动调用视图模型实现类的doLoadData()方法:

protected void doLoadData(ViewDataset dataset)
throws Exception {
// Add your code here
super.doLoadData(dataset);
}

protected void doLoadData()
throws Exception {
// Add your code here
super.doLoadData();
}

可以在以上两个方法中通过自定义的代码实现dataset相关数据加载工作。以上两个方法只是构造函数不一样,功能相同。自定义实现的时候要注意保留super关键字。

利用listener响应flushData

如果给dataset定义了listener,则flushData()还会自动调用Listener中的beforeLoadData(),afterLoadData()方法:

public boolean beforeLoadData(Dataset dataset)
throws Exception {
return true;
}

public void afterLoadData(Dataset dataset)
throws Exception {
}

Dataset的数据加载工作也可以在listener中的这两个方法上实现。

利用DataProvider响应flushData

在marmot开发架构中还可以指定一个DataProvider以及通过method属性指定相关的数据加载方法:

<Dataset id="dsUser" type="Marmot" objectClazz="sample.domain.User"
dataProvider="userService" method="loadAllUsers">
...
</Dataset>

userService在spring的xml配置:

<bean id="userService" class="sample.service.UserService"/>

DataProvider定义:

public class UserService {
/**

  • 查询所有的用户信息
    */
    public void loadAllUsers(DataSet recordSet) throws Exception {
    List employees = query.list();//获取数据

    recordSet.setRecords(employees);//将数据交给DataSet
    }
    }

分页处理

以上三种响应flushData()的处理方式中,都可能会涉及到分页技术的处理。我们可以在相应flushData()的方法中获取该次请求的pageIndex,pageSize信息。
以下的dataset分页处理代码目的是为了说明分页处理注意事项,并不严谨。实际开发时注意调整。另外实现分页处理时也可以利用dorado提供的PagingHelper辅助分页处理。
视图模型实现类:

protected void doLoadData(ViewDataset dataset)
throws Exception {
int pageIndex = dataset.getPageIndex();
int pageSize = dataset.getPageSize();
super.doLoadData(dataset);
}

protected void doLoadData()
throws Exception {
Dataset dataset = getDataset("dsUser");
int pageIndex = dataset.getPageIndex();
int pageSize = dataset.getPageSize();
super.doLoadData();
}

获得pageSize, pageIndex信息之后就可以调用自己的逻辑处理代码将符合条件的数据交给dataset。例如:
范例1:List处理

List employees = query.list();
List list = employees.subList(pageSize*(pageIndex-1), pageSize*pageIndex);
dataset.fromDO(list);

范例2:ResultSet处理

Connection conn = ConnectionHelper.getConnection("doradosample");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from employee");

rs.absolute(pageSize*(pageIndex-1));
while(rs.next()){
dataset.insertRecord();
dataset.setString("employee_id", rs.getString("employee_id"));
dataset.setString("employee_name", rs.getString("employee_name"));
dataset.setString("dept_id", rs.getString("dept_id"));
dataset.setBoolean("sex", rs.getBoolean("sex"));
dataset.setDouble("salary", rs.getDouble("salary"));
}

范例3:DBDataset处理

Connection conn = ConnectionHelper.getConnection("doradosample");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from employee");

dataset.load(rs);//DBDataset会自动根据pageSize,pageIndex从ResultSet中装载一部分记录

范例4:Hibernate处理

List employees = session.createQuery("from Employee")
.setFirstResult(pageSize*(pageIndex-1))
.setMaxResults(pageSize)
.list();

dataset.fromDO(employees); // 将employees中的数据反射到Dataset中

实现分页处理时,不仅要保证dataset只装载分页的数据,还要记得设置dataset的pageCount属性,否则客户端就无从得知本次查询的总记录数,如下图的分页导航组件可以看到总页数信息:

图表 26 查询结果总页数
pageCount不仅在PagePilot(分页导航组件)中要使用,也是作为dataset的一个重要属性不能被忽视的。因此在执行分页处理的时候,必须同时指定dataset的pageCount属性。
范例1:List处理

List employees = query.list();
List list = employees.subList(pageSize*(pageIndex-1), pageSize*pageIndex);
dataset.fromDO(list);
dataset.setPageCount(list.size()/pageSize);

范例2:ResultSet处理

Connection conn = ConnectionHelper.getConnection("doradosample");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from employee");

rs.absolute(pageSize*(pageIndex-1));
while(rs.next()){
dataset.insertRecord();
dataset.setString("employee_id", rs.getString("employee_id"));
dataset.setString("employee_name", rs.getString("employee_name"));
dataset.setString("dept_id", rs.getString("dept_id"));
dataset.setBoolean("sex", rs.getBoolean("sex"));
dataset.setDouble("salary", rs.getDouble("salary"));
}
rs.last();
dataset.setPageCount(rs.getRow()/pageSize);

范例3:Hibernate处理

int rowCount = ( (Integer)
session.createQuery("select count(star) from Employee").
iterate().next()).intValue();
List employees = session.createQuery("from Employee")
.setFirstResult(pageSize*(pageIndex-1))
.setMaxResults(pageSize)
.list();

dataset.fromDO(employees); // 将employees中的数据反射到Dataset中
dataset.setPageCount(rowCount/pageSize);

查询处理

Dorado中实现查询通常都是通过flushData()实现。

select * from employee where dept_id=?

以上是查询常用的sql查询语句,无论您是采用JDBC编程还是ORM技术,业务逻辑层都必须要接受一个dept_id信息,并根据这个参数的值进行数据的刷选。
幸好dataset提供了一个参数集合parameters(),任何一种类型的Dataset都拥有该参数集合。该参数集合在客户端的使用方式如下:

var pm = dataset.parameters();
pm.setValue("parameter1","value1");
pm.setValue("parameter2","value2");

parameters()的详细使用参考:ParameterSet(客户端);
其中ParameterSet的setValue()方法会自动判断,如果ParameterSet中没有对应的参数变量就自动的先添加一个,再将value保存进去。
根据以上的sql查询的需求,我们就可以在客户端这么写代码:

datasetEmployee.parameters().setValue("dept_id", "D11");

参数信息存储到dataset的parameters()中之后,如果调用flushData()方法系统就会自动的将该参数信息提交的服务器的业务逻辑处理层。

datasetEmployee.parameters().setValue("dept_id", "D11");
datasetEmployee.flushData();

在业务逻辑层获取该参数的方法如下:
范例1:Listener(视图模型实现类参考listener):

public boolean beforeLoadData(Dataset dataset)
throws Exception {
String deptId = dataset.parameters().getString("dept_id");
List employees = query.listByDeptId(deptId);
dataset.fromDO(employees);
return true;
}

范例2:利用AutoSqlDataset的MatchRule实现查询

<Dataset id="datasetEmployee" type="AutoSql" originTable="employee" keyFields="employee_id" retrieveAfterUpdate="true">
...
<MatchRules>
<MatchRule originField="dept_id" table="employee" operator="=" dataType="string" value=":dept_id" escapeEnabled="true" />
</MatchRules>
</Dataset>

在AutoSqlDataset中利用冒号+变量名的方式定义sql查询参数。Dataset执行flushData的时候会自动的将parameters()中名称与MatchRule中的参数比较,如果相同就自动实现赋值工作。通过这种特性在很多dorado页面中可以通过配置实现查询节约大量的代码编写工作。
范例3:利用hibernate的Criteria实现查询

public void loadAllUsers(DataSet recordSet) throws Exception {
Session session = hibernateTemplate.getSessionFactory().getCurrentSession();
Criteria criteria = session.createCriteria(Employee.class);

Map parameters = (Map)recordSet.getParameters();
String deptId = (String)parameters.get("dept_id");

if (StringHelper.isNotEmpty(deptId))
criteria.add(Expression.eq("deptId",deptId));

recordSet.addRecords(criteria.list());
}

异步刷新功能(async)

flushData()提供与服务器异步通信的能力,从而使用户从请求/响应的循环中解脱出来。借助于flushData()的异步刷新功能,可以在用户单击按钮时,使用JavaScript和DHTML立即更新UI,并向服务器发出异步请求,以执行更新或查询数据库。在请求返回之前用户可以继续执行其他的业务操作,而当请求执行结束并返回时,就可以使用JavaScript和CSS来相应地更新UI,而不是刷新整个页面。最重要的是,用户甚至不知道浏览器正在与服务器通信:就如同多线程一样,一边听歌一边写文档。实现方法:

datasetEmployee.flushDataAsync();

在很多情况下使用异步刷新能大大地改善用户的体验,极大地加快系统响应速度,不过开发人员使用异步刷新时,必须要确保界面上用户的后续操作不会因为异步操作还未完成而产生逻辑上的错误方可使用。