使用本示例需通过docker容器,请先下拉jxTMS的docker镜像并按说明启动tms容器,并从helloWorld开始尝试。
jxTMS的查询
上一节中我们演示了数据库中的表的定义和ORM操作,本节我们主要演示条件查询。大部分情况下,我们是:
-
查询出数据显示到一个web界面的数据表中供用户查看
-
用户点击某行的某个工具条,jxTMS再执行相应的响应函数对该行数据进行处理
本节我们先演示如何从数据库中查询数据显示到一个web界面的数据表中。
数据源的定义
jxTMS中将一个查询语句称为一个数据源,数据源的定义是在sql文件中以类SQL的语法进行定义的。请在demo1目录中新建一个名为sql的文件,然后输入:
#请注意:我们用的是类sql语法,所以和sql语法是有一点区别的
sql listDemoData
#from子句要在select子句前
from demoData as ta
#all相当于sql中的*,即全部读取
select ta.all
#其where子句中的相等比较是==,两个等号
where ta.Type=='test'
orderBy ta.CreateTime DESC;
注:目前的where子句中的条件都是and连接,or连接的条件要先转换为and连接
每个数据源定义语句,以sql开头,以英文分号结尾,具体语法可参考sql数据源.。
listDemoData数据源在使用时必须使用全名,而数据源的全名是【模块名.数据源名】,则示例中的全名应为:demo.listDemoData。其含义是查询所有Type是test的demoData对象。
对应的数据表
为了显示listDemoData查询出来的数据,我们还需要定义一个数据表。我们在web文件中添加如下的定义【具体语法可参考数据表控件】:
web listDemoData type div;
web listDemoDatat1 bind tableTotalCount parent listDemoData type table title="demoData列表",width=900,pagination=true,query=search,queryParam={'listTable':'listDemoDatat1'};
with listDemoDatat1 col ID head ID hide=true;
with listDemoDatat1 col CreateTime head 创建时间 width=150;
with listDemoDatat1 col Type head 类型 width=100;
with listDemoDatat1 col Name head 名字 width=80;
with listDemoDatat1 col NoUsed head 已删除 width=80;
上述文本,定义了一个listDemoData的界面,该界面的主体是listDemoDatat1数据表,该数据表是一个分页表【pagination=true,默认每页15行】,由于是分页表,所以必须绑定tableTotalCount,jxTMS会在初始时,先查询符合条件的数据行总数,以便于分页控件的初始化【确定页数等】,query、,queryParam属性也都必须按示例书写,其中queryParam是一个json类型的属性,其必须将listTable值,指定为本数据表的名字,由于本数据库名为listDemoDatat1,所以listTable的值就必须设置为listDemoDatat1,否则无法正确显示数据。
listDemoDatat1数据表,一共定义了5列,分别对应demoData中的五个属性,但由于ID一般都不需要显示,所以使用了hide属性,其它可见列都定义了width属性,大家一会可以观察一下效果。
注1:这里定义的其实是各列的相对宽度,listDemoDatat1表我们定义了900的宽,表中各列的实际宽度就是:
本列的相对宽度 * 900 /各列相对宽度之和
注2:ID不显示出来,还要写在这里的原因很简单,如果有针对各行【即针对每个demoData对象】的操作,这些操作都需要以ID来定位是对哪一行的操作。后面会演示如何使用这样的ID
增加入口
想显示上面定义的这个数据表,需要一个入口才能被我们找到后使用,所以我们需要在op.py中为listDemoData增加一个入口:
@biz.Motion('demo.demo1','disp','listDemoData')
@biz.OPDescr
def op1(json):
json.setShortcut('演示'.decode('utf-8'),'listDemoData')
json.setParam('objType','demoData').setParam('dispType','list').setParam('dataSource','demo.listDemoData')
对照上节helloWorld的入口定义,我们会发现listDemoData多了三条setParam语句。setParam是用来为入口设置参数的,为了listDemoData能正确的执行,我们为其设置了三个参数:
-
objType:从数据库查询出来的数据,我们应将其转换为哪种类型的数据对象
-
dispType:对于数据表来说,必须固定为list
-
dataSource:指定本次查询的数据源的全名
现在我们就将sql、web、op.py三文件文件按用sftp管理jxTMS的代码所述更新到/home/tms/codeDefine/demo/demo/demo1目录中。
然后执行一次热机刷新.。由于我们在左侧快捷栏中增加了一个入口,而快捷栏是每次登录后一次性加载的,所以我们得退出登录再次登录后才能看到刚添加的入口。
再次登录后,点击快捷栏中的【演示->listDemoData】,看看显示效果:
注:由于我们只创建了一个demoData对象,所以只有一行。因此最下面的分页栏处只有一页
显示详情
上面说了ID为什么被隐藏起来,现在我们就来看看如何使用这个隐藏起来的ID。我们先在web文件中增加一个demoData的详情界面:
web dispDemoData type div;
web dispDemoDatat1 parent dispDemoData type table title="世界,你好",width=900;
with dispDemoDatat1 row 0 col c0 web n type text text='类型:',width=100;
with dispDemoDatat1 row 0 col c1 web n bind demoType type text width=350;
with dispDemoDatat1 row 0 col c2 web n type text text='名称:',width=100;
with dispDemoDatat1 row 0 col c3 web n bind demoName type text width=350;
同一行中的列叫什么无所谓,但不能重名,否则前一个会丢失掉。
然后在capa.py文件中增加dispDemoData的prepareDisp事件响应函数:
@myModule.event('prepareDisp', 'dispDemoData')
def dispDemoData(self, db, ctx):
dd = pyORM.getByID(db.getDBConn(),'demoData',self.getInput('ID'))
self.setOutput('demoType',dd.Type)
self.setOutput('demoName',dd.Name)
然后,还要在listDemoData表中增加一行:
with listDemoDatat1 col op1 head 显示详情 web n type a width=80,capaname='demo.demo1',motion=disp,
demand=dispDemoData,primary=true,text='查看',require=[{"paramName":"ID"}];
将web、capa.py等文件文件按用sftp管理jxTMS的代码所述更新到/home/tms/codeDefine/demo/demo/demo1目录中。
然后执行一次热机刷新,点击快捷栏中的【演示->listDemoData】,看看显示效果。
大家会看到列表中多出了一列,大家点击【查看】这个工具条,看看会发生什么。
大家请回头仔细想一下我们做了什么:
-
为了显示某个对象的详情,我们定义了一个针对该对象的详情显示界面
-
为了将对象的详细信息显示出来,所以我们定义了该详情界面的prepareDisp事件响应函数,用来在加载完该界面后,从数据库中读取相应的数据对象,然后用该数据对象的属性对详情界面进行初始化
-
前面讲过,我们的任何操作都需要一个入口,所以我们还需要为详情界面准备一个入口,由于查看详情查看的是listDemoData表中的每行数据的详情,所以其入口只能依附在该表中,所以我们又在listDemoDatat1中增加了一个op1列,专门用于放置查看详情的入口。
此外,dispDemoData的prepareDisp函数是如何知道自己应该显示哪个对象的详情呢?!这就用到了我们开始藏起来的那个ID列了,require属性就是用来给dispDemoData操作准备参数的,我们这个指定了其只有一个参数,参数名是ID,由于本行中恰好有一列的列名就叫做ID,jxTMS就会取该列的值作为参数送给dispDemoData函数。
数据加工
我们上面是直接将数据库中的数据显示出来,但如果需要显示加工后的数据该怎么办呢?比如,年纪超过70,我们在列表显示时,想加一个特殊提醒等等。我们先对dispDemoData做下简单的修改:
web listDemoData type div;
web listDemoDatat1 bind tableTotalCount parent listDemoData type table title="demoData列表",width=900,pagination=true,query=search,queryParam={'listTable':'listDemoDatat1'};
with listDemoDatat1 col demoID head demoID hide=true;
with listDemoDatat1 col demoCreateTime head 创建时间 width=150;
with listDemoDatat1 col demoType head 类型 width=100;
with listDemoDatat1 col demoName head 名字 width=80;
with listDemoDatat1 col demoTypeName head 类型名字 width=180;
with listDemoDatat1 col demoNoUsed head 已删除 width=80;
with listDemoDatat1 col op1 head 显示详情 web n type a width=80,capaname='demo.demo1',motion=disp,
demand=dispDemoData,primary=true,text='查看',require=[{"paramName":"demoID"}];
可以看到,我们把每列的列名都加了个demo,这主要是我们编程时,最好给所有的名字都起的具有一定的业务含义,让大家一看就知道是干什么用的,这可以大幅度降低数量混用的可能性。此外还增加了一个demoTypeName的列。
注:由于我们把ID改成了demoID,所以大家仔细看一下最后一行op1的定义中,require的参数也必须跟着改
然后我们在capa.py函数中增加一个dispAffairInfo函数:
#json是listDemoDatat1数据表中的一行
#jo是数据库中demoData表中每一行所转换成的demoData数据对象
def dispAffairInfo(self,db,ctx,json, jo):
#将jo对象的ID属性值设置给demoID列
json.set("demoID", jo.ID)
json.set("demoCreateTime", jo.CreateTime)
json.set("demoType", utils.getMsg('{}-type',jo.Type))
json.set("demoName", utils.getMsg('{}-name',jo.Name))
#给demoTypeName列设置数据
json.set("demoTypeName", utils.getMsg('{}-{}',jo.Type,jo.Name))
json.set("demoNoUsed", jo.NoUsed)
上面我们在op1中把require的参数名改了,所以dispDemoData的prepareDisp事件响应函数也得跟着把输入参数名从ID改为demoID:
@myModule.event('prepareDisp', 'dispDemoData')
def dispDemoData(self, db, ctx):
dd = pyORM.getByID(db.getDBConn(),'demoData',self.getInput('demoID'))
self.setOutput('demoType',dd.Type)
self.setOutput('demoName',dd.Name)
将web、capa.py等文件文件按用sftp管理jxTMS的代码所述更新到/home/tms/codeDefine/demo/demo/demo1目录中。
然后执行一次热机刷新,点击快捷栏中的【演示->listDemoData】,看看显示效果。
在jxTMS中,以默认方式执行的数据表查询,在数据查询完毕后,准备提交到前端的时候,都会逐行调用dispAffairInfo函数对每一行输出都进行数据处理,如果没有重载dispAffairInfo函数的话,默认的dispAffairInfo函数只是简单的将jo这个数据对象的所有属性输出到json中。
而我们上面因为重载了dispAffairInfo函数,所以会把读取到的数据逐行调用上面的dispAffairInfo函数,而在我们的dispAffairInfo函数中,我们就可以对数据进行加工后再显示给用户了。
直接输出
大家应该看出来了,上面讲的查询输出,需要先转换为一个数据对象,然后再逐行调用dispAffairInfo函数进行数据加工,如果我们不需要数据加工,同时又想输出的数据列名都是demoType这样带有业务语义的,那能不能不要这么麻烦呢?
当然能,我们只要两步就可以了:
1、修改sql定义增加别名:
#所以请一定注意:相等是==,两个等号
sql listDemoData
from demoData as ta
select ta.ID as demoID,ta.CreateTime as demoCreateTime,ta.Type as demoType,ta.Name as demoName
where ta.Type=='test'
orderBy ta.CreateTime DESC;
2、修改op.py文件中的入口定义,增加一个resultType的参数:
@biz.Motion('demo.demo1','disp','listDemoData')
@biz.OPDescr
def op1(json):
json.setShortcut('演示'.decode('utf-8'),'listDemoData')
json.setParam('dispType','list').setParam('dataSource','demo.listDemoData')
json.setParam('resultType','json')
这样一来,jxTMS在查询出数据后,就不再把每行数据先转换为一个数据对象了,而是直接生成一个json行【就是dispAffairInfo函数的参数中的那个json】而不需要调用dispAffairInfo进行转换,最后汇集后发送到前端。这就非常省事而且效率更高。