Aurora实践 下载本文

Aurora实践

目录

目录 ...................................................................... 1 1典型界面 ................................................................ 3 1.1 一个简单的FORM-GRID程序概览 ...................................... 3

1.1.1 以“系统描述”为例 ................................................. 3 1.1.2 简析FORM ......................................................... 3 1.1.3重要属性BINDTARGET ................................................ 4 1.1.4简析GRID .......................................................... 5 1.1.5简述BM ............................................................ 7 1.1.6查询过程 .......................................................... 8 1.1.7新增和修改数据的保存 .............................................. 9 1.2单FORM录入 ........................................................... 9 1.3GRID多级联动 .......................................................... 9 1.3.1介绍GRID的多级联动 ............................................... 9 1.3.2GRID多级联动的查询 ............................................... 12 1.3.3头行保存的SVC写法 ............................................... 13 1.3.4头行保存的BM写法 ................................................ 15 1.4 FORM+GRID,头行一起保存 ............................................. 16 2客户端逻辑 ............................................................. 17 2.1页面元素的隐藏与显示 ................................................. 17 2.1.1纯JS方法隐藏一个组件 ............................................ 17 2.1.2隐藏和显示GRID中的某一列 ........................................ 17 2.1.3根据特定参数决定 ................................................. 17 2.2可变编辑器(GRID EDITORFUNCTION) ...................................... 18 2.3可输状态 ............................................................. 18 2.3.1硬编码方式的可输入状态 ........................................... 18 2.3.2通过JS控制可输入状态 ............................................ 19 2.4必输状态 ............................................................. 19 2.4.1硬编码方式的必输状态 ............................................. 19 2.4.2通过JS控制的必输状态 ............................................ 19 2.5 COMBO BOX二级联动 ................................................... 19 2.6动态设置LOV特性 ..................................................... 19 2.6.1设置LOV来源 ..................................................... 19 2.6.2设置LOV参数 ..................................................... 20 2.7对DATASET循环操作 ................................................... 20 2.7.1取RECORD数组的方法 .............................................. 20 2.7.2处理RECORD数组 .................................................. 20 3校验 ................................................................... 21 3.1常规客户端校验 ....................................................... 21

1

3.1.1必输字段校验 ..................................................... 21 3.1.2使用验证器校验 ................................................... 21 3.1.3根据头字段校验行字段 ............................................. 21 3.1.4根据行字段校验头字段 ............................................. 21 3.1.5通过AJAX执行SERVER端校验证 ..................................... 21 4 BM特性 ................................................................ 25 4.1查询 ................................................................. 25

4.1.1通过BASETABEL和FIELDS自动生成的查询 ............................ 25 4.1.2通过在BM中定义节点查询 ................... 26 4.1.3查询优先级 ....................................................... 28 4.2INSERT、UPDATE、DELETE ............................................... 28 4.2.1通过框架自动生成 ................................................. 28 4.2.2通过在BM中定义定义INSERT语句 ........... 29 4.2.3使用INSERT、UPDATE、DELETE需要注意的内容 ........................ 29 4.2.4对BATCH_UPDATE的解释 ............................................ 29 4.3自定义BM的SQL出错信息 .............................................. 30 4.4 多语言 .............................................................. 30 4.5 STANDARD WHO ........................................................ 30 4.6LOOKUP CODE .......................................................... 31 4.7执行动态SQL ......................................................... 31 5各种组件 ............................................................... 32 5.1 VBOX,HBOX .......................................................... 32 5.1.1VBOX .............................................................. 32 5.1.2HBOX .............................................................. 32 5.2 FORM布局 ............................................................ 33 5.2.1 FORM的显示效果 .................................................. 33 5.2.2 FORM的常用属性 .................................................. 33 5.3 AUTO COMPLETE ....................................................... 33 5.4 通过任意HTML模板布局 ............................................... 33 5.5 TREE ................................................................ 33 5.5.1 TREE的构建方法 .................................................. 33 5.5.2 TREE的树节点渲染 ................................................ 34 5.6TREEGRID ............................................................. 35 5.6.1 TREEGRID的构建方法 .............................................. 35 5.6.2 TREEGRID节点渲染方法 ............................................ 36 5.6 GRID列锁定(LOCK),复合表头 .......................................... 36 5.6.1锁定列 ........................................................... 36 5.6.2复合表头 ......................................................... 38 5.7 各种提示(SHOWMESSAGE,SHOWCONFIRM) ................................... 38 5.7.1 SHOWMESSAGE和SHOWCONFIRM ........................................ 38 5.8 TAB的用法 ........................................................... 40 5.8.1 TAB的使用 ....................................................... 40

2

1典型界面

在介绍实践内容之前,首先简单介绍一下Aurora框架的核心思想:

在web应用中,无论是用户向服务器提交的数据,还是服务器向用户返回的数据,都是具有一定含义的数据的集合。例如用户注册时可能要填写个人的基本信息、填写简历时需要填写工作经历、培训历程等,服务器向用户返回查询的航班信息等等,都是具有一定的含义的。这种数据的集合在Aurora框架中抽象为DataSet。在Aurora框架中,DataSet是web前端与服务器直接进行数据交换的介质,是Aurora框架前端AuroraUI中最核心的部分。

DataSet提供了对数据的操作和导航,对数据的操作会触发相应的事件(event),所有绑定(bind)到DataSet有UI组件会根据事件做出响应。

1.1 一个简单的form-grid程序概览

1.1.1 以“系统描述”为例

在HAP系统中,我们可以参考一下“系统描述”功能。(详情请参见下列清单)

一、 功能简述:用于程序页面的多语言,比如,当页面上有一条提示“查询条件”,

实际在编码时写入其对应的代码“HAP_QUERY_TITLE”,在实际运行时,会根据当前用户选择的local并配合程序中的code来唯一确定一条描述信息 二、 用到的页面文件(screen文件):sys_prompt.screen 三、 用到的业务模型文件(bm文件):sys_prompts.bm 四、 用到的数据库表:sys_prompts

五、 用到的数据库对象:sys_prompts_s(序列)

1.1.2 简析form

使用form,是为了提供一种类似于表单的界面,但其本身并没有提供任何与查询有关的

3

能力,使用form后,框架解析后生成的界面类似下图:

Form常见属性:

? column :表示了该表单每行有多少列,form中的组件当排满一行后会自动换行至下

一列。 ? width :表示了该表单的宽度,此属性可能会影响表单内控件的外观,当宽度较低时,

会产生意外的结果。

? title:如图中title所示。

? 未提到的属性信息,请参阅“Aurora Tag Documentation”文档

1.1.3重要属性bindTarget

在提到bindTarget属性时,首先先介绍一下Aurora框架页面端的基本编程概念。Aurora页面端采用数据和表示分离的思想,既页面端所有的数据均存放在Dataset(实际为一个js对象)中。Dataset中既存放有数据,又有该数据的附加信息,如对应字段是否必输,是否只读,还有内置的一些对数据的操作方法。

Dataset中可以有一条数据也可以有多条数据,这些数据的存在形式类似于数据表,可以认为dataset中有一张数据表,表中可以有一行或多行记录,这些记录被称作record。

页面中的许多数据元素要和一个dataSet进行绑定。比如,在一个form中输入查询条件,查询条件的输入控件又和一个dataset绑定,那么,这个查询条件就会以该输入组件的name属性为key,输入值为value绑定到此编辑器指定的dataSet上(准确的说是该dataset当前的record上)。sys_prompt.screen中对应查询的dataSet代码清单如下:

该dataset的声明较为简单,这里你只需要知道form中的查询控件是绑定到该dataset上即可。

再来看grid控件绑定的结果dataset 该dataset中所包含的信息较多,涉及到的属性讲解如下:

? autoQuery:值取boolean类型,默认为false。意为在页面加载完毕后是否自动进行

一次ajax方式的查询动作。

? selectable:表示查询结果是否可以被选中

4

? fetchAll:表示是否一次加载全部数据(不分页) ? pageSize:如果分页,每页的数据量 ? autoCount:显示结果计数

? queryDataSet:重要属性,指示查询时,用户可输入的查询条件来源。比如在此例中,

查询条件绑定的dataset称为A,结果grid绑定的dataset称为B,如果B的queryDataSet属性为A的ID,那么,当B调用其查询方法的时候,会将A中的数据取出作为附加的查询条件。

? queryUrl:指定了当前dataset查询数据时的url,其一般格式为:

${/request/@context_path}/autocrud/test.testbm/query?contractno=${/parameter/@contractno}

其一般可分成四部分:${/request/@context_path},取当前web应用的根路径,比如项目名配置为HAP,那么解析后便成为/HAP;autocrud,框架内置,调用框架处理增删改查的机制;test.testbm:前面的test指示bm的文件目录,从web-inf/classes/开始计算,本例中即为web-inf/classes/test/testbm.bm;query:指示该url对应的行为,目前总共有5个可用,query对应查询,insert对应新增,update对应更新,batch_update对循环应增删改,delete对应删除,execute可执行一个pl sql块。 ? model :此属性具有多重作用。首先,该属性值必须是一个bm文件路径(有关bm文

件的详细讲解内容,请参见本文档中介绍bm的部分,这里只是先做简单介绍),页面解析时,会对给定路径进行严格检查。当dataset中无queryUrl时,如果调用该dataset的query(),那么会尝试从指定bm文件自动生成查询语句;当dataset中无submitUrl时,如果调用该dataset的submit(),那么会尝试从指定的bm文件自动生成insert、update、delete语句。

? 其余未列出的属性见本文档DataSet详细介绍一节以及请参阅“Aurora Tag

Documentation”文档

此例中涉及到的grid中的子节点介绍如下:

? fields: field节点是对dataset中的字段的修饰。在上述代码中,字段prompt_code

被声明为“必填项”,当绑定在dataset上的控件有name=”prompt_code” 时,该控件既为必填项。同理,只读控制和其他控制均需在field中声明。

1.1.4简析grid

editorFunction=\/> 此例中涉及到的grid属性讲解如下

? bindTarget:说明其绑定的dataset。

? marginWidth、marginHeight:与页面布局有关的属性,详细请查阅HTML标准。 ? 未提到的属性信息,请参阅“Aurora Tag Documentation”文档

此例中涉及到的grid中的子节点介绍如下:

? toolbar:工具条,常用的有增加、保存、删除。此三按钮如果仅仅声明type属性,

则默认行为为调用绑定dataset的对应行为。 ? columns:数据列,说明要显示的结果列。

? name:显示的列名。比如当有结果名为user时,若name=”user”,则将值显示

在此列。

? sortable:表明可以按此列排序(当鼠标点击该列的标题时进行排序)。当此列

数据为子查询结果时不可用,否则会引发异常。

? editorFunction:指定一个处理函数,可以对数据的可编辑性进行控制。比如在

此例中,业务要求是当建立了一个prompt记录的时候,其code和语言类型均不可再被编辑。此属性对应的是一个js函数名,当业务逻辑允许该列修改数据时,可以在js中返回一个编辑器的ID,如果不允许修改,返回空即可。 function promptCodeEditFunction(record, name) { if (record.get('prompt_id')) { 6

return ''; } else { return 'sys_prompt_result_grid_upper_tf'; } } ? editors:编辑器。其子节点的类型指定编辑器的类型,id为该编辑器的id

1.1.5简述bm

Bm文件主要负责和数据库的交互,既可以是类似于hibernate一样对数据库结构进行映射,从映射中尝试自动生成增删改查语句,也可以自己写增删改查。一句话,bm文件主要是负责与数据库交互,增删改查和Ajax请求(需要和数据库交互)都要在bm中定义。具体信息,请参阅bm详解一节。

我们先把本例中的bm文件贴出来 7

本例中的bm文件,是对一张数据表的映射,从开头的baseTable=\alias=\可以看出来,对应的是sys_prompts表,同时取表别名为”f”。 节点下全是对数据库字段的映射,比如第一个prompt_id,在数据库中的数据类型为bigint,在java中的数据类型为Long。指示当前bm文件中对应表的主键是哪个字段,中的节点主要和查询条件有关,比如在此例中,我们从前台传过来一个名为prompt_code的参数,参数值为”HAP_QUERY”,当查询请求过来后,

prompt_code和query-field中的一个field对应,那么,就会按照后面queryOperator的规则拼接条件子句。要注意,如果query-field中声明的属性是 field,那么必须在上文中的节点中声明和field属性中相同的field节点。比如在此例中,,那么必须在中声明一个

name=\/>节点。如果传递过来的参数是需要拼接一个自己定义的查询条件,需要将query-field声明为如下形式:

节点下是对当前bm添加附加功能。比如是在该bm生成insert语句的时候自动加入序列,需要先声明,然后根据固定规则找到对应的序列。规则是:序列名=表名_s。在本例中,序列即为sys_prompts_s;

是在对数据表进行插入和更新的时候自动对4个字段(新建日,更新日,插入者,更新者)进行维护。

Bm文件可以尝试生成对应请求的操作,比如如果过来一个query请求,bm可以根据定义的field来尝试生成query语句,在此例中,如果页面发来一个query请求,并且携带一个参数prompt_code,参数值为“HAP_QUERY”生成的query语句为 select f.prompt_id, f.prompt_code, f.language, decode(f.language, 'U', 'English', '简体中文') as language_display, f.description from sys_prompts f where f.prompt_code = 'HAP_QUERY' 1.1.6查询过程

此例中,查询的过程简要分析如下: 首先,如果用户在查询条件中输入值,比如在“描述字段”中输入”HAP_QUERY”,

8

然后点击“查询”。查询按钮绑定的函数为 function queryPrompt() { $('sys_prompt_result_ds').query(); } 即:取到负责显示结果的dataset,然后调用其内置的query方法。注意这里是调用负责显示结果的dataset,而不是查询条件所绑定的dataset。将从查询dataset中取出用户填写的值,即为prompt_code:’HAP_QUERY’,作为附加的查询条件。同时,如果dataset没有指定queryUrl(其实际地址是请求一个bm的query行为),那么会尝试从指定的model中生成一个查询语句;如果指定了,则按照指定url提交查询请求,queryUrl的优先级高于从model中生成。同时将取到的查询参数传递过去。Bm文件接到查询请求后,尝试从field定义中生成查询语句,查询完毕后,会以json格式将查询结果组装好,发至页面端,dataset接收数据后即通知绑定组件进行数据显示。至此整个查询过程完毕。

1.1.7新增和修改数据的保存

在本例中,单击页面上的“新增”按钮,即在grid中新增了一行记录,填写完毕后单击“保存”,即调用dataset的submit()方法,将页面上更改过的行(包括新增的)以json格式传递到bm中,bm文件可以根据每行的状态来生成相应的sql语句。这里类似于查询,当dataset中声明了submitUrl时,调用dataset的submit方法是以此url为提交地址;如果没有声明,则尝试从model属性指定的地址来生成url。

1.2单form录入

思路:form中组件绑定一个dataset,在该dataset中声明一个submitUrl,在写完相应数据后,点击保存按钮,调用dataset的submit()即可。具体可参考HAP系统中“系统设置”下“用户定义”中的“用户新增”。

1.3grid多级联动

在实际需求中,也有一种很重要的结构,即头行结构。就是汇总信息存在头表,明细信息存在行表。比如HAP系统中有“代码维护”应用。比如现在系统中有一代码“COMPANY_TYPE”(公司类型),其下有四种类型:业务实体、汇总公司、合并公司、调整公司。则类型代码是存在sys_codes表中,该代码下的具体值存放在sys_code_values表中。我们现在就以该应用为例,讲解一下如何编写头行结构的增删改查。

1.3.1介绍grid的多级联动 我们先来看一下程序运行的界面:

9

当我们选中头表记录中的“科目类型”的时候,行表自动刷新数据

10

我们先来看这是怎么做到的。

fetchAll=\ queryUrl=\FIELD=code_value\> 在代码中看到,我们声明了两个dataset,一个是负责和头表数据交互的dataset:sys_code_result_ds,另一个是负责和行表数据交互的dataset: sys_code_ref_ds。同时在行表dataset上声明了一个重要属性:bandTarget=”sys_code_ref_ds”。

1.3.2Grid多级联动的查询

在头dataset上,我们声明了数据来源:

12

queryUrl=\,表明数据从sys_codes这个bm中获得,行dataset上,我们声明了

queryUrl=\ode_value\,表明了数据从sys_code_values这个bm中获得。当行dataset上声明了bandTarget=”sys_code_ref_ds”后,当头dataset中被选中的record的index发生改变时(在此应用中可以使简单的单击其他行),会自动将头的当前record中的所有数据当做行dataset的查询数据,进行一次行表的查询。这样,只要行表bm中有对应头记录的ID的条件子句时,就可以正确拼出查询sql。

1.3.3头行保存的svc写法

将头dataset的submitUrl声明为一个svc文件,在此例中,svc文件如下: 我们结合一次更新操作,来理解一下svc文件在这里的作用,界面 13

点击“保存”后的请求参数(已被格式化): _request_data : { \ : [ { \ : \, \ : \, \ : \, \ : \Emerson的测试code\, \ : [ { \ : \, \ : \优\, \ : \, \ : 1064, \ : \ }, { \ : \, \ : \良\, \ : \, \ : 1065, \ : \ }, { \ : \, \ : \中\, \ : \, \ : 1066, \ : \ }, { 14

\ : \, \ : \差\, \ : \, \ : 1067, \ : \ } ], \ : 1063, \ : \ } ] } 可以发现,我们提交过去的参数中又出现了个名为result_ds的json数组,其中正是我们在行表中填写的项。名字正是我们在行dataset中声明的bindName。 总体步骤是:

1、 在页面上写两个dataset,两个grid分别绑定上去; 2、 在行dataset上写属性bindTarget=“头dataset的ID”;bindName自行确定; 3、 将头dataset的submitUrl指向一个svc文件(切记提交时是提交头dataset); 4、 在svc文件中指明头数据的循环根路径; 5、 在svc文件中指明行数据的循环根路径;

6、 在行bm中,保存头表记录ID的字段,加入属性insertExpression insertExpression=\头表ID字段名}

详细代码请参见“HAP”系统中的“代码维护”功能。

1.3.4头行保存的bm写法

在BM中,通过

标签,可设置层级更新,例如:

15

这样,在对DEPT表进行批量更新时,每条DEPT主记录更新完毕后,会找当前主记录中名为

EMPLOYEE-LIST的下级记录集,并以testcase.HR.EMP为基础BM,对EMP表进行批量更新。输入参数的数据结构类似于:

如果要对多个detail表进行更新,那么在cascade-operations下面设置多条cascade-operation标记就可以了,没条对应一个detail表。 cascade-operation的属性: 属性 说明 inputPath detail记录在主记录中的访问路径 model detail记录对应的BM operations detail记录允许的操作,如insert,update,delete,execute等,用逗号分隔

1.4 Form+Grid,头行一起保存

方法其实和1.3中相同,只不过前一种的头dataset中有多条数据,此种情况中头dataset中只有一条数据而已。具体可参考1.3节。

16

2客户端逻辑

2.1页面元素的隐藏与显示

2.1.1纯js方法隐藏一个组件

可在需要隐藏的元素上声明id,再使用document.getElementById(id)取得组件,然后设置style属性display,none为隐藏,block为显示。代码示例如下 function hidetest() { var input = document.getElementById(\); input.style.display = \;// hide this element input.style.display = \;// } 2.1.2隐藏和显示grid中的某一列

取得grid(通过id),然后调用grid的hideColumn(column名)隐藏列,通过showColumn(column名)显示列: var grid = $(\); grid.hideColumn('testColumnName'); grid.showColumn('testColumnName'); 2.1.3根据特定参数决定

当需要根据某以参数决定显示与否的时候,采用如下结构。 ..... 需要注意的是,2.1.1和2.1.2中介绍的方法均是通过js来控制元素的可见性,但本小节中其实是如果满足了匹配值1,就将代码块1中的代码加入解析。如果不符合条件,则在浏览器端查看源代码时根本看不到不符合的内容。

17

2.2可变编辑器(grid editorFunction)

当有特殊需求时,比如在grid中,当前行为新增行时,行上的username列可以编辑,当保存后便不可编辑,实现步骤如下:

1、在grid的editors节点中加入一个编辑器,以textField为例 ………………

2、在目标column上声明属性editorFunction,指明一个函数: 3、编写js代码 function codeEditFunction(record, name) { if (record.isNew()) {//判断是否是新增行 return 'tf_editor';//是,返回编辑器ID } else { return '';//否,返回空 } } 2.3可输状态

2.3.1硬编码方式的可输入状态

比如在dataset ds中有绑定有控件username,在查看界面中是不可编辑的,操作步骤为: 1、在ds中的fields中声明子节点field,在field中声明属性 readOnly=”true” ………… 2、注意控件username必须绑定在该dataset上。 18

2.3.2通过js控制可输入状态

在实际需求中,也经常有某字段根据一些条件来调整其可输入与否的特性。这种可以通过js代码来控制:

var usernameField = record.getMeta().getField(\); usernameField.setReadOnly(true); 其中,record是当前正在操作的record(如果是form,可以认为是from中元素绑定的dataset的第一条record;如果是grid,则是高亮显示的行,默认选中第一行,然后随用户的操作改变)。

2.4必输状态

2.4.1硬编码方式的必输状态

同可输入状态一样,可在对应field上声明required=”true”。

2.4.2通过js控制的必输状态

同可输入状态一样,当取得字段对应的field对象后,调用setRequired(true)即可。 var usernameField = record.getMeta().getField(\); usernameField.setRequired(true); 2.5 combo box二级联动 2.6动态设置LOV特性

2.6.1设置lov来源 首先取得lov对应的field对象: var lovField = record.getMeta().getField(\); 然后有三种设置lov的方式 lovField.setLovModel(\model位置\); lovField.setLovService(\bm文件位置\); lovField.setLovUrl(\screen位置\); 19

2.6.2设置lov参数 首先先取得lov对应的field对象: var lovField = record.getMeta().getField(\); 然后通过 lovField.setLovPara('company_id', \); 这里就将lov中设置了一个默认的参数company_id,当点开lov时,此参数自动传入后台参数参与查询。此方法主要用于lov的联动,比如在汇率定义中,当用户选择了本币后,在选择外币时要将本币排除在结果列表外。

2.7对dataset循环操作

当遇到某些情况需要对dataset内的所有数据进行操作时,就要用到对dataset内容的循环操作。核心思想是将dataset中的所有record取出,循环处理每条record。

2.7.1取record数组的方法

常用的有两种方法,假如我们现在要取名为ds 的dataset中的record数组: var records=ds.getAll(); //取得该dataset下的所有record,返回一个js array对象。 var records=ds.getSelected();//取得所有用户选中的记录,返回一个js array对象。 2.7.2处理record数组

使用for循环遍历处理即可。比如要在每个选中的record中插入temp字段的值”Y”,处理过程如下: function test() { var ds = $(\);// 取得dataset对象 var records = ds.getSelected();// 取得record数组 for ( var i = 0; i < records.length; i++) { records[i].set(\, \); } } 20

3校验

3.1常规客户端校验

3.1.1必输字段校验

当在名为ds的dataset中有必输字段时,如果要对用户输入进行验证,既调用ds的validate()方法,即会对必输项进行校验。注意,该方法返回一个boolean值,如果有未填项,页面上会提示“校验不通过”来表示有未填项,并返回false,请根据返回值做进一步处理。

3.1.2使用验证器校验 3.1.3根据头字段校验行字段 3.1.4根据行字段校验头字段

3.1.5通过AJAX执行server端校验证

这是本框架中较为重要的一个技能,下面将详细介绍如何进行一次ajax校验 首先,介绍一个重要的框架内置js方法:Aurora.request。 Aurora.request({ url : url, params : para, opts : opts, success : function(response, options) { }, failure : function(response, options) { }, scope : scope }); 参数讲解:

? ? ? ?

url:处理请求的url,通常是一个bm地址 params:携带的参数,需为json格式数据 opts:没用过

success:成功后的回调方法,接受两个参数,一个是返回的json对象,另一个是

21

? failure:失败后的回调方法 ? scope:作用域

url参数有些讲究,我们先来分析一下url的结构,一个典型的url如下:

${/request/@context_path}/autocrud/sys.sys_testbm/execute 此url可以拆分成如下几部分:

? ${/request/@context_path}:取得应用的web根路径 ? autocrud:

? sys.sys_testbm:表示bm文件的位置,从web应用的web-inf/classes下开始查找,目录以“.”分

割,在此例中,该bm的位置是:web-inf/classes/sys/sys_testbm.bm。

? execute:调用bm的行为。当要执行一段pl sql块时,这里就声明为execute。同时,bm中要有如

下结构:

begin test_pkg.primary_position_flag_check(${@employee_id}, ${/session/@user_id} ); end; 在operation中声明 name=”execute”,和url最后的execute对应。

除了execute,还有update。这里详细说一下这些参数应该在什么时候使用: 框架内置的一种机制,当dataset中新增一条record时(调用ds的add方法),会自动将record中的一个_status属性设置为insert;同理,当有一条数据更改时,会将其设置为update。比如当新增一条记录后,数据提交给bm时,如果url最后声明为insert,则

我们现在来以“注册新用户时用户名是否重复”这一假设来讲解如何用ajax方式进行校验。 假设素材:

页面:sys_user_new.screen

Bm文件:sys_user_check.bm(在sys目录下) Pl sql包:sys_user_pkg

22

包内用到的过程:check_username( p_username varchar2 , p_resultcd out varcahr2);

首先,在screen文件中,通过Aurora.request方法进行ajax调用:

Aurora.request({ url : \, params : { user_name : 'AA' }, opts : opts, success : function(response, options) { var result_cd = response.result.result_cd; if (result_cd == 0) { //业务逻辑上出错 } else { } }, failure : function(response, options) { }, scope : scope }); //业务逻辑的成功 这里的用户名我们假设为AA,实际应用中我们应当从用户的实际输入获取。当执行到此js代码时,浏览器即向服务器发送一个请求。地址为url中声明的地址,参数为params。

我们再来看bm端 begin sys_user_pkg. check_username( ${@user_name} , ${@result_cd}); end; 23

首先bm中的要和url中的execute对应,这样才会正确找到这部分代码执行。其次,如果有out参数,必须在parameter节点中声明output=”true”,并且声明outputPath,这样,才可以在成功的回调函数中取得返回值。然后,主要就是调用过程处理相关逻辑。我们在这里规定,如果符合业务要求,返回1,如果不符合,返回0。当过程执行结束后,回到js的success回调函数那里。在页面端,如果要拿到返回值,通用的写法是 success : function(response, options) { var result_cd = response.result.result_cd; if (result_cd == 0) { //业务逻辑上出错 } else { } } //业务逻辑的成功 灰色部分只需要保持一致就可以,黄色部分只要和bm中传出参数名称保持一致就可以了。

在这里我们根据返回的状态来做进一步处理,这就是整个的校验过程。

24

4 bm特性

Bm文件既可以是对数据表的映射,也可以定义数据库操作。它是框架自定义命名空间属性的xml文件,基于单张数据库表的,通过框架自定义的一些节点和tag,来定义一般表达业务逻辑的逻辑的文件。

4.1查询

一个bm文件是对一张数据表进行映射时(即特点是根节点中声明有baseTable属性,同时在bm文件内声明有fields节点),我们暂时假设此bm文件名为testbm.bm,所在位置是web-inf/classes/test/testbm.bm,同时,当页面发出一个查询请求时(不带任何查询参数)

URL:${/request/@context_path}/autocrud/test.testbm/query}

从此url看出,请求的是该bm的query方法。 4.1.1通过baseTabel和fields自动生成的查询

如果该bm是对一张数据表(或多张表,以其中一张表为主表,通过bm中关联其他数据表的方法组织起来)的映射,那么框架会尝试从映射关系中生成查询语句 databaseType=\ datatype=\ name=\ prompt=\/> databaseType=\ datatype=\ name=\/> databaseType=\ datatype=\ name=\ prompt=\/> databaseType=\ datatype=\ name=\/> 25

该bm生成的sql语句为: select f.prompt_id, f.prompt_code, f.language, f.description from sys_prompts f 如果携带的有查询参数,那么会根据query-field节点中的对应项进行拼接。 4.1.2通过在bm中定义节点查询

有时候自动生成的query语句无法满足需求(比如有union子句时),这时就需要自行写query语句。具体方法如下: 26

我们按照此结构编写我们自己的query语句,其中需要说明的几点是:

? operation name=\:这里必须将name的值写为query,当一个查询请求过来时,才能正确找到我们写的sql

? #WHERE_CLAUSE#:这里是为了和query-field配合使用,当有附加查询条件过来时,如果和

query-field中的能匹配上,则要在sql语句拼接条件子句。由于这时我们自己编写的查询,要给框架指明条件子句要拼接到什么地方。

? :此节点下的子节点声明的内容,是在生成sql时无论如何都要拼接上的条

件子句,比如我们在expression 中写”1=1”,那么无论前面的sql如何,最终形成的sql语句中一定有 (and) 1=1 。

如果在没有任何附加查询条件的情况下,我们自己的sql本身就含有where子句(如表连接,默认查询条件等),需要特殊注意一下,我们不能写为如下形式:

#WHERE_CLAUSE# ]]> 这样的话,如果查询时有附加查询参数,那么会在#where_clause#处又拼接上where 关键字,导致错误。

解决办法有两种:

? 将默认就有的where子句写在data-filter里;

? 将自己写的查询语句做嵌套,如上例,我们改造成如下形式: 4.1.3查询优先级

如果在同一个bm中即符合可以自动生成查询sql的条件,又有自己书写的sql,那么,只会执行自行书写的bm。

4.2insert、update、delete

4.2.1通过框架自动生成

如果一个bm对应一张数据表,那么,可以自动生成对应的增删改语句。比如在HAP系统的“系统描述”功能中,当点击grid中的新增按钮时,会多出一行,当用户填写后点保存,会将数据传入bm,bm生成insert语句。

28

4.2.2通过在bm中定义定义insert语句

类似于查询,同样可以在bm文件中编写自己的insert语句。这里就不再赘述细节部分,和查询形式类似。

4.2.3使用insert、update、delete需要注意的内容

如果你希望不管什么时候都能够正确调用你自行书写的sql时,要时刻谨记以下内容: 之所以数据提交到后台,框架能够自动识别到底是新增还是修改还是删除,主要是有一个隐藏的参数来决定:_status。当在dataset上调用add()方法新增一行数据时(点“新增按钮”实际也是调用此方法),会在新生成的record中自动记录一个属性值 _status:insert。当一条记录有修改时,会自动修改此属性为update。当此记录传递到bm端时,bm靠此标记来确定到底应该调用什么行为。所以,如果你的dataset中没有新增的行,那么将数据传送到bm端时不会执行insert操作中的内容;同理可见update和delete。

4.2.4对batch_update的解释

当你的dataset中有多条数据有修改或新增时,最后点击“保存”按钮,会调用dataset的submit()方法。然后框架将dataset中所有修改过(包括新增)的record的数据组装成json格式传递到bm,submitUrl如下:

/hclc/autocrud/sys.sys_service/batch_update 经过捕获,我们了解到传输参数的结构大致如下(已经经过格式化): { \ : [ { \ : 2202, \ : \, \ : \, \ : \, \ : \, \ : \, \ : \请勿555\, \ : 1022, \ : \ }, { \ : \, \ : \, \ : \, \ : \, \ : \, \ : \, \ : 1024, 29

\ : \ }, { \ : \二恶\, \ : \, \ : \, \ : \, \ : \, \ : \心iol\, \ : 1025, \ : \ } ] } 可以看出,传输过去的json格式的数据中有三组数据,一条update,两条insert。

Batch_update是框架中的一种实现机制,使后台能够循环处理每条传递过来的数据,并且根据_status来判断该如何处理每条数据。

4.3自定义BM的SQL出错信息

在bm里可以捕获直接捕获数据库抛出的异常信息,比如在bm中插入数据的主键重复异常。 做法如下:

1. 在bm的根节点声明命名空间。xmlns:e=\2. 在bm中增加如下子元素。

handleClass=\

Code:代表数据库抛出的异常代码。如主键重复代码ORA-00001,写成1. Message:针对该错误的提示信息 。如主键重复。写成“机型重复”。

4.4 多语言 4.5 Standard who

每个表都有四个字段:创建人,创建时间,更新人,更新时间。有该节点后,框架会自动维护这四个字段的信息。前题是所有的dml操作都是非自定义的。如果是自己定义的操作,如写的plsql过程。那么在plsql过程里就要自己维护了。

30

4.6Lookup code

表示该属性的值需要通过其他字段信息来描述.

如status有两个值,1和-1,我们需要表示成正常和不正常。Status的lookupCode值是status_code.那么该属性值写上lookupCode=”status_code”就行了。Status_code的值是表示正常和不正常的代码。真正的正常和不正常的值的表示还需要配个lookupField属性, lookupField=” Status_code_description

4.7执行动态SQL

动态sql,就是根据传入的条件的不同,执行不同的sql语句得到不同的sql结果。 语法:excute immediate <动态sql> into <输出参数>。 如下例子:

begin

--执行行头校验,出错退出程序 for i in 1 .. 21 loop

v_sql := ' select a.attribute_' || i ||

' from fnd_interface_lines a where a.line_id = ' || xxx || '

order by a.header_id desc, a.line_id asc'; execute immediate v_sql into sss(i); end loop; exception

when others then null; end ;

本例是查询多个值放到数组sss(i)中。Sss的定义这里省略。Xxx代表变量参数。

在bm的自定义的操作中,即就是在operation节点中需要执行动态sql来完成你的逻辑。可仿照此例。

31

5各种组件

注:展示组件需要放到view标签中。

5.1 vbox,hbox

5.1.1vbox

box组件类似于html中的div标签,在页面上不做显示,用于控制其他组件的位置,相当于一个布局容器。

vBox组件在box组件的基础上添加了竖向排列的限制,在vBox中的组件全部纵向排列,相当于column恒等于1,因此不需要设置column属性限制列数。 例如:在screen文件中有如下代码:

按钮将纵向顺序排列,如下图: 5.1.2hbox

hBox在box组件的基础上添加了横向排列的限制,在hBox中的组件全部横向排列,相当于row属性恒等于1,因此不需要设置row属性,例如有如下代码:

按钮将横向排列,如下图:

32

5.2 form布局

5.2.1 form的显示效果

form在box的基础上多提供了一个title,代码如下:

5.2.2 form的常用属性

form的常用属性除了title外,还有width(宽),height(高),column(列数),row(行数)属性,下面的代码将创建一个宽300,高120,2行,2列的form。如图下:

5.3 Auto Complete 5.4 通过任意html模板布局

5.5 tree

5.5.1 tree的构建方法

tree用于构建一个树对象,通常用于构建菜单,或者复杂的机构层次,显示效果如下:

33

树中的每个节点都是所绑定的数据集(dataset)中每一条记录(record) 节点与节点之间的层次关系是通过tree标签的属性idField和parenFeild来联系的,idField属性指定的是record中用来表示该节点的唯一标识(ID)的字段(field)名,parentField属性指定的record中用来表示该节点的父节点的ID和field名。 Tree标签的属性displayField指定的record中用来表示节点文本信息的field名。 下面的代码将构建一个简单的树。

树的显示效果如下图:

5.5.2 tree的树节点渲染

通过节点渲染,我们可以为树节点添加超链接。在tree标签中指定renderer渲染函数实现。

代码如下:

34

在tree标签中添加rederer属性,指定treeRecnderer函数渲染连接,渲染函数获取url,指定连接到相应的url。下表为渲染函数 return ''+text+''; return text; }else{ 显示效果如下图:

节点的颜色变为超链接的颜色,点击后可以连接到相应的url页面。

5.6treeGrid

5.6.1 treeGrid的构建方法

和tree类似,treeGrid需要指定父节点,显示的字段,和当前节点ID。但同时也集成了grid的一些特性,可以通过columns标签指定多个显示域,实例代码如下: 显示效果如下: 35

5.6.2 treeGrid节点渲染方法

treeGrid通过使用editors标签渲染节点,修改代码如下: 显示效果如下图:

5.6 grid列锁定(lock),复合表头

在实际需求中,有时候需要在grid的显示上做一些特殊的处理,目前我们已知的有两种特殊的需求:锁定grid中的某一列,以便在拖动grid上的横向滚动条(如果存在)时,被锁定的列始终保持固定在列表的最左侧;另一种是将一行表头分为多行,以起到合并同类项的效果

5.6.1锁定列

我们首先来看一下锁定列的效果,如下图,我们在查询结果中锁定“概算书编号”这一列,其余列不做特殊处理,效果如图:

36

1锁定列效果1

2锁定列效果2

实现方法:

在需要锁定的column上加入lock=”true”属性。 ………… 37

5.6.2复合表头

若要实现如下形式的表头

可以将需要组合的列用column组合

组合的层数没有限制,可以根据需求组合出各种复杂的结构。

5.7 各种提示(showmessage,showconfirm)

5.7.1 showmessage和showconfirm

代码如下,showmessage只有一个确认按钮,而showconfirm可以选择确定或者取消,点击按钮后可以执行参数相应的回调函数。

function drop(){ if(true){ Aurora.showMessage('title','messages'); }else{ Var fc=Aurora.showConfirm('标题','消息内容',function(){ 38

Aelrt(‘1’); Fc.close();}); } } 显示效果如下: Showmessage的显示效果

showConfirm的显示效果

点击确定后显示:

需要注意的是,框架中的showconfirm和基本js的confirm不同,框架中的确认框起不到阻塞作用,而基本js可以。示例如下: function testConfirm() { var result = false; var comfirm = Aurora.showConfirm('title', '确定提交?', function() { //点“是”后的回调 result = true; }, function() { //点“否”后的回调 39

result = false; }, null, 100); return result; } 现给出情景如下:出现确认框后,当用户点击“是”的时候,请判断该函数返回的结果是true还是false?

如果用户无法用比程序顺序执行的速度还要快的速度去点击“是”的话,那么不论用户点什么按钮,始终返回的是false。

因为框架中的确认框是非阻塞性的,在给出确认框的同时,程序顺序执行到下一步,即return结果。

5.8 tab的用法

5.8.1 tab的使用

在screen文件中我们通过标签来定义tab的一个对象容器,用标签定义每一个tab对象。实例代码如下,见hap的welcome.screen文件。TabPanel标签下定义了tabs标签,tabs标签中的每个tab标签即一个标签页。Tab标签的属性prompt定义了标签的标题,selected属性定义了标签页是否被选中。 Tab标签下可以直接编写screen标签代码,也可以通过属性ref指定引用screen页面的路径,引用页面是延迟加载的,只有当页面被选中时,才会首次加载。

显示效果如下图: 40

如未指定selected属性,则默认为第一个tab页为选中状态。

41