自助报表分析 4:源代码简析
润乾 BI 之所以开源,主要考量是 BI 前端的管理需求多变,固定的产品难以应付,在 DQL 解决了关联数据查询难题后,用户容易基于它开发出真正敏捷的 BI 前端。
代码结构
润乾 BI 运行流程
代码结构:
主要源码简介
浏览器端的 Javascript 源代码都在 {WEB 根目录}/raqsoft/guide/js/ 下,主要的 js 文件有 dqlApi.js、dqlreport.js、query.js、raqsoftApi.js、where.js、common.js。
页面用 JSP 中的 taglib 技术展示,taglib 定义在 {WEB 根目录}/WEB-INF/raqsoftAnalyse.tld,实现 taglib 的 Java 类是 com.raqsoft.guide.tag.AnalyseTag.java,其它一些主要 Java 类有:
com.raqsoft.guide.web.DataSphereServlet.java,请求入口的 Servlet
com.raqsoft.guide.web.dl.ActionResultPage.java,处理大部分 Servlet 请求,主要功能代码在这个类里。
com.raqsoft.guide.web.dl.DfxQuery.java,用内置集算器脚本查询 / 计算不同来源的数据。
com.raqsoft.guide.web.dl.DfxData.java,缓存计算好的数据集。
引入的 jar 主要有:
datalogic.jar,DQL JDBC 驱动,连接 DQL Server 做查询;
esproc-bin-*.jar 集算器,内置了一些集算器脚本实现查询、计算;界面用户也可以自定义脚本做个性化的数据处理;
raqsoftReport.jar 润乾报表。
源代码中会调用这三个工具的一些接口类实现功能,但这三个工具自身的代码不开源。
同时集算器和润乾报表共用了同一个运行环境配置文件,{WEB 根目录}/WEB-INF/raqsoftConfig.xml,里面会定义所有可用的 JDBC 数据源,一些资源路径等。
获得 DQL 元数据
看 ConfigUtil.java 里的代码:
JDBC 查询语句”metadata”,能从 DQL 服务器获得 JSON 格式的整个元数据信息:
{
"tables": [{"name": "客户","dispName": "客户","type": "0","desc": "",
"fields": [{
"name": "客户",
"type": 2,
"desc": "",
"pk": 1,
"dim": "客户"
}
......
],
"subTables": []
}
}],
"dims": [{"name": "市","table": "市","field": "市",
"destLevels": [{
"name": "省","dest": "省. 省","formula": "int(?/100)"
}, {
"name": "大区","dest": "大区. 大区","formula": "int(?/10000)"
}]
},
......
],
"levels": [],
"annexTables": [
[{
"name": "客户","pks": ["客户"]
}, {
"name": "VIP 客户","pks": ["VIP 客户"]
}],
......
],
"classTables": [],
"editStyles": []
}
显示元数据树
把上面元数据信息从 WEB 服务器端传送到浏览器端,query.js 中用一个 JS 控件 zTree 把这些元数据信息整理后,显示为一棵元数据树:
其中的 zNodes 就是整理后的树节点,根据外键关联关系,相应的树节点可以展开出外键表:
依据界面操作生成 DQL 语句
从元数据树上选出一些字段做多维分析:
这些界面操作记录在 JS 变量 olapObj.conf.rpxs 里:
之后用 dqlApi.js 里的 dqlQuery.confUtils.generateDql() 方法按照界面上多维分析操作拼出相应的查询 DQL:
在 generateDql()方法里的最后可以看到,把整理好的 DQL 片段 (dqlSegments) 提交到服务器拼出最终的 DQL 语句:
得到 DQL 语句后,在 dqlreport.js 的 aly.queryData() 方法中,向 WEB 服务器发送查询请求:
用 DQL 查出的数据生成报表
界面上多维分析操作,除了用来生成查询 DQL,同时还用来生成润乾报表模板,用 aly.generateReport() 方法整理出一些报表关键信息,然后请求 WEB 服务器生成报表:
ActionResultPage.java 里 genReport 操作中,把生成好的报表模板存入 session:
最后在 showReport.jsp 中把 session 中的润乾报表模板展示出来即可。
实际上,大部分选项设置都提供了控制标签。像查询中:
guideConf.queryType = "group";//detail明细查询/group分组查询
guideConf.analysePage = "raqsoft/guide/jsp/analyse.jsp";//分析界面,用来显示查询结果
guideConf.fixedTable = '';//只显示某个具体的表
guideConf.maxDimSize = '5000';//自动生成维显示值时,每个维支持的条数,多于这个的数据会弃用掉
guideConf.detectLevel = '0';//广义字段自动检测的层数,默认4,0表示让用户在界面上选择
guideConf.showToolBar = 'yes';//是否显示查询界面上部的工具条
guideConf.showDataSources = 'yes';//是否显示工具条上的数据源切换
guideConf.fieldAreaWidth = 350;//树状表字段区域的宽度
guideConf.emptyReport = "yes";//跳转到分析界面时,是否默认生成明细列表
guideConf.defaultSaveName = "";//qyx默认的保存名称
guideConf.filter="default";
guideConf.autoReloadDimDataOnServer = 'yes';
guideConf.scanRow=1000;
比如要修改查询页面的默认取数条数:
修改 maxDataSize 就可以:
guideConf.maxDataSize = 1000;
如果想显示 / 隐藏这个取数条数,可以使用:
<script>
$(document).ready(function(){
document.title = "<%=GuideMessage.get(request).getMessage("guide.web3")%>";
//设置取数条数
$('#maxDataSizeConf').before('<span style="float:right;margin:15px 5px 10px 0;color:#DDD;font-size:14px;">条数据</span>')
.after('<span style="float:right;margin:15px 0px 10px 5px;color:#DDD;font-size:14px;">查询前</span>')
.val(guideConf.maxDataSize).css('display','block').css('margin','14px 2px 10px').css('width','60px').css('color','#333').css('text-align','center')
.keyup(function(){
try {
guideConf.maxDataSize = parseInt($(this).val());
} catch(e) {
$(this).val("0");
guideConf.maxDataSize = 0;
}
if (guideConf.maxDataSize<0) {
$(this).val("0");
guideConf.maxDataSize = 0;
}
submitQuery();
setTimeout(function(){$('#maxDataSizeConf').focus();},200);
});
//$(‘#maxDataSizeConf’).css(‘display’,‘none’); //隐藏掉界面设置取数条数
});
<scrpt>
如果想自定义查询按钮,增加如下代码调用 queryApi.submitQuery() 方法:
<input type="button" onclick="queryApi.submitQuery()" style="color:#fe4164;vertical-align:20px;text-decoration: none;" value="自定义查询按钮"/>