语义层自定义视图的应用实例
第32章 语义层自定义视图的应用实例
1. 问题概述
最近有个客户要对语义层做二次开发,咨询了关于语义层的详细操作,个人觉得此问题有点深度,也是多数情况下没有考虑用到过的,对语义层方面有一定代表性,和大家分享下,具体需求体现在两个方面:
A.语义层文件(XML)的生成,是客户通过自己的业务逻辑处理,在其系统操作流程里向导的方式调用润乾API动态生成语义层XML文件(遵循语义层规范).
B.对于数据的来源,不能直接连接数据库,也是要通过中间系统走逻辑整理过的数据,作为语义层的数据来源(类似自定义数据集).语义层提供了数据表、SQL查询、存储过程、内建视图等多种视图定义方式,显然客户对视图定义的需求需要用到自定义的方式才能满足.
几种视图具体实现的类如下:
数据表: com.runqian.report4.semantics.TableView
SQL查询:com.runqian.report4.semantics.SQLView
存储过程:com.runqian.report4.semantics.ProcView
内建视图:com.runqian.report4.semantics.BuiltinView
自定义视图:com.runqian.report4.semantics.CustomView
2. 案例
上海维涛信息技术有限公司
3. 实例演示
1. 在语义层设计器中,展开”视图”,在”自定义”上点右键-追加,弹出视图定义窗口, 在弹出的视图定义窗口中,可以编辑自定义视图的名称,这里写为”EMPLOYEE”。在数据源下拉框中选择数据源,在类名框中输入自定义视图类的名字.在字段里,可以先增加一些列信息(通常也可以利用API后台程序准备好,直接返回),EMPID,EMPNAME,BONUS,主要目的是为了程序里能动态拿字段信息,方便测试.
2.在参数选项里,定义了参数为EMPNAME,在后台进行接收参数查询,这里支持表达式传递,默认缺省值传递
3.把编译后的class文件放到设计器里指定目录下运行
4.重启设计器,编辑语义层,预览自定义视图:EMPLOYEE,参数值选出方式为缺省选出.
5.预览数据,根据默认值”小”进行like 查询结果,后台日志信息等
6. 保存语义层后回到报表设计器,刷新语义层面板,可以看到”EMPLOYEE”已经被列出在视图节点下了,可以像普通的表视图一样去使用,报表模板里数据的展现和后台日志信息
4. 关键性程序说明
自定义视图类需要实现润乾报表提供的com.runqian.report4.semantics.ICustomViewDataSetFactory接口; TestCustomView2.java代码:
packageapi;
importcom.runqian.report4.semantics.*;
importcom.runqian.report4.usermodel.Context;
importcom.runqian.report4.usermodel.ViewDataSetConfig;
importcom.runqian.report4.dataset.*;
importcom.runqian.report4.ide.base.*;
importcom.runqian.report4.model.expression.Expression;
importjava.sql.*;
importcom.runqian.report4.usermodel.*;
/**
*自定义视图示例
*自定义视图必须实现ICustomViewDataSetFactory接口
*@authorzHouHuiHui
*@version1.0
*/
publicclassTestCustomView2 implements
com.runqian.report4.semantics.ICustomViewDataSetFactory {
publicTestCustomView2() {
}
/**
*根据视图数据集配置vdsc来动态创建相应检索的字段以及检索数据
*
*@paramctx
*Context,应用的上下文对象,从中获取数据库连接,语意层,以及参数值
*@paramvdsc
*ViewDataSetConfig,视图数据集配置,字段数目以及条件
*@paramretrieve
*boolean,是否检索数据
*@returnDataSet
*/
publicDataSet createDataSet(Context ctx, ViewDataSetConfig vdsc,
booleanretrieve) {
// 示例2:该段为稍微复杂的演示如何从数据库取数据的例子.
// 获取语意层管理器
SemanticsManager sManager = ctx.getSemanticsManager();
// 当前的视图名称
String viewName = vdsc.getViewName();
System.out.println(“当前的视图名称:”+ viewName);
CustomView customView = (CustomView) sManager.getView(viewName);
DataSet ds = newDataSet(vdsc.getName()); // 数据集的名称
StringBuffer sql = newStringBuffer(“SELECT “);
// 根据视图数据集的选出的字段来构造数据集
System.out.println(“选出列的个数:”+ vdsc.getSelectedColCount());
for(inti = 0; i < vdsc.getSelectedColCount(); i++) {
String colName = vdsc.getSelectedCol(i);// 获取字段标题
ColInfo colInfo = customView.getColInfoByColName(colName);// 由字段标题获取列对象
ds.addColInfo(colInfo);// 把列对象添加到视图数据集
sql.append(colName);// 拼接SQL
if(i != vdsc.getSelectedColCount() – 1) {
sql.append(“,”);
} else{
sql.append(” FROM “);
sql.append(viewName); // 假设视图名称跟数据集要检索的表名称相同,仅供参考
}
}
if(!retrieve) {
returnds;
}
sql.append(” WHERE EMPNAME like ?”); // 查询条件
System.out.println(“SQL:”+ sql.toString());
// 根据视图的数据源获取到连接对象
String dsName = customView.getDataSourceName();
System.out.println(“数据源:”+ dsName);
try{
DataSourceConfig dsConfig = ctx.getDataSourceConfig(dsName);// 获取数据源
Connection con = ctx.getConnectionFactory(dsName).getConnection();// 当前可用的数据库连接
PreparedStatement pst = con.prepareStatement(newString(sql
.toString().getBytes(), dsConfig.getDBCharset()));// 准备查询
// 下面的参数个数应该跟上面的where字句的问号个数相匹配,这里仅仅示意
for(inti = 0; i < vdsc.getParamCount(); i++) {
String paraName = vdsc.getParam(i);
System.out.println(“参数:”+ paraName);
ViewParam vp = getParamByName(customView, paraName);//获取参数的完整信息
if(vp != null) {
String exp = vp.getExp(); // 获取参数表达式
System.out.println(“表达式:”+ exp);
Expression expr = newExpression(ctx, exp); // 定义表达式类对象
Object val = expr.calculate(ctx, false); // 计算表达式
System.out.println(“计算表达式结果:”+ val.toString());
String df = vp.getDefValue(); // 默认值:张三
System.out.println(“默认值:”+ df);
pst.setString(i + 1, “%”+ df + “%”);// 设置要查询的参数值like匹配,如果有别的类型,请自己注意调用不同的setXXX
}
}
System.out.println(“步骤开始“);
ResultSet rs = pst.executeQuery();// 执行SQL语句,返回结果集
System.out.println(“步骤一“);
while(rs.next()) {
System.out.println(“步骤二“);
Row r = ds.addRow();// 向自定义视图中添加一个空行
for(intj = 1; j <= ds.getColCount(); j++) {
System.out.println(“数据集列:“+ ds.getColCount());
System.out.println(“数据集列值:“+ rs.getObject(j));
r.setData(j, rs.getObject(j));// 把数据集记录中的字段值添加到视图字段中
}
}
} catch(Exception ex) {
ex.printStackTrace();
}
returnds;
}
//由参数名获取参数的完整信息
privateViewParam getParamByName(CustomView cv, String paraName) {
for(inti = 0; i < cv.getParamCount(); i++) {
ViewParam vp = cv.getParam(i);
System.out.println(“参数标题:”+ vp.getTitle());
if(vp.getTitle().equalsIgnoreCase(paraName)) {
returnvp;
}
}
returnnull;
}
/**
*该方法构造一个空的数据集,用于上层程序获取字段的名称以及类型信息;比如语意层管理器从该方法登记字段结构
*
*@paramctx
*Context,理论上可以根据不同的数据源名称来动态设置不相同的字段,但实际应用过程中
*参数的设置是为了将来可能的用途,目前没有意义
*如果真的更换了数据源,则需要重新读取视图结构;建议不要用,而是不同的数据源多建一个类来表示不同的数据结构
*@paramcv
*CustomView,没有意义,不要管
*@paramretrieve
*boolean,没有意义,不要管
*@returnDataSet
*/
publicDataSet createDataSet(Context ctx, CustomView cv, booleanretrieve) {
DataSet ds = newDataSet(“自定义视图“);
returnds;
}
}