语义层自定义视图的应用实例

第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;

}

}