1、NCV5新查询模板技术红皮书新查询模板技术红皮书NC-UAP 5.3用友NC-UAP2018-09-23目 录第一章 前言 1第二章 设计介绍 31. 模型 32. 默认编辑器及扩展机制 43. 查询模板与数据权限 7第三章 开发说明 101. 如何调用 101.1 原先自己实现了查询对话框情况 101.2 没有自己写的查询模板的单据 111.3 常用条件Panel的使用 111.4 多公司的数据权限控制 122. FAQ 12附录 161. 查询模板中的条件表中的各字段值的意义 16第一章 前言查询模板的功能比较单纯,用一句话概况就是,接受用户的输入,构造SQL语句的Where条件。另外还可
2、以通过设置固定条件和启用数据权限实现对用户的所能查询的数据做一定的限制。V53对查询模板重新做了设计(以下称新查询模板)准备逐步替换原来的查询模板(以下称老查询模板)。老查询模板主要存在问题是1.操作不方便,不够直观,尤其是在定义复杂条件时。2.无法支持对括号的嵌套,无法支持一些复杂条件,比如 A and (B or (C and D)图 1 老查询模板新版查询模板较之旧查询模板明显优点:(1)新查询模板设计了“普通”和“高级”两个视图,分别针对简单条件和复杂条件的编辑。普通视图采用Form形式,使简单条件(查询条件都是And联接)的录入更方便。高级视图采用了类似ClearQuest的树形查询
3、编辑器的形式,避免了括号的输入,使得复杂条件的设置比老查询模板要简单和直观。图 2 普通视图图 3 高级视图(2)增加了Between操作符,可以替换各产品组定制的常用条件的“从到”类条件。增强了等于操作符,使其能支持多选(相当把原来的等于和in操作符合成一个了,单独的in操作符仍然支持),这样可以消除实际操作时对“或者(or)”操作符的需要,加强了常规视图的实用性。第二章 设计介绍1. 模型查询模板最终形成的Where条件总是由若干个相对独立的小条件通过and和or操作符组合合成的。比如:部门=生产部 and (人员编码=P0001 or 人员编码=P0003)。在新查询模板中,这样每个独立
4、的小条件由一个IFilter接口来描述。IFilter又分成三个组成部分,元信息(IFilterMeta),操作符(IOperator),和字段取值(IFieldValue)。图 1 IFilter 类结构图FilterMeta(IFilterMeta的在查询模板中的默认实现)描述了条件字段的元信息,相当于老查询模板的QueryConditionVO。FilterMeta目前实际就是通过把QueryConditionVO进行转换操作后生成的,以后有可能从单据元数据生成。IOperator接口是对操作符的抽象。IFileldValue接口是对字段取值的抽象,它实际只有一个方法,即返回一个IFie
5、ldValueElement的集合。IFieldValueElement是对一个“原子”值的抽象,实际可能是描述了一个整数,或者是一个枚举值,或者是参照返回值。整个的Where条件就可以看成由and, or操作符以及IFilter形成的一棵树,在新查询模板中以QueryTree来描述。前面举的例子,表示成树的形式就如下图所示。图 2 Where条件树不论是高级视图还是常规视图,其内部都是用QueryTree来组织单个的IFilter的。QueryTree及相关类结构图如图 3所示图 3 QueryTree相关类结构图2. 默认编辑器及扩展机制基于前面的模型,查询模板从功能上就可以理解为一个是能
6、对QueryTree和IFilter进行编辑的编辑器。对QueryTree的编辑实际就是把IFilter看成最小的单元,提供一定的方法,让用户修改IFilter之间的与或关系。对于常规视图来说,用户不用关心,实际也不能修改,IFilter之间的与或关系。常规视图上的IFitler都是“与(AND)”的关系,用户不能修改,只能增加或删除IFilter。对于高级视图,用户可以则可以任意调整IFilter之间的与或关系,从而构造出复杂的查询条件。新查询模板对QueryTree的编辑没有设计扩展机制,因为对与或关系的编辑没有太多的特殊性需求,常规视图和高级视图已经能完全满足简单条件和复杂的条件的编辑了
7、。但是对于IFilter的编辑,往往是和具体的业务相关的,默认的编辑方式不一定能满足业务的要求。因此新查询模板针对这个问题重点做了设计,支持在不同层次上对IFilter编辑进行扩展。对IFilter进行编辑的编辑器被抽象为接口IFilterEditor,当查询模板需要一个IFilter的编辑器,即一个IFilterEditor实例时,会调用FilterEditorManager创建出一个。默认的情况下查询模板创建出来的是DefaultFilterEditor,如图 4所示。如果DefaultFilterEditor不能满足业务的需要,则可以按需定制符合要求的编辑器,并注册到FilterEdit
8、orManager中,即可实现对DefaultFilterEditor的替换。图 5展示了一个定制的FilterEditor,对于“经济类型”这样的枚举型字段,采用图示的编辑器可能更方便。图 4 DeafultFilterEditor图 5 定制的FilterEditor图 4中被红色线框框住的部分即是DefaultFilterEditor,它由三部分组成:左边是显示FilterMeta的Label控件,中间是供选择操作符的下拉框控件,右边被绿色线框框住的部分是对IFieldValue进行编辑的编辑器,抽象为IFieldValueEditor,默认情况下创建出来的是DefaultFieldVa
9、lueEditor,同DefaultFilterEditor一样,通过FieldValueEditorManager注册定制的编辑器,DefaultFieldValueEditor也是可以被替换的。如前文所述,IFieldValue是对IFieldValueElement包装,而DefaultFieldValueEditor实际上是对IFieldValueElementEditor的包装。DefaultFieldValueEditor包含了两个IFieldValueElementEditor的实例,根据用户所选择的操作符的不同会有不同的界面展现。图 4中选择的是“介于”操作符,它是一个接受2个
10、参数的操作符,因此DefaultFieldValueEditor把两个IFieldValueElementEditor都显示出来了。如果是其他情况,即操作符是接受0个,1个,任意多个参数时,DefaultFieldValueEditor总是显示一个IFieldValueElementEditor,但会根据操作符接受参数的个数,设置IFieldValueElementEditor是否允许多选。上面所描述的DefaultFieldValueEditor的行为如果符合业务的需要,那么你可以坦然接受它,反之则是定制你自己的IFieldValueEditor的时候了。在没替换DefaultFieldVa
11、lueEditor的情况下,用户在为某个查询条件选定一个部门,或者一个公司,或者一个人员,或者输入一个订单货品的数量,实际都是通过IFieldValueElementEditor进行的,而后者是通过IFieldValueElementEditorManager创建出来的,默认的情况下它又把这个任务委托给了DefaultFieldValueElementEditorFactory这个工厂类。这个工厂类根据注册在pub_query_condition的信息,主要是字段的数据类型等信息,生产出合适的IFieldValueElementEditor实例。同样地,这个过程也是可以根据需要扩展的,支持注册
12、定制的IFieldValueElementEditor。综上所述,新查询模板对IFilter的编辑,分别在IFilterEditor,IFieldValueEditor,IFieldValueElementEditor三个层次上提供了扩展机制,在实际使用时可以根据情况具体选择扩展方式。图 6是相关的类图,从中可以看到,这三个层次的扩展机制是完全相同的。都是由一个IXXEditor接口来表示编辑器,然后有一个IXXEditorFactory的工厂来负责创建编辑器,一个XXEditorManager来管理工厂。注册一个定制的编辑器,概况来讲可以分成三个步骤,1.提供一个实现了IXXEditor接口
13、的自定义编辑器2.提供一个相应的工厂类,负责生产该自定义编辑器3.把该工厂类注册到XXEditorManager中。关于如何注册,请参看开发说明有关章节!图 6 IFilter编辑器相关类图3. 查询模板与数据权限NC中需要控制数据权限的业务节点,对于查询操作的控制,即限制用户仅能查询到其有权限的数据,一般是通过查询模板来实现的。其原理是由查询模板在用户设置的查询条件后面自动附件数据权限相关的条件。举例来说,订单上有经销商(custom),存货(inv)等字段。现在需要限制某个用户仅能查询特定的经销商和特定的存货订单。用户A,其有权限的经销商为C1,C2,C3,其有权限的存货为I1,I2,I3
14、。那么当用户A对订单执行查询操作时,不论其设置的条件是什么查询模板都必须附加如下的SQL语句。(custom is null or custom in (C1,C2,C3)and(inv is null or custom in (I1,I2,I3)当然对于订单来说,其经销商和存货字段一般都是不可为空的,上面的custom is null这样的条件有些多余,但如果对于其他可以为空的字段则必须加上这样的条件,否则则查询出来的结果可能是不完全的。另外实际查询模板拼接出来的sql不会象上面一样是用(C1,C2,C3)这样的形式枚举其有权限的数据而是一个有权限服务提供一个子查询sql语句。实际的sql
15、是以下的形式bd_cubasdoc.pk_areacl is null OR bd_cubasdoc.pk_areacl in (select distinct power.resource_data_id from sm_power_areaclass power,sm_user u,sm_user_role urole where u.cuserid=0001SD100000000000UP and u.cuserid=urole.cuserid and urole.pk_corp=1001 and urole.pk_role=power.pk_role andpower.orgtypec
16、ode=1 and (power.pk_org=1001 or iscommon_power in(y,Y) )NC的权限不但和角色相关,和角色所属的组织也相关,即权限实际上描述了,角色,组织和资源之间的关系。在上面的例子里,忽略了多个组织的情况。因为一般情况下对一个单据的查询实际上有个隐含的限制条件,即查询当前角色所登录的组织(公司或者主体账簿)的单据。当要需要对多个组织的数据进行查询时,则数据权限的附件条件要比上面复杂许多。还是上面的例子,现在需要指出订单上还有一个字公司(pk_corp)字段,即表示订单是按照公司的组织维度来区分的。现在用户A有权限查询的公司为(O1,O2),并且对于公司
17、o1,其有权限的经销商为(C1,C2),有权限的存货为(I1,I2);对于公司o2,其有权限的经销商为(C2,C3),有权限的存货为(I2,I3)。那么用户A对公司o1和o2的数据进行查询时,需要附加的数据权限相关条件如下:( (pk_corp=o1 and (custom is null or custom in (C1,C2) and (inv is null or inv in (I1,I2) ) or (pk_corp=o2 and (custom is null or custom in (C2,C3) and (inv is null or inv in (I2,I3) ) 同样上
18、面的语句只是示意,实际的过程是对于每个公司都需要向权限服务获取字段custom和inv对应的数据权限子查询,然后组合成最终的条件。关于数据权限具体,参见开发说明之多公司的数据权限控制第三章 开发说明1. 如何调用1.1 原先自己实现了查询对话框情况旧的方式对应的新的方式nc.ui.pub.query.QueryConditionClient(含引用和继承 )getUIPanelNormal():得到常用条件Panel.getWhereSQL():获得查询对话框的SQLsetNormalShow; hideNormal():可见NormalPanelsetShowDefine; hideDefi
19、ne:可见用户自定义Panelnc.ui.querytemplate.QueryConditionDLGgetNormalPanelgetWhereSQLSetVisibleNormalPanel(boolean)SetVisibleUserDefPanel(boolean)setTemplateID(.)废弃,如果需要指定的templateid,只需要在传入的参数templateinfo中设置其templateid即可;如果确实外面想在show之前自己加载数据,可以调用方法initUIData代码样例:(A) 继承查询对话框样例代码可参见:nc.ui.trade.query.HYQueryC
20、onditionDLG该类只适用于UI工厂,产品组请勿继承和调用之,且参照之即可。(B)直接调用样例代码示例:TemplateInfo tempinfo = new TemplateInfo();tempinfo.setPk_Org(ClientEnvironment.getInstance().getCorporation().getPrimaryKey();tempinfo.setCurrentCorpPk(ClientEnvironment.getInstance().getCorporation().getPrimaryKey();tempinfo.setFunNode(getModu
21、leCode();tempinfo.setUserid(ClientEnvironment.getInstance().getUser().getPrimaryKey();queryDlg = new QueryConditionDLG(this, null, tempinfo);queryDlg.showModal(); 1.2 没有自己写的查询模板的单据采用与UI工厂原先类似的方法。只是把 nc.ui.trade.query.HYQueryDLG替换为nc.ui.trade.query.HYQueryConditionDLG.一般用UI工厂做的查询模板不需要考虑这个!1.3 常用条件Pan
22、el的使用1 简单得到并操作.常用条件Panel必须实现接口nc.ui.querytemplate.normalpanel.INormalQueryPanel。把常用条件Panel放上去有两方式:(1) 如果没有逻辑条件,直接通过QueryConditionDLG的构造子传进去。(2) 对于可能有的逻辑条件参见FAQ如何组织非查询条件现在只有一种方式:通过自己的构造子传入。对于逻辑条件的处理亦参见FAQ如何组织非查询条件(有修正)的得到2持久化保存问题如果要把对应的常用条件保存到我的收藏夹(即查询模板的个人历史保存)。则必须实现方法setNormalQueryObject和getNormalQ
23、ueryObject。反之do nothing.序列化的对象和字段不能为transient样例类如下:private class TestNormalPanel extends UIPanel implements INormalQueryPanel private UILabel label = new UILabel(Fill the txt:); private UITextField txtField = new UITextField(30); public TestNormalPanel() super(); add(label); add(txtField); public JC
24、omponent getComponent() return this; public Object getNormalQueryObject() return txtField.getText(); public void setNormalQueryObject(Object qryObject) txtField.setText(qryObject=null?:String.valueOf(qryObject); 3.默认情况下 常用条件panel是不会显示的,所以欲显示之,则必须调用setVisibleNormalPanel(true).-含数据库级的逻辑条件的现实现在是不需要主动调用
25、setVisibleNormalPanle.因为平台是根据构造子里面传入的INormalPanel是否为空,来添加与否。 对于逻辑条件Panel,默认有就增加,没有也就不处理。(如果想自己处理逻辑条件)。1.4 多公司的数据权限控制1.单字段-即所有权限字段依赖于单一的字段(一对多关系)2.多字段-即不同的权限字段可能依赖于不同的字段(多对多关系)(一) 程序调用方法:在初始化查询界面时候设置之。(即在TemplateInfo中设置之)/step1:设置权限组织字段PowerCorrelationVO pcvo = new PowerCorrelationVO();pcvo.setOrgFie
26、ldcode(bd_cubasdoc.pk_corp1);/step2:设置被关联的字段pcvo.addCorrelatedFieldcode(bd_cumandoc.pk_resppsn1);pcvo.addCorrelatedFieldcode(bd_cumandoc.pk_respdept1);templateinfo.addPowerCorrlationVO(pcvo);/多字段PowerCorrelationVO pcvo2 = new PowerCorrelationVO();(同上)templateinfo.addPowerCorrlationVO(pcvo2);/调用查询界面构
27、造子2. FAQ关于废弃的旧的接口方法,如何又新的方法来实现原来的功能?有些新的功能如何实现?FAQ列表!1. 如何定制某个Field编辑后的响应事件?即原来的afterEditor方法?答:可以参照nc.ui.querytemplate.filtereditor.MultiCorpFilterEditor来实现一个Editor(继承DefaultFilterEditor,并注册对应的监听即可!),然后注册作为FilterEditorFactory注册到查询UI中。注意其不能触发别的FilterEditor,只能触发自己本身!如果想联动触发,参见FAQ如何设置组合Filter2. 如何定制自己
28、的编辑器,如非默认的“男女”的下拉框?答:这和FAQ3问题是同一性质,可以只不过返回的FieldValueElementEditor不同而已UIComboBox combo = new UIComboBox();combo.addItem(null);combo.addItem(new DefaultConstEnum(UFBoolean.TRUE,”男”);/TODO i18ncombo.addItem(new DefaultConstEnum(UFBoolean.FALSE,”女”);/i18ne = new DefaultFieldValueElementEditor(combo);3.
29、 如何给特定的查询的参照,设置过滤条件?答:可以参照nc.ui.querytemplate.QueryConditionEditor,main方法中注册“部门档案”的方法去注册一个registerFieldValueEelementEditorFactory即可。在其中可以自己去设置条件。示例代码如下m_queryDlg.registerFieldValueEelementEditorFactory(new IFieldValueElementEditorFactory() public IFieldValueElementEditor createFieldValueElementEdito
30、r(FilterMeta meta) if (pub_systemplate.operator.equals(meta.getFieldCode() UIRefPane refPane = new UIRefpaneCreator(m_queryDlg.getQueryContext().createUIRefPane(meta);refPane.setWhereString( pk_corp= + getCurrPK_corp() + );return new RefElementEditor(refPane, meta.getReturnType(); return null; );4,如
31、何在程序中动态地处理查询条件呢?答:其可能应用的有两种情况。(1)在数据库中模板数据基础上 .过滤,修改(如自定义项的处理),增加查询条件。需要注册一个模板VO处理器。然后具体调用示例代码qryDlg.registerQueryTemplateTotalVOProceeor(newIQueryTemplateTotalVOProcessor() public void processQueryTempletTotalVO(QueryTempletTotalVO totalVO) /here,do what you want to do.Note: totalVO is a reference
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1