元数据JSON包含字段相关的一些信息,是最初始的输入。字段查询设置查询细节后,输出为查询JSON。
元数据JSON结构:
[
{
name : "group1", //组名
fields : [ //字段数组
{ //字段属性
name : "field1", //字段名
title : "中文字段名", //字段别名
dataType : 3, //数据类型
dateFormat : "yy -mm-dd", //日期格式
timeFormat : "HH:mm:ss", //时间格式
referData : [
{id:1, pId:0, name: ‘北京’,v:’1’ },
…
],
multi : 2 //是否允许多选,值为2表示不可多选
},…
]
},…
]
元数据JSON整体是一个数组。包含一个或多个元素(可看作分组)。一个元素是一组字段,对字段进行分组管理方便页面上按组选字段。
每个字段对象中属性定义如下:
name:字段名,和表中的字段名一致;
title:字段别名,在页面上显示,业务人员容易理解;
dataType:数据类型。1表示整数;2表示实数;3表示字符串;4表示日期。日期类型的数据在进行条件值编辑时,可使用日期控件;
dateFormat:日期格式,设置日期字段条件时使用;
timeFormat:时间格式,设置时间字段条件时使用;
referData:用选择方式编辑条件时的备选数据,可以是三状态切换按钮、多选按钮、下拉树等多种编辑风格;
referData的每一个备选项中的属性:
id及pId:下拉树才需要这两个属性,表示节点的上下级关系,其它编辑风格时可以省略;
name:显示值;
v:真实值。
multi:用选择方式编辑条件时,是否可以选多个值。multi的值为1时,按钮可多选,值为2或者不设置时表示单选。
name为必须设置的参数,其他参数可选。
不同结构的元数据JSON,在字段列表和查询页面所呈现的形式各不相同。如字段分组和多选按钮的JSON呈现的形式如下图所示:
使用不同结构的元数据json不仅可以对字段进行分组,为字段设置别名,还可以定义多种编辑风格以帮助用户快速正确地录入查询条件值。
例如:三状态切换按钮、多选按钮、下拉列表、下拉树等。期待用什么方式在页面上设置查询细节,就要生成相应的元数据JSON来驱动页面。
l 字段分组
表中字段多时,通过组名name 设置分组,进行分类管理。
[
{
name : 'group1',//组名
fields : [ //字段数组
{name:'a'},
{name:'aa'}
]
},{
name : 'group2',//组名
fields : [ //字段数组
{name:'b'},
{name:'bb'}
]
},{
name : 'group3',//组名
fields : [ //字段数组
{name:'c'},
{name:'cc'}
]
}
]
使用分组功能,可将同一类数据划分到一组,方便查看。缺省显示全部字段。
下拉列表选择不同的分组时,字段列表仅列出该组包含的字段,如:选择group1。
注:只有一个分组时,不显示分组下拉列表框。
l 别名
使用别名可增加字段可读性,便于理解。字段名必须与表中的字段名称相同,别名可随意设置。
通过title 为字段定义别名,不使用title 时,默认显示name。
[
{
name : 'group1',//组名
fields : [ //字段数组
{
name : 'StuId', //字段名
title : '学生编号' //字段别名
},{
name : 'Gender', //字段名
title : '性别' //字段别名
},{
name : 'Subject'
}
]
}
]
l 三状态切换按钮
三状态切换按钮是指有三种状态可以切换,且仅支持单选。
referData中备选项为2个时,字段会被设置成三状态切换按钮。
[
{
name : 'group1',//组名
fields : [ //字段数组
{
name : 'StuId', //字段名
title : '学生编号' //字段别名
},{
name : 'Gender', //字段名
title : '性别', //字段别名
referData : [ //三状态切换按钮。name为显示值,v为真实值。
{name:'男',v:'M'},
{name:'女',v:'F'}
]
},{
name : 'Subject', //字段名
title : '科目' //字段别名
}
]
}
]
本例中该按钮有3种显示方式:全部/男/女,在使用时只能选择一种状态:
l 多选按钮
referData中备选项不多于5个时,会列出全部备选项,且multi的值为1时,按钮可多选:
[
{
name : 'group1',//组名
fields : [ //字段数组
{
name : 'StuId', //字段名
title : '学生编号' //字段别名
},{
name : 'Gender', //字段名
title : '性别', //字段别名
referData : [ //三状态按钮。name为显示值,v为真实值。
{name:'男',v:'M'},
{name:'女',v:'F'}
]
},{
name : 'Subject', //字段名
title : '科目', //字段别名
referData : [ //多选按钮。name为显示值,v为真实值。
{name:'体育',v:' PE '},
{name:'数学',v:' Math '},
{name:'英语',v:' English '}
],
multi : 1
}
]
}
]
Subject字段referData的备选项有3个,则该按钮会出现3个子选项:体育/数学/英语。子选项可多选。
l 下拉列表
referData中备选项多于5个时,备选项会以下拉列表的形式呈现:
[
{
name : 'group1',//组名
fields : [ //字段数组
{
name : 'StuId', //字段名
title : '学生编号' //字段别名
},{
name : 'Gender', //字段名
title : '性别', //字段别名
referData : [ //三状态按钮。name为显示值,v为真实值。
{name:'男',v:'M'},
{name:'女',v:'F'}
]
},{
name : 'Subject', //字段名
title : '科目', //字段别名
referData : [ //多选按钮。name为显示值,v为真实值。
{name:'体育',v:' PE '},
{name:'数学',v:' Math '},
{name:'英语',v:' English '},
{name:'物理',v:' Physics'},
{name:'历史',v:'History '},
{name:'语文',v:'Chinese '}
],
multi : 1
}
]
}
]
multi的值为1时,下拉列表可多选。
multi的值为2,或者无multi时,下拉列表只能单选。
l 下拉树
referData备选项增加id/pId时表示父子关系,pId为0时为顶级:
[
{
name : 'group1',//组名
fields : [ //字段数组
{
name : 'StuId', //字段名
title : '学生编号' //字段别名
},{
name : 'Gender', //字段名
title : '性别', //字段别名
referData : [ //三状态按钮。name为显示值,v为真实值。
{name:'男',v:'M'},
{name:'女',v:'F'}
]
},{
name : 'Subject', //字段名
title : '科目', //字段别名
referData : [ //多选按钮。name为显示值,v为真实值。
{name:'体育',v:' PE '},
{name:'数学',v:' Math '},
{name:'英语',v:' English '},
{name:'物理',v:' Physics'},
{name:'历史',v:'History '},
{name:'语文',v:'Chinese '}
],
multi : 1
},{
name : 'native', //字段名
title : '户籍城市', //字段别名
referData : [ //多选按钮。name为显示值,v为真实值。id和pId设置节点的上下级关系。
{id:1, pId:0, name:'北京',v:'1'},
{id:2, pId:0, name:'天津',v:'2'},
{id:3, pId:0, name:'上海',v:'3'},
{id:6, pId:0, name:'重庆',v:'4'},
{id:4, pId:0, name:'河北省',v:'5'},
{id:41, pId:4, name:'石家庄',v:'6'},
{id:42, pId:4, name:'保定',v:'7'},
{id:43, pId:4, name:'邯郸',v:'8'},
{id:44, pId:4, name:'承德',v:'9'},
{id:5, pId:0, name:'广东省',v:'10'},
{id:51, pId:5, name:'广州',v:'11'},
{id:52, pId:5, name:'深圳',v:'12'},
{id:53, pId:5, name:'东莞',v:'13'},
{id:54, pId:5, name:'佛山',v:'14'},
{id:6, pId:0, name:'福建省',v:'15'},
{id:61, pId:6, name:'福州',v:'16'},
{id:62, pId:6, name:'厦门',v:'17'},
{id:63, pId:6, name:'泉州',v:'18'},
{id:64, pId:6, name:'三明',v:'19'}
],
multi : 1
}
]
}
]
multi的值为1时,下拉树可多选。
multi的值为2,或者无multi时,下拉树只能单选。
关于元数据JSON的使用方式有如下四种:
方法一:直接提供json字符串。
编辑【安装目录】\report\web\webapps\demo\raqsoft\guide\jsp\下的cq.jsp,使用json字符串生成元数据JSON:
String metadata = "[{name:'group1',fields:[{name:'EID',title:'员工编号'},{name:'GENDER',title:'性别'},{name:'SALARY',title:'工资'}]}]";
结果如图:
方法二:提供一个服务器上的.json文件,元数据JSON来自.json文件。
.json文件内容如图:
该文件位于【安装目录】\report\web\webapps\demo\下。在commonQuery标签中指定metadata的值为 "myMetadata.json":
结果如图:
方法三:使用根据页面参数和当前登录用户动态生成的json字符串。
通用查询控件集成到应用系统后,通常由应用系统负责提供当前登录用户的信息以及要查询的表名。
比如将用户信息和表名从session中传递过来。本例为了演示,直接在jsp写了固定的值,手动改这个值来模拟不同登录用户。假如系统中有两个用户user1和user2。user1用户可以查看学生表或成绩表中的一部分字段;user2用户可以查询学生表或成绩表中的另一部分字段。那么我们就可以通过使用变量传递不同的值达到动态生成json字符串的目的。
在cq.jsp中添加如下java代码判断:
<%
String tableName = "学生表";
String userId = "user2";
if ("成绩表".equals(tableName)){
if ("user1".equals(userId))
metadata = "[{name:'group1',fields:[{name:'CLASS',title:'班级'},{name:'STUDENTID',title:'学号'},{name:'SUBJECT',title:'科目'},{name:'SCORE',title:'成绩'}]}]";
else if ("user2".equals(userId))
metadata = "[{name:'group1',fields:[{name:'CLASS',title:'班级'},{name:'STUDENTID',title:'学号'}]}]";
} else if ("学生表".equals(tableName)){
if ("user1".equals(userId))
metadata = "[{name:'group1',fields:[{name:'STUDENTID',title:'学号'},{name:'Gender',title:'性别'},{name:'name',title:'姓名'}]}]";
else if ("user2".equals(userId))
metadata = "[{name:'group1',fields:[{name:'STUDENTID',title:'学号'},{name:'name',title:'姓名'}]}]";
}
%>
<raqsoft:commonQuery
metadata="<%=metadata%>"
params="<%=params%>"
cqx="<%=cqx%>"
/>
结果如图:
方法四:使用集算器脚本spl文件生成的json字符串。
使用集算器脚本spl文件(文件后缀为.splx/.spl/.dfx)从数据库中把表取出来,然后动态地生成元数据JSON。
本小节内容要求用户对集算器脚本有一定的学习了解。
spl文件是通过润乾集算器生成的文件。在spl文件中可以执行各类数据分析与结构化计算,也可以自由访问数据库。通用查询在使用spl时,需在.splx文件的网格程序中使用return语句返回json串类型的结果集。
.splx文件内容如下:
|
A |
|
1 |
=connect("demo") |
连接demo数据源 |
2 |
=A1.query("select * from 员工 limit 1") |
查询"员工"表中的一行数据 |
3 |
=create(name,dataType) |
创建空序表 |
4 |
=A2.fname().run(c=~,val=A2(1).field(c),type=if(ifnumber(val):1,ifstring(val):3;4),A3.insert(0,c,type)) |
获取员工表中的字段名和字段数据类型,并将处理后的数据插入到A3 |
5 |
=create(name,fields) |
创建空序表 |
6 |
>A5.insert(0,"员工表",A3) |
将数据插入到 A5 |
7 |
>A1.close() |
关闭数据源连接 |
8 |
return json(A5) |
返回json串 |
spl文件位于【安装目录】\report\web\webapps\demo\WEB-INF\reportFiles\commonQuery\下。spl类型的元数据使用相对路径,相对于应用根目录。在commonQuery标签中指定metadata的值为 "WEB-INF/reportFiles/commonQuery/QueryMetadata.splx":
结果如图:
这样就完成了使用数据库表生成元数据JSON的操作。
但是如果想要换一个表查询时,本例中spl脚本就不通用了。因此我们还需要做一个通用模版,这样无论查询哪张表均不用再修改spl脚本,甚至还可以根据页面参数和当前登录用户用spl脚本动态的生成json字符串。具体可参考动态生成JSON小节。
通过前面小节的介绍我们了解了元数据JSON的细节内容以及它如何驱动通用查询页面。现在我们再讲述下如何自动化的产生元数据JSON,最原始的素材是数据库里的表,我们需要一个程序能动态的把数据库里的表转换成元数据JSON,这中间还要考虑权限控制。
如果想让数据库里的表自动化的产生元数据JSON,那么我们需要一个程序能动态的把数据库里的表转换成元数据JSON,而使用spl(文件后缀为.splx/.spl/.dfx)是一个非常好的选择,使用集算器脚本可灵活生成所需元数据JSON。
前面的spl例子中指定了"员工"表生成元数据JSON,现在对QueryMetadata.splx稍作修改,不指定表名而是通过参数传递表名,将spl另存为commonQueryMetadata.splx,修改文件内容如下:
|
A |
|
1 |
=connect("demo") |
连接demo数据源 |
2 |
>params=json(params) |
将json格式串解析成序表返回 |
3 |
=A1.query("select * from "+params.table+" limit 1") |
根据表名参数table查询一行数据 |
4 |
=create(name,dataType) |
创建空序表 |
5 |
=A3.fname().run(c=~,val=A3(1).field(c),type=if(ifnumber(val):1,ifstring(val):3;4),A4.insert(0,c,type)) |
获取table表中的字段名和字段数据类型,并将处理后的数据插入到A4 |
6 |
=create(name,fields) |
创建空序表 |
7 |
>A6.insert(0,params.table+"表",A4) |
将数据插入到 A6 |
8 |
>A1.close() |
关闭数据源连接 |
9 |
return json(A6) |
返回json串 |
参数定义:
表名作为参数,由外部传入。传入不同的表名可得到不同的元数据json,从而达到动态的目的。传入spl里的参数值格式随意,只要spl里按照如下格式正确解析就可以:
String params = "{'table': '员工', 'userId': '23'}";
commonQueryMetadata.splx脚本只涉及字段名和数据类型,形成最简单的元数据JSON,接下来在这个的基础上,我们一点点补充成完整功能的元数据JSON,增加元数据JSON中的表现信息(分组管理、中文名、条件值的可选项等)。
l 设置字段别名,可用来给英文字段设置中文字段名。
7 |
'[{v:"EMPID",d:"员工编号"},{v:"EMPNAME",d:"姓名"},{v:"GENDER",d:"性别"},{v:"DEPT",d:"部门"},{v:"NATIVE",d:"户籍城市"},{v:"DEGREE",d:"学历"},{v:"BIRTHDAY",d:"生日"},{v:"SALARY",d:"工资"}] |
>fieldNames=json(A7) |
|
8 |
>A4=A4.derive(fieldNames.select(v==name).d:title) |
|
|
l 增加性别三状态切换按钮、学历多选按钮、省市下拉树的数据。
10 |
'[{v:1,d:"男"},{v:2,d:"女"}] |
>gender=json(A10) |
|
11 |
'[{v:1,d:"小学"},{v:2,d:"初中"},{v:3,d:"高中"},{v:4,d:"大专"},{v:5,d:"本科"}] |
>education=json(A11) |
|
12 |
'[{id:1, pId:0, name:'北京',v:'1'},{id:2, pId:0, name:'天津',v:'2'},{id:3, pId:0, name:'上海',v:'3'},{id:6, pId:0, name:'重庆',v:'4'},{id:4, pId:0, name:'河北省',v:'5'},{id:41, pId:4, name:'石家庄',v:'6'},{id:42, pId:4, name:'保定',v:'7'},{id:43, pId:4, name:'邯郸',v:'8'},{id:44, pId:4, name:'承德',v:'9'},{id:5, pId:0, name:'广东省',v:'10'},{id:51, pId:5, name:'广州',v:'11'},{id:52, pId:5, name:'深圳',v:'12'},{id:53, pId:5, name:'东莞',v:'13'},{id:54, pId:5, name:'佛山',v:'14'},{id:6, pId:0, name:'福建省',v:'15'},{id:61, pId:6, name:'福州',v:'16'},{id:62, pId:6, name:'厦门',v:'17'},{id:63, pId:6, name:'泉州',v:'18'},{id:64, pId:6, name:'三明',v:'19'}] |
>city=json(A12) |
|
13 |
>A4=A4.derive(if(name=="GENDER":gender,name=="DEGREE":education,name=="NATIVE":city;null):referData) |
|
|
14 |
>A4=A4.derive(1:multi) |
|
|
l 拼元数据JSON时,按照字段类型分组,方便选字段。可根据需求改为其它要求的分组方式。
17 |
>A4.group(dataType).run(c=~,t=~(1).dataType,A16.insert(0,if(t==1:"数值字段",t==3:"字符字段";"日期字段"),c)) |
16 |
if (params.userId==23) |
>data=A4.select("EMPID,EMPNAME,DEPT".split(",").pos(name)!=null) |
17 |
else if (params.userId==24) |
>data=A4.select("DEPT,BIRTHDAY,GENDER".split(",").pos(name)!=null) |
18 |
=create(name,fields) |
|
19 |
>data.group(dataType).run(c=~,t=~(1).dataType,A18.insert(0,if(t==1:"数值字段",t==3:"字符字段";"日期字段"),c)) |
|
参数中传入了用户ID,期望不同的用户看到不同的字段:
用户ID为23时,选用EMPID、EMPNAME、DEPT字段生成的元数据JSON
用户ID为24时,选用DEPT、BIRTHDAY、GENDER字段生成的元数据JSON
详细集算器脚本参考commonQueryMetadata.splx。该文件位于【安装目录】\report\web\webapps\demo\WEB-INF\reportFiles\commonQuery\下。
使用"员工"表生成元数据JSON,结果如图:
参数说明:
table:需要查询数据的表名。
metadata:spl类型(文件后缀为.splx/.spl/.dfx)的元数据,仅支持相对路径,相对于应用根目录
table_name +spl类型的metadata用来生成最终的元数据json串。
rpx:报表模版,用来展示数据。可使用相对路径或绝对路径,使用相对路径时,相对于应用中配置文件raqsoftConfig.xml 里配置的Report中的home属性的路径。