Wabacus 框架开发指南(二)


第 1 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> Wabacus 框架开发指南(二) 作者:星星 二○一二年四月十七日 第 2 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 一、 常用功能配置 1.1 页面拦截器 页面拦截器是对整个页面进行拦截器,可以在页面初始前执行动作,也可以在整个页面显示 完后执行动作,用户可以根据需要在这两个时机加入自己的执行逻辑,完成某些功能,比如常前 的就是授权功能。 1.1.1 页面拦截器分类 页面拦截器根据作用范围及定义位置分为两种:全局拦截器和页面自己的拦截器 全局页面拦截器 全局页面拦截器定义在系统级配置文件 wabacus.cfg.xml 的标签中,每个 全局拦截器定义在此标签的一个子标签中。 标签包括如下属性:  class 属性:此全局页面拦截器对庆的实现类的全限定类名;  pageid 属性:此全局拦截器需要匹配哪些页面 ID,只有页面 id 值与这里定义的 pageid 匹配的页面才会被此拦截器拦截,否则不会被它拦截,也就是显示此页面前后都不会调 用拦截器的相应接口方法。 pageid 的配置方式有两种,由下面的 matchmode 属性决定,具体请看这个属性的介 绍。  matchmode 属性:指定上面 pageid 属性的匹配模式,包括两种:  如果配置为“regex”,则采用正则表达式匹配页面 ID,此时上面的 pageid 属性配置 为一正则表达式,只有与此正则表达式匹配的页面 ID 才会被这个全局拦截器拦截;  如果没指定此属性或指定为其它任意值,则采用直接匹配,即只有与 pageid 属性完 全相等(通过 equals()比较)的页面 ID 才会被这个全局拦截器拦截,不过此时 pageid 属性支持配置多个页面 ID,用分号分隔,页面 ID 只要与其中任意一个相等就算匹 配,对应的页面在显示时就会被此拦截器拦截。 如果没有配置 pageid 属性,或配置为空,则与所有页面都匹配。 在 wabacus.cfg.xml 的标签中,可以配置任意多个全局拦截器,每个拦截 器都定义在一个独立的标签中,它们的执行顺序后面会介绍到。 例如: 上面依次定义了三个全局页面拦截器,第一个采用普通的匹配方式,只匹配页面 ID 为 page3_0_3 和 page3_0_4 的页面;第二个采用正则表达式匹配,只匹配页面 ID 满足正则表达式 (page3)(\S*?)的页面;第三个没有指定 pageid 属性,则匹配所有页面。 全局拦截器只能用 J AVA 类的方式实现,不能直接用标签配置。 第 3 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 页面私有拦截器 页面私有拦截器配置在标签的 interceptor 属性中(此时为 J AVA 类实现)或其 子标签中。 一个页面可以同时通过 interceptor 属性和子标签定义拦截器,它们在页面显示 时都将会拦截,并执行各自定义的方法。 interceptor 属性是通过指定拦截器 JAVA 类的全限定类名进行配置,在这里可以配置多个拦 截器,用分号“;”分隔。 子标签只能定义一个拦截器,拦截器的每个方法它都有一个相应的标签进行配 置,在其中可以定义拦截器类的 J AVA 代码。 不管是在的 interceptor 属性中,还是在子标签中定义的拦截器都将只被 这一个页面所有,不会拦截到其它页面。 1.1.2 页面拦截器实现 从上面的介绍中可以看出,页面拦截器有两种实现方式:开发拦截器类和通过拦截器标签进 行配置,其中全局拦截器和通过的 interceptor 属性配置的页面专有拦截器只能用 J AVA 类 的方式实现,而通过子标签配置的页面专有拦截器则是直接在配置文件中 配置拦截器代码,下面分别进行介绍。 通过JAVA类实现页面拦截器 不管是用作全局拦截器,还是用作某个页面专有拦截器,在用 J AVA 类实现时,方法都完全 一样,也就是说,一个 J AVA 类实现的页面拦截器,即可以把它配置到 wabacus.cfg.xml 中做为全 局拦截器使用,又可以将它配置给某一个页面做为此页面的专有拦截器。 所有 JAVA 类实现的拦截器都必须继承抽象类: com.wabacus.system.intercept.AbsPageInterceptor,然后实现其中的如下两个方法: public abstract void doStart(ReportRequest rrequest); public abstract void doEnd(ReportRequest rrequest); doStart()方法在页面初始化前调用,doEnd()方法在页面显示完后调用。每次刷新页面时,即 使刷新当前页面的某一个部分,比如本次只刷新此页面的一个从报表,也会执行此页面拦截器的 这两个方法,这对有些操作,比如授权非常有用。 下面给出一个 J AVA 类实现的页面拦截器代码: public class Interceptor2 extends AbsPageInterceptor { public void doStart(ReportRequest rrequest) { String pageid=rrequest.getPagebean().getId();//取到当前拦截的 页面id String sql="select * from tbl_permissions where pageid='"+pageid+"'";//取到为此页面类型在tbl_permissions表中定义的所有 权限 Connection conn=rrequest.getConnection(); Statement stmt=null; try { stmt=conn.createStatement(); 第 4 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> ResultSet rs=stmt.executeQuery(sql); while(rs.next()) {//对取到的每个权限定义进行授权 rrequest.authorize(rs.getString("componentid"),rs.getString("part type"),rs.getString("partid"),rs.getString("permissiontype"),rs.g etString("permissionvalue")); } rs.close(); }catch(SQLException e) { e.printStackTrace(); }finally { //关闭stmt,不用关闭conn } } public void doEnd(ReportRequest rrequest) { } } 上面的拦截器只实现了 doStart()方法,没有实现 doEnd()方法。 在配置文件中配置页面拦截器 页面专有拦截器除了可以在的 interceptor 属性配置 J AVA 类,还可以通过其子标签 进行定义,不过这里只能定义一个拦截器。它包括三个子标签: 子标签:导入拦截器前后置动作要用到的外部包; 定义前置动作,对应 J AVA 类实现的 doStart()方法; 定义后置动作,对应 J AVA 类实现的 doEnd()方法。 上面三个子标签的使用与报表拦截器完全相同。 这种方式配置出来的拦截器与用 JAVA 类实现的拦截器完全相同,可以互换实现,不过执行 的顺序略有不同,在下一节将会讨论到。 例如上面用 J AVA 类实现的拦截器可以用配置文件配置如下所示: java.sql.* Connection conn=rrequest.getConnection(); Statement stmt=null; try { stmt=conn.createStatement(); ResultSet rs=stmt.executeQuery(sql); while(rs.next()) {//对取到的每个权限定义进行授权 rrequest.authorize(rs.getString("componentid"),rs.getString("part type"),rs.getString("partid"),rs.getString("permissiontype"),rs.g etString("permissionvalue")); } rs.close(); }catch(SQLException e) { e.printStackTrace(); }finally { //关闭stmt,不用关闭conn } ]]> 因为此拦截器没有提供后置动作,所以没有配置子标签。 1.1.3 页面拦截器执行顺序 上面已经介绍到,一个页面可能会被多个拦截器拦截到,因此理解各拦截器的 doStart()方法 和 doEnd()方法执行顺序非常重要,下面以一个示例来介绍定义在各位置上的拦截器的 doStart() 和 doEnd()方法的执行顺序。 假如在 wabacus.cfg.xml 中依次注册了如下三个全局拦截器: 然后某个页面的拦截器配置如下所示: ............... 第 6 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面页面定义了三个私有拦截器,其中通过 interceptor 属性定义了 D 和 E 两个 J AVA 类实现 的拦截器,通过属性定义了一个拦截器,假设名字为 F 访问此页面时,两个方法的执行顺序如下所示: doStart()方法执行顺序:A―――>B―――>C―――>D―――>E―――>F doEnd()方法的执行顺序为:F―――>E―――>D―――>C―――>B―――>A 1.2 报表继承 1.2.1 概述 为了简化报表的配置,如果新配置的报表与已有的某报表很多地方相似,框架支持通过让 新报表继承已有报表的方式进行配置,然后在新报表中只配置那些与父报表不同的地方,覆盖掉 父报表在这些地方的配置。这样就可以减少冗余配置,提高了报表的配置效率及配置文件的可维 护性。 针对继承的父子报表,有如下四个特点: 1、 子报表可以与父报表配置在同一个报表配置文件中,也可以配置在不同的报表配 置文件中; 2、 子报表可以配置在父报表之前,也可以配置在父报表之后。 3、 报表间的继承层数没有限制。比如 A 报表继承 B 报表,B 报表又是继承 C 报表, C 报表又是继承 D 报表等等。 4、 报表继承关系不能出现循环继承,即不能 A 报表继承 B 报表,B 报表继承 C 报 表,然后 C 报表又继承 A 报表。这样会导致报表加载失败。 1.2.2 配置继承报表步骤 当 A 报表继承 B 报表时,配置 A 报表的步骤包括如下几步: 1、 将 A 报表的标签的 extends 属性配置为 B 报表的页面 id+“.”+B 报表的 报表 id。 2、 A 报表的标签中除 id 之外的其它所有属性,如果想重用 B 报表的配置, 则均不需配置。只有想覆盖掉 B 报表的配置值的配置属性才需在 A 报表的 标签中显式配置。 3、 如果 A 报表的四个标签中的任意一个 标签上的某个配置项(包括其子标签的配置项)与 B 报表对应标签有所不同,则 要在 A 报表中重新配置自己的相应标签。 比如,以标签为例,只有 A 报表的标签下所有配置项(包括 标签上的所有配置属性以及其子标签的配置数量、顺序以及每个上 的配置属性)都与 B 报表相同时,才不用配置自己的标签,直接用 B 报表的即 可,否则就必须重新配置自己的标签,覆盖掉 B 报表中关于的配置。 其它三个标签道理也与此相同。 4、 如果 A 报表的拦截器配置与 B 报表保持一致(即都需配置拦截器且拦截器代码完 第 7 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 全相同或都不需配置拦截器),则不用在 A 报表配置自己的拦截器,否则就需要 在 A 报表配置自己的拦截器。 这里有两个情况需要着重说明: 1)、如 果 B报表配置了拦截器(不管是使用的interceptor属性还是 子标签),同时 A 报表不需要拦截器,则需将 A 报表标签的 interceptor 属性显式 配置为空字符串,即配置为 interceptor=””,覆盖掉 B 报表的拦截器配置。 2)、如果 B 报表是通过的 interceptor 属性配置了拦截器,则如果 A 报表想覆 盖掉 B 报表的拦截器而配置自己的拦截器,则 A 报表的拦截器配置必须也通过 的 interceptor 属性进行配置,而不能通过属性进行配置,否则覆盖不起作用。 1.2.3 示例 假设一个报表配置如下所示: 第 8 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> com.wabacus.system.format com.wabacus.util " + code + ""; } gm = FormatTools.formatLong(gm,"##,###"); rq=FormatTools.substring(rq,0,10); if (ShowDate == null) ShowDate = ""; ]]> 此报表显示效果如下图所示: 现在要配置一个新报表,它与上面 simplepage3.report1 报表有如下几个地方不同:  不需要提供 Excel 下载功能;  数据标题行的“组 1”改名为“新组 1”; 第 9 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  “新组 1”包括三列:“名称”、“日期”、“数量” 其它地方与上面 simplepage3.report1 报表完全一样,包括加载数据的逻辑以及对显示字段的 格式化等等。 现在我们看它配置,如下所示: 可以看到,上面的报表配置非常简单,它与上面父报表 simplepage3.report1 的配置有如下不 同: 将标签的 extends 属性配置为上一报表即父报表的页面 ID+“.”+报表 ID,即 simplepage3.report1,表示是继承这个报表; 标签中只配置了 id 属性和 excel 属性,其它属性都共用父报表的。之所以配置 excel 属性是因为这个报表不需提供“下载 Excel”功能,所以显式地将其配置为 0。 标签因为有几个配置不一样,导致全部重新配置自己的标签,因为不能 部分覆盖这个标签。 标签与父报表完全相同,所以不需配置,直接重用父报表的。 下面我们看其显示效果,如下图所示: 第 10 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 可以看到上面三个红圈圈住的地方与上面父报表的显示不同。 现在我们再看一个示例, 需求:假设再新增一报表,显示效果与上面子报表 extendpages1.report1 完全一样,加载数 据的逻辑以及对显示字段的格式化也完全相同,不过增加一个查询条件,允许用户输入日期然后 根据日期字段进行搜索。 分析:因为这个报表与上面子报表 extendpages1.report1 完全相同,所以考虑从继承这个报 表开始配置。继承后标签和标签可以重用父报表 extendpages1.report1 的。因 为新增了一个查询条件,即在中增加了一个子标签,所以需要重新配置自己的 标签。 配置如下所示: 第 11 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 可以看出,它的 extends 属性配置为 extends="extendpages1.report1",即从继承这个 报表开始。因为显示效果和格式化逻辑与父报表完全相同,所以没有配置 标签,又因为在标签中增加了一个子标签,即增加了一个查询条件,所以整个 重新配置。此报表的显示效果与父报表完全相同,所以这里不给出显示效果图。 其实这个报表也可以从继承上面“simplepage3.report1”报表开始配置,不过因为差异比较 大,配置的代码就要相对比较多,即要重新配置自己的标签和标签,这样,继承 的意义可能就不会很大了。 如果从继承“simplepage3.report1”报表开始配置,则其配置代码如下所示: 第 12 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 可以看出,重新配置了自己的标签,只重用了父报表的标签配置 以及中的一些配置属性。 这里介绍的被继承的父报表都是定义在一层页面中,即其上只有一层,所以在extends 配置它们的路径时非常方便,只要配置为“页面 ID”+“.”+“报表 ID”即可。在《Wabacus 框 架高级开发指南》中,我们还将介绍页面类型嵌套,这样,被继承的父报表可能是被定义在嵌套 N 层的子页面中,如果要继承一个这种报表,在 extends 属性中配置父报表路径时就相对比较复 杂一些(具体配置方法可参看《Wabacus 框架高级开发指南》一书中的介绍),但差别也仅此而 已,其它配置规则与方法与这里介绍的继承方法完全一致。 1.3 查询条件配置 1.3.1 概述 对于查询报表数据的 SQL 语句,框架支持为它们配置动态查询条件,并且支持为查询条件 配置条件输入框,输入框的类型可以是框架内置的所有输入框类型(比如文本框、下拉框、复选 框、单选框等等),同时框架还支持用户自己提供条件输入框。 查询条件配置有两种方式: 一种是在 SQL 语句中指定占位符{#condition#},然后为每个查询条件配置 子标签,并在此子标签中配置条件表达式,条件表达式中以#data#做为此条件动态数 据的占位符,当本条件有数据时,就会以数据替换掉条件表达式中的#data#,然后再与其它 输入了条件值的的条件表达式用 and 组合在一起,拼凑成一个完整的条件表达式 替换到 SQL 语句中的占位符{#condition#}中做为条件进行查询。 另一种是将#name#(其中的 name 为某个查询条件的 name 属性)占位符放 入 SQL 语句的条件语句中,当此查询条件有值时将会用它的值替换掉 SQL 语句中的对应占 位符做为真正的条件进行查询。 一个查询条件即可以采用第一种方式,也可以采用第二种方式,也可以同时 采用第一种和第二种方式为 SQL 语句传入动态条件。 下面分别介绍这两种条件的配置方法。 1.3.2 在中配置条件表达式 这种配置动态条件的方式包括如下几步: 1、 在 SQL 语句中需要存放动态查询条件表达式的地方放入{#condition#}占位符 例如: 第 13 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 再比如: 等等。 2、 在查询条件的中配置子标签,在其中配置本条件表达式,其中以 #data#做为本条件数据的占位符。 例如: 当查询条件有数据时,将会用其数据替换掉其条件表达式中的#data#占位符,组成 真正的条件表达式。 3、 在运行时,所有配置了条件表达式的,如果传入了条件值,则将它们的条件 表达式通过 and 方式连接起来,替换掉 SQL 语句中的{#condition#}占位符做为动态条件 进行查询。 例如: 某个报表配置如下所示: '%#data#%')]]> 上面三个都配置了自己的条件表达式, 如果在运行时它们都没有传入条件值时,则查询数据的 SQL 语句为: SELECT no,name,sex,age,birthday,deptname FROM tbl_baseinfo A left join tbl_department B on A.deptno=B.deptno order by no 即将{#condition#}占位符去掉了,因为这里只有一个条件,所以把前面的 where 也 去掉了。 如果 txtno 的条件值为“001”, txtname 的的条件值为“吴”,则查询 数据的 SQL 语句为: SELECT no,name,sex,age,birthday,deptname FROM tbl_baseinfo A left join tbl_department B on A.deptno=B.deptno where no like '%001%' and (name like '%吴%' or ename like '%吴%') order by no 1.3.3 在SQL语句中指定条件表达式 这种指定条件的方式是直接在 SQL 语句中通过占位符#name#指定条件,其中 name 为某个查 询条件的 name 属性。 这种指定方式包括两种情况: 1)、如果此条件值为空时,它在 SQL 语句中相应的条件表达式要去掉,则在 SQL 语句 中用{}将它对应的条件表达式括住 2)、如果此条件值为空时其在 SQL 语句中对应的条件表达式不用去掉,直接将此空值 做为条件值进行查询,或者为此条件配置了默认值,即不可能出现为空值的情况,则此条件 所在的条件表达式不需用{}括住。 例如:某个报表的查询数据 SQL 语句配置如下所示: SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where {A.no not in(#txtgonghao#)} and {#condition#} and ({age <>#txtage#} or birthday between #txtStartDate# and #txtEndDate#) order by no 上面的 SQL 语句中,“txtgonghao”、“ txtage”、“ txtStartDate”、“ txtEndDate”为相应 的 name 属性。 第 15 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面的 SQL 语句表示: i. name 属性为“txtgonghao”的查询条件如果值为空时,则它对应的条件 表达式 A.no not in(#txtgonghao#)需要从 SQL 语句中去除,因此它所在的条件表达 式用{}括住 ii. name 属性为“txtage”的查询条件如果值为空时,则它对应的条件表达 式 age <>#txtage#需要从 SQL 语句中去除,因此它所在的条件表达式用{}括住 iii. name 属性为“txtStartDate”和“txtEndDate”的两个的查询条件不能为 空,因为为空时,这个短语就不合法,因此当这两个查询条件值为空时,需要给它 赋默认值,因为不会为空,因此这两个查询条件的表达式不需用{}括住。 注意:这个 SQL 语句中还指定了{#condition#}占位符,说明它也可以接受配置了条件表 达式的的动态条件值,即上面介绍的第一种指定条件值的方式配置动态条件。 注意:  一个可以同时配置子标签并在其中指定条件表达式和通过#name# 的方式在 SQL 语句中指定条件 比如上面的 txtgonghao 条件,它在 SQL 语句中指定了“{A.no not in(#txtgonghao#)}”,也可以同时为它配置子标签,指定其它条件表达式。 这样在运行时当 txtgonghao 条件有条件值时,一方面会传入 SQL 语句的“{A.no not in(#txtgonghao#)}”中,变为 A.no not in (条件值),另一方面又会替换掉其 中配置的条件表达式的#data#占位符,并将真替换后的条件表达式替换到 SQL 语句中的{#condition#}占位符中。  一个查询条件可以在 SQL 语句中对应多个占位符,如果它们放在连续的位置时,则可 以用一个{}将此查询条件对应的表达式括住, 例如: SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where {A.no not like ‘%#txtgonghao#%’ and A.name not like ‘%#txtgonghao#%’} and ........ 但要注意,如果当前报表是采用 preparedstatement 方式执行,且存在同一个查询条 件的值在这两个表达式中一个采用 like 进行匹配,一个没有采用 like 进行匹配,或者两 个都采用 like 进行匹配,但所用的%个数或位置不同,则不能将它们括在一个{}中,而 是要分两个{}分别括住,或者采用 Statement 方式执行查询。 例如上面的 SQL 语句假如是这种形式: SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where {A.no not in(#txtgonghao#) or A.name not like ‘%#txtgonghao#%’} and ...... 或者 SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where {A.no not like ‘%#txtgonghao#’ or A.name not like ‘%#txtgonghao#%’} and ...... 如果当前报表是采用 statement 方式执行,即的 type 配置为 statement,则不会有任 第 16 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 何问题,但如果是采用 preparedstatement 方式执行,则会报错,分别需要变成如下形式: SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where ({A.no not in(#txtgonghao#)} or {A.name not like ‘%#txtgonghao#%’}) and ...... 和 SELECT A.no,name,ename,sex,age,marriage FROM tbl_baseinfo A left join tbl_detailinfo B on A.no=B.no where ({A.no not like ‘%#txtgonghao#’} or {A.name not like ‘%#txtgonghao#%’}) and ...... 即各自用独立的{}括住,当成两个条件。虽然它们都是从 name 为 txtgonghao 的 中取条件值。  因为在 sql 语句中{、}、#三个符号是框架的关键符号,如果用户需要用到其中之一做为 普通字符,则需要在前面加上转义字符\,比如“\}”则会当成一个普通的}符号,“\#” 会当成一个普通的“#”符号,等等,\符号本身是不需要转义的。  如果某个的条件值是一个用户自己拼凑的条件表达式,想完整地做为一个条 件表达式传入 sql 语句中,则可以在 SQL 语句中这样指定它的占位符:{#name#},其中 的 name 即为查询条件的 name 属性。 注意,这里的 name 不能是“condition”,因为{#condition#}是一个专用的占位符, 表示所有配置了条件表达式组成的条件语句。 1.3.4 高级查询条件 高级查询条件是指可以为一个条件配置多个条件表达式、多个比较字段、多套条件输入框等 等,这种条件的配置只适用于采用第一种指定动态条件的方式,即在中指定条件表达 式的方式,不能用在通过#name#占位符在 SQL 语句中指定条件的查询条件中。 框架支持的高级查询条件包括如下几类: 为一个条件配置多个条件表达式 如果要为一个条件提供多个条件表达式的选择,则在中配置一个子标 签,然后在其中配置一个或多个子标签,每个对应一个条件表达式,用户在此条件的输 入框中输入条件值后,可以选中一个条件表达式做为条件进行查询。 标签有如下属性:  label:显示在条件表达式选择框前面的提示信息  inputbox:条件表达式选择框类型,可配置值为 selectbox 和 radiobox,分别表示下拉框和单选框,默 认为前者  labelstyleproperty:显示 label 的的样式字符串  valuestyleproperty:显示条件表达式选择框的样式字符串  left:离左边元素的距离,即左边距,这里只能配置为大于等于 0 的数,显示时会自动加上 px,即象 素  right:离右边元素的距离,即右边距,这里只能配置为大于等于 0 的数,显示时会自动加上 px,即 象素 下面的子标签包括如下两个属性:  id 属性:标识当前条件表达式,保持唯一  label 属性:当前条件表达式在下拉框或单选框的显示 label 第 17 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 标签可以直接配置条件表达式,也可以配置其它内容,后面会介绍。 例如,某个查询条件配置如下所示: ... #data#)]]> ....... 则其显示框如下图所示: 为一个条件配置多个比较字段 是指为每个条件表达式提供选择比较字段,如果提供了多个比较字段时,框架将会在前台显 示一个下拉框或单选框供用户选择当前用哪个字段进行比较 要为某个条件提供多个字段的选择功能,需要配置如下几步: 1) 在中配置一标签,声明要提供哪些字段供用户选择,它然后在其 下配置多个子标签,每个子标签配置一个比较字段的信息。 标签包括的属性与标签完全一样,每个属性的意义也完全一样。 标签包括 id 和 label 属性,与上面介绍的标签的属性意义完全一样。 2) 在配置标签时,不能在标签中直接配置条件表达式,而是要在其中为 每个配置一个相应的条件表达式,上面在中声明了多少个,在 中就要为它们一一配置一个条件表达式,中配置的通过 refid 属性与 中配置的对应起来,即前者的refid属性配置为对应的的id配置值。 如果有多个,则每个都要这样。 例如: 第 18 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面的因为在中只有一个,因此可以简化为如下配置: 这样框架会在前台提供下拉框/单选框,用户可以选择其中一个字段做为条件,在后台时框架 会用用户在条件输入框中输入的条件值放到此字段对应的条件表达式中,拼凑成查询条件放到 SQL 语句中。 此条件显示效果如下图所示: 上面是一个条件表达式,也可以是多个条件表达式,同时提供多个字段的选择功能,例如配置 如下所示: (name like '%#data#%') (ename like '%#data#%') (name not like '%#data#%') (ename not like '%#data#%') (name ='#data#') (ename ='#data#') 第 19 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 为一个条件显示多套条件输入框 如果一个查询条件提供了条件表达式选择功能或比较字段选择功能,则可以配置它显示多套 条件输入框,配置方法为将的 iterator 属性配置为大于 1 的数,iterator 配置为多少, 前台就会为它显示多少套条件输入框(之所以这里用“套”,是因为如果配置了条件表达式选择 功能或比较字段选择功能,则此查询条件就不是只显示一个查询条件输入框,还要显示相应的选 择框)。 例如: 这样,此查询条件会显示两套输入框,这两套输入框之间的逻辑关系默认为 and。开发人员 也可以指定为 or,或者指定为在 and 和 or 之间进行选择。 指定显示多套输入框之间的逻辑关系有两种途径:  通过的 innerlogic 属性指定 这种方式只能指定为 and 和 or 中的一种,且不会在前台显示它们是 and 还是 or 的关系,只是在运行 时拼凑查询条件的时候会用到这里指定的逻辑关系。  通过标签的子标签指定 包含的属性与上面介绍的完全一样,各属性的意义也完全一样。 在标签中,每个逻辑关系配置为一个子标签,标签有两个属性: id 属性:只能配置为 and 和 or 之一 label 属性:配置 and 或 or 对应的逻辑关系在前台显示的 label。 通过这种方式配置时,如果配置了两个,则会在前台提供一下拉框或单选框(根 据标签的 inputbox 属性决定)让用户选择当前条件采用哪种逻辑关系;如果中 只配置了一个,则在前台会显示当前的 label 出来,这是与的 innerlogic 属性 配置的不同的地方。 例如: 第 20 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 注意:  只有当一个条件配置了 iterator 为大于 1 的数时,innerlogic 属性和子标签配置才有意义, 否则配置没有意义;  如果一个查询条件的 iterator 大于 1,则不能将它与某列过滤功能进行绑定,即不能将某列的列过滤通 过 condition{name}方式绑定此查询条件;  当一个查询条件的 iterator 大于 1,则不能在动态模板中通过自定义标签为它定制输入框,必须用框架 提供的输入框  提供多个条件表达式或多个比较字段的条件可以定制查询条件输入框,但只能定制条件输入框,不能 定制它的条件表达式选择框和比较字段选择框,这两个框无论如何都是由框架自动生成 一个配置了多套条件输入框的查询条件显示效果如下图所示: 控制一个条件各种输入框的显示顺序 如果提供了条件表达式选择框(配置了 values/>标签)或者比较字段选择框(配置了 columns/> 标签)或者提供多个逻辑关系的选择框(即配置了)中的一个或多个,则一个条件会显 示多个输入框、即条件输入框、条件表达式选择框、比较字段选择框,逻辑关系选择框等等,它 们的显示顺序是如何控制的呢? 答案是根据它们的配置顺序进行控制,例如,某个如果配置如下所示: ... ... ...... 则它们显示顺序为:比较字段选择框、条件表达式选择框、逻辑关系选择框、条件输入框。 如果它配置如下所示: ...... 第 21 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> ... ... 则它们显示顺序为:条件关系选择框、比较字段选择框、条件输入框、条件表达式选择框。 其它依次类推。 不过有一点需要说明,如果条件输入框是文本框,大部分情况下是不会去配置标签,即如下 所示: ...... ... ... 此时相当于将配置在最后的位置,即显示顺序为:逻辑关系选择框、比较字段选择框、条件 表达式选择框、条件输入框。 1.4 列过滤功能 1.4.1 概述 此功能就是允许用户点击某列的数据标题时,弹出此列当前显示的所有不重复的数据的下 拉选项列表供用户选择,当用户选中某个/些数据选项后,报表就会按此数据进行过滤,只显示 出此列数据为被选取中的数据的记录。这个功能也称为列过滤功能。 此功能只对数据自动列表类型的报表起作用( 继承自 com.wabacus.system.reporttype.abstracttype.AbsListReportType 的报表类型),对细览报表无效。 列过滤分两种:  允许用户多选过滤项进行过滤,显示效果如下图所示: 第 22 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  只允许用户选中某一个选项进行过滤。 第 23 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 两种过滤方式配置方法下面会进行介绍 框架在标签中,提供了 filter 和 filterformat 两个属性配置列过滤功能。  filter 属性: 声明当前列需要列过滤功能,根据列过滤的不同类型,可配置如下几种类型的值:  false:表示此列不需要列过滤功能,这也是默认值,即没有配置 filter 或配置为空 字符串时,此列也不具有列过滤功能。  true:当前列具有列过滤功能,这种类型的列过滤功能能进行多选,也就是一次可以选 择多个过滤项进行过滤。  列运算表达式:与上面配置为 true 类似,表示该列具有多选列过滤功能,但这种配置方 式更为灵活,它能指定当前列在过滤时,所用的表达式。 如果配置为 true,列过滤构造的查询条件为 select col1,col2,col3...from (配置的 查询 SQL 语句) tbl where col2 in(选中的过滤数据列表),其中 col1、col2、col3 等为配 置的的 column 属性,选中的过滤数据列表都是通过 getString()方式来获取的,所 以这样拼凑的 SQL 语句对于整型、字符串类型等不带格式的字段类型没有问题,但对 于日期类型,通过 getString()取到的数据格式如果直接用 where col2 in(...)的方式来取 可能因为格式不同匹配不到,此时可以通过将 column 为 col2 的的 filter 属性配置 为一个针对 column 属性对应字段的一个运算表达式,使它与过滤选项数据列表保持同 样的格式,这样就能正确完成列过滤功能。 比如,对于 oracle 数据库,为了保持统一格式,可以将某个日期类型字段的 配置为,这样此列在列过 滤时就会将条件拼凑成如下所示: select col1 , col2 , col3...from ( 配置的查询 SQL 语句) tbl where to_char(col2,’yyyy-MM-dd’) in (选中的过滤数据列表) 除了通过将 filter 配置为对字段的运算表达式来使用数据库中的数据与选项列表中 的数据通过 in 能匹配,还可以修改选项数据列表,通过后面介绍的 filterformat 配置 的格式化方法可以做到,具体参考后面此属性的介绍。  condition{name}:这种方式配置的列过滤与某个查询条件关联,且只能对过滤选项进行 单选。其中 name 为查询条件对应的 name 属性。 与查询条件相关联的列过滤与相应的查询条件具有完全相同的行为,在此列进行 列过滤时,与在相应条件中进行查询效果完全相同。如果对应的查询条件与其它报表 的查询条件是关联的,则在此列进行列过滤时,有条件关联的报表也会利用它的值进 行查询。 比如有一个报表中,有“名称”这一列,且有一个查询条件是根据“名称”进行查 询,则可以将此“名称”列的列过滤功能与这个条件关联起来,即在“名称”列中进行 列过滤与在“名称”查询条件进行搜索时,效果完全等同,则将此列的 filter 属性配置 为 condition{name}格式,其中 name 为“名称”查询条件对应的的 name 属 性。 这种方式配置的列过滤只能一次选中一个选项进行过滤,这是因为查询条件只能一 次查一个条件,也就是说不能多选。 如果某个列过滤希望采用单选方式,但又没有为它提供查询条件,则可以为它配置 第 24 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 一个 hidden 为 1,即隐藏查询条件,然后将它的 filter 属性配置为 condition{name}方式。 如果某个列虽然有对应的查询条件,但想为它提供多选列过滤功能,则只要将它的 filter 属性配置为 true,即不与查询条件关联即可。  filterformat 属性: 如果某列的过滤选项中的数据需要做某种格式化显示,或者为了能与数据库中的相应字段 数据进行匹配,需要对过滤选项数据进行某种转换,则都可以通过此的 filterformat 属性配 置格式化方法。 filterformat 属性配置的方法是一个静态方法,它的签名为: public static String[] 方法名(ReportBean rbean,String[] values) {} 参数 rbean:当前报表的配置对象; 参数 value:过滤选项数据数组,存放本次取到的所有过滤选项数据。 返回值:针对 values 中每个字符串格式化后的结果字符串数组 如果要对过滤选项数据的显示进行格式化,则修改返回的 String[],如果需要对过滤数据进 行格式化转换,则直接修改参数 values 中的值。 这个方法必须出现在当前配置的 formatclass 类中或系统配置文件 wabacus.cfg.xml 的名为 format-class 类中。否则不会进行格式化。 只能配置一个列过滤方法。  filterwidth 属性: 配置列过滤选项窗口的宽度,默认为的宽度。 另外,当的 column 属性为{sequence}或{non-fromdb},即显示自动增长的序号列或不 从数据库中取数据时,则不允许配置 filter 属性,也就是说这两种类型的列不能提供列过滤功能; 在超级数据自动列表报表类型中,不能在标签中配置 filter 属性,配置了也不会有任何 作用。 1.4.2 示例 比如一个报表配置如下所示: 第 25 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面在“工号”、“名称”两列都有相应的查询条件,但工号是配置为与其对应的查询条件 关联,而名称,没有关联,它们过滤选项显示效果如下图所示: 可以看到,“工号”列只能单选,“姓名”列可以多选,因为它没有查询条件关联。 “年龄”列没有提供查询条件,但想让它只提供单选功能,所以配置了一个 hidden 为 1 的 隐藏查询条件,然后将此列的 filter 配置为 condition{txtage},这样它就能只能单了选了,并且为 它配置了一个对过滤选项进行格式化的方法,格式化方法代码如下所示: public static String[] formatAge(ReportBean rbean,String[] ages) { 第 26 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> if(ages==null||ages.length==0) return new String[0]; String[] results=new String[ages.length]; for(int i=0;i的宽 度,它的显示效果如下图所示: 第 27 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 每个过滤列都是取出当前查询条件(包括所有类型的查询条件,比如显示输入框的,隐藏 的,常量的等等的)对应的数据做为当前过滤列的所有过滤选项,也就是说在取某 个列的所有过滤选项数据时,会在 SQL 语句中带上所有中的条件数据。但不会带上 任何过滤列已选中的选项数据的做为查询条件。 每个列的选中数据为当前页面显示数据,即带上所有条件和所有列过滤选中的选项数据做 为查询条件。 1.5 列排序功能 1.5.1 概述 此功能是指允许用户点击数据自动列表报表某列标题时,能让报表数据根据此列的数据进 行顺序和倒序进行排序显示。此功能只对数据自动列表报表有效,对细览报表无效。 1.5.2 配置方法 配置列排序功能非常简单,只要将允许列排序功能的列的的 clickorderby 属性配置为 true 即可。这样此列就自动具备了点击列标题进行排序的功能。 注意:不能将不是从数据库取数据的列,即column 属性不是数据库字段的列配置clickorderby 属性为 true。比如行排序列、行选择列、sequence 列等,将它们的 clickorderby 属性配置为 true 也无效。 默认情况下,用户点击的列排序只对本次访问有效,关掉浏览器后下次再访问时,不会保留 用户本次点击的列排序效果,但框架提供了接口方法允许保存每个用户对某个报表的列排序效 第 28 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 果,这样此用户下次访问本报表时,仍能保留上次列排序的效果,关于这一部分的介绍,请参 看后面“保存用户个性化信息”一节的介绍。 1.6 报表分页显示 1.6.1 分页显示配置方法 对于用框架配置的所有类型的报表(包括数据自动列表报表和数据细览报表)都支持分页显 示的功能。配置方法都是通过的 pagesize 属性,如果某个报表没有配置此属性,则采用 系统配置文件 wabacus.cfg.xml 中 default-pagesize 配置项配置的值。 数据自动列表报表 对于数据自动列表报表,如果的 pagesize 配置为-1,则此报表不分页显示。如果配 置为大于 0 的数,则分页显示,每页显示的记录数即为 pagesize 配置值。 数据自动列表报表还支持为 pagesize 配置多个页大小,用“|”分隔,这样前台会提供页大 小选择下拉框,用户可以切换每页显示的记录数。 例如某个报表的 pagesize 配置为 pagesize=“5|10|-1|20”,则此报表翻页导航栏就会显示一个 包含这四个选项的下拉框,用户可以选中它们切换每页显示记录数。 另外,用户除了可以通过 pagesize 属性静态配置页大小,还可以在报表拦截器的前置动作或 访问报表的 URL 中动态指定页大小,指定方法如下所示: 在拦截器中指定: rrequest.setAttribute(“reportid_PAGESIZE”,”页大小”); 在 URL 中指定: & reportid_PAGESIZE=页大小 这里要说明一下 reportid,一般情况下,这里的 reportid 就是报表的 id,但如果当前 报表与其它报表进行翻页导航栏关联,即本报表的 navigate_reportid 属性配置为其它报 表,则这里要用 navigate_reportid 配置的值进行指定。 注意:如果一个报表静态配置为只不分页显示,(即 pagesize 配置为-1,不 包 括 pagesize 配置 为多个值中包括一个-1 的情况),则不能动态指定页大小为>0 的数,即不能动态指定为分页显示, 但如果静态配置为分页显示,可以动态指定为不分页显示,即允许动态指定页大小为-1。 数据细览报表 对于数据细览报表,框架也支持为它们配置分页显示的功能,如果将细览报表的的 pagesize 配置为 1、则此报表提供分页显示的功能,此时一页显示一条记录,有多少条记录就显 示多少页,也就是说页数和记录数相同;如果配置为其它任意值,则视为不分页显示,只会显示 查询出来符合条件的第一条记录。 因为细览报表一页只会显示一条记录,即页大小只会是 1,所以这种报表类型不支持为 pagesize 配置多个页大小的功能。 常用翻页导航功能 下面介绍一下实现翻页报表常用功能的方法,这里介绍的方法对数据自动列表报表和数据细 览报表都有效。  配置翻页导航栏关联 如果两个或多个报表共用一个翻页导航栏,在此翻页导航栏上进行翻页操作时,这几个报表 都切换到指定的页,则说这几个报表存在翻页导航栏关联。 第 29 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 要配置翻页导航栏关联,只需将关联报表的 navigate_reportid 属性配置为被关联报 表的 reportid。 例如有 reportid 分别为 A 和 B 的两个报表需要配置翻页导航栏关联功能,且要在 B 报表显示 翻页导航栏,则配置 A 报表的的 navigate_reportid 属性为 B 即可。 存在翻页导航栏的两个或多个报表必须保持页数永远相等,不管进行什么操作后都要相等, 否则无法正确翻页。 WabacusDemo 有翻页导航栏的演示。  动态指定显示页码 框架支持动态指定访问页码,即指定访问哪一页的数据,指定方式如下两种: 在拦截器中指定: rrequest.setAttribute(“reportid_DYNPAGENO”,”页码”); 在 URL 中指定: & reportid_DYNPAGENO=页码 说明:  这里的 reportid 与上面介绍的动态指定页大小的 reportid 意义一致,即如果本报表没有与 其它报表存在翻页导航栏关联,则就是本报表的 id,如果本报表在中 配置了 navigate_reportid ,即与其它报表存在翻页导航栏关联,则就指定为 navigate_reportid 配置值。  这里的参数名后缀是_DYNPAGENO,而不是_PAGENO,否则指定无效  指定的“页码”值即为要定位到哪一页的页码,从 1 开始,比如指定 &reportid_DYNPAGENO=1,则定位到第一页,指定&reportid_DYNPAGENO=3,则定 位到第 3 页,等等。 如果指定的页码大于总页数,则框架自动会定位到最后一页。 示例:希望访问 id 为 report1 的报表时,默认显示最后一页,而不是第一页。 实现方法一:在访问 URL 中加上 reoprt1_DYNPAGENO=999999 实现方法二:在拦截器的前置动作中通过如下代码实现: String mypageno=rrequest.getStringAttribute(“report1_PAGENO”,””);//取到当前报表所翻到的 页码 if(mypageno.equals(“”)) {//没有进行翻页操作 rrequest.setAttribute(“report1_DYNPAGENO”,”999999”); } 注意:在设置时,先要判断一下用户是否已经进行过翻页操作,如果进行过翻页操作,则根 据 report1_PAGENO 参数名就会取到当前显示的页码,如果没有取到,则设置默认页码为最后一 页。 1.6.2 翻页导航栏 翻页导航栏配置方法: 翻页导航栏通过静态模板实现,静态模板可以定义在资源文件中,此时资源项的 type 属性为 com.wabacus.config.resource.TemplateRes,也可以写在.htm 或.html 格式 的模板文件中,关于静态模板,请参看后面“静态模板”一节的介绍。 在翻页导航栏的静态模板中,可以使用下面“静态模板”中介绍的所有标签来定义显示内容, 第 30 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 最常用的是两个标签,前者用来显示各导航按钮和导航信息, 后者用来显示其它功能按钮。 在使用显示翻页导航按钮或导航信息时,必须为其指定 type 属性,因为 不指定 type 属性时,表示显示整个翻页导航栏,这样会出现死循环。 的 type 属性和意义如下所示: first:定义“首页”按钮显示信息,此时标签内容可指定按 钮、图片、文字,用于定义 “首页”链接的显示label previous:定义“上一页”按钮显示信息,此时标签内容可 指定按钮、图片、文字,用于定义 “上一页”链接的显示label next:定义“下一页”按钮显示信息,此时标签内容可配置 按钮、图片、文字,用于定义 “下一页”链接的显示label last:定义“尾页”按钮显示信息,此时标签内容可配置按 钮、图片、文字,用于定义 “尾页”链接的显示label 上面几个如果没有定义内容,则显示对应的图片,定义 的内容也可以从普通资源文件或国际化资源文件中取值,即定义成${key}或i18n{key}的形 式。 sequence:定义连续页按钮显示信息,显示一连串页码,类似于google/baidu等中间部 分。 此时,有如下几个专有属性: minlength属性:指定页码的最小长度,默认为1,页码显示为1、2、...;如果指定为 2,则页码会显示成01、02...;如果指定为3,则页码会显示成001、002、...011、012...; 等等。 initcount属性:指定显示的连续页码数,默认为5,即显示连续5个页码,可以指定为 任意大于等于0的数。 maxcount属性:指定显示的最大连续页码数,默认与initcount相等。如果指定的值大 于initcount属性,则效果与百度搜索的翻页效果类似,即刚进入页面时显示initcount个数 的页码,翻页时可以增加到maxcount个数的页码,当超过maxcount时,则保持maxcount个 页码。 标签内容: 指定当页码有链接时的显示字符串,以%PAGENO%做为页码的占位符。例如: [%PAGENO%],则有链接的页码显示为: [1]、[2]...。 [%PAGENO%],则有链接的页码 显示为:[1]、[2] 显示在文本框中:此时在里面改变了页码时,onblur后自动跳转到指定页,此时在其 ....等。 也就是说页码占位符%PAGENO%左右可以编写任意html代码。 默认即为%PAGENO%,即没有用任意html代码包括,显示纯页码。如果中只有html代码,没有%PAGENO%占位符,则此标签内容会被 忽略,只显示默认的%PAGENO%。 注意:对于当前页的页码,即不带有跳转链接的,永远只显示纯页码数字,不会受这 里标签内容的影响。 pageno:定义当前页显示信息,定义当前页显示信息,有三种显示形式: 只显示页码:此时不配置内容,或配置为text; 第 31 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 中配置textbox。 显示在下拉框中:此时会将所有页码显示在下拉框中,用户可以选中下拉框进行跳转, 此时在其中配置selectbox。 pagesize:定义页大小显示信息,显示配置的每页显示记录数,如果配置了多个,则提供 下拉框供用户切换它的页大小。其对应的标签内容会被忽略 recordcount:定义总记录数显示信息,其对应的标签内容 会被忽略 pagecount:定义总页数显示信息,其对应的标签内容会被 忽略。 为报表/表单指定翻页导航栏 1)、默认翻页导航栏: 在 wabacus 框架中,report.navigate.default 为全局默认翻页导航栏资源项的 KEY,并在自 带的系统资源文件 wabacus.resources.default.xml 中定义了此 KEY 的资源项做为项目中所有翻页 导航栏的默认显示信息,如果用户想在自己的项目中改变全局默认翻页导航栏显示信息,可以 直接修改这个资源项,也可以在自己的全局资源文件中定义一个 KEY 为 report.navigate.default 的资源项,在此资源项中定义导航栏要显示的静态模板,它将会覆盖框架自带的配置。 2)、单独指定翻页导航栏 在报表配置的中,有一个 navigate 属性,用于配置本报表/表单的翻页导航栏显示 信息,只有在当前报表不采用默认的导航栏时,比如想显示某个特定的功能按钮,可以利用此 属性配置翻页导航栏。 navigate 属性可配置如下几种类型的值:  普通资源文件中资源项的模板,即配置为${key}形式;  国际化资源文件中资源项的模板,即配置为 i18n{key}形式;  静态模板文件中的模板,即配置为 classpath{filepath} 、 absolute{filepath} 、 relative{filepath}三种形式之一。 另外,开发人员也可以在动态模板中使用上面的标签单独控制此报表的翻页导航信息显示。 1.7 动态选择显示列 动态选择列是指在客户端用户可以选择要显示或导出的列,这个功能对数据自动列表报表和 数据细览报表均有效,不过交叉统计报表除外,这种报表类型不提供列选择功能。 1.7.1 列的displaytype属性取值及意义  对于所有报表表单,的 displaytype 属性值及意义如下所示:  initial:如果本报表提供列选择功能,则开始访问时默认显示此列,但可以通过 列选择功能将它取消显示;如果本报表关闭列选择功能,则一直显示此列。此 值为默认值  optional:如果本报表提供列选择功能,则开始访问时不显示此列,但可以通过 列选择功能将它显示出来,如果本报表关闭列选择功能,则一直显示此列。  always:不管此报表有没有提供列选择功能,此列一直显示。  hidden:不管此报表有没有提供列选择功能,此列一直不显示 对于带列分组的数据自动列表报表,其没有 displaytype 属性,它的显示与不显 示由它所包括的所有子决定。 第 32 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 1.7.2 开启/关闭列选择功能 数据自动列表报表默认提供列选择功能,数据细览报表默认不提供列选择功能,但可以通过 如下方式来禁用或启用列选择功能:  在标签中有一个属性:colselect,对于列表报表,默认值为 true,对于细览报 表,默认值为 false,用户可以显式配置其值为 true 或 false,如果配置为 false 时,则当 前报表不提供列选择功能,此时 displaytype 为 initial、optional、always 的列都将显示出 来。只有 displaytype 为 hidden 的列不显示出来。  当一个报表配置的所有的 displaytype 均为 always 或 hidden,即没有配置值为 initial 和 optional 的列时,将不在客户端提供列选择框功能。  交叉统计报表均不提供列选择功能。 列选择框的宽度为 wabacus.cfg.xml 的 default-colselect-width 配置的默认宽度,每个报表还可 以通过标签的 colselect 属性指定,这里的指定会覆盖掉全局默认配置。 开发人员还可以将某个用户对某个报表做的列选择保存起来,以便下次本用户访问时仍能保 留他上次选中显示的列,关于这一部分,请参看后面“保存用户个性化信息”一节的介绍。 注意:如果一个数据自动列表报表需要在客户端提供动态列选择功能,同时它要提供统计功 能(包括针对整个报表数据的统计、针对树形分组的统计、针对普通行分组的统计等),则在配 置统计功能时,不能分多列显示这些统计信息,即只能配置一个,所有统计信息都显示在 此中,此将会占据整行的单元格(当然对于分组的统计,不会占据分组列所在的单 元格),因此,此时的的 colspan 属性无效,可以不用配置,因为它会占据整行。 1.8 行选中功能 只有数据自动列表报表的数据行具有行选中功能  配置方法 数据自动列表报表的标签有如下属性用于配置本报表的行选中行为:  rowselect 属性 用于配置当前报表是否具有行选中功能,可配置值有如下五种: none:当前报表不具有行选中功能; single:当前报表具有单行选中功能,即一次只能选中一行,不能进行多行选择; multiply:当前报表具有通过配合 Ctrl 或 Shift 键进行同时选中多行的功能; checkbox:当前报表自动为每一行提供一个复选框进行行选中,可以多选。 radiobox:当前报表自动为每一行提供一个单选框列进行行选中,一次只能选中一行。 对于只读的数据自动列表报表,默认为 none,即不具有行选中功能; 对于可编辑数据自动列表报表,如果配置了删除功能,则默认为 multiply,还可以为它 配置为 checkbox、single 或 radiobox。配置为 none 无效。 对于主/从报表的主报表,默认为 single,不能配置为 none。 如果配置为 checkbox 或 radiobox,如果用户没有配置选择列,即 column 为{col-rowselect} 的,则默认会在第一个非分组列前面生成一个显示单选框或复选框的选择列,以便专 门显示用于行选择的复选框或单选框,自动生成的行选择列不会放在中,如果想控 制行选择列的显示位置或样式,比如让它显示到某个中,则为它专门一个, 将其 column 配置为{col-rowselect}。 另外,如果用户想控制显示行选择列的样式或标题,也可以不采用框架自动生成的行选 择列,而是自己在任意位置配置一个 column 为{col-rowselect}的,且只能配置一个。 如果当前报表的行选中功能不是 checkbox 和 radiobox 这两种类型,则不能配置 column 第 33 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 为{col-rowselect}的。  selectcallback 属性: 配置报表的行选中回调函数,如果有多个,用分号分开。只有当前报表具有行选中功能 时,此属性配置的行选中回调函数才有意义。 所有行选中回调函数的签名如下所示: function 方法名(pageid,reportguid,selectedTrObjArr) 运行时,框架会自动将这两个参数传入 供行选中回调函数使用。 pageid 参数:当前报表所在页面的 id reportguid 参数:报表的 guid,根 据 reportguid 参数,可以从全局变量 WX_selectedTrObjs 中取到所有被选中的对象。此对象为一类似 J AVA 中的 Map> 对象,其中 reportGuid 为报表的 guid,Map为此报表所有被选中的对象,以 的 id 为键,对象为值。 selectedTrObjArr 参数:本次选中的行对象数组,跟上面从 WX_selectedTrObjs 中取出的 所有选中行对象集合有时候不同,因为通过 checkbox 或者通过 Ctrl 键进行多选时, selectedTrObjArr 数组不包括之前选中的行对象。 如果是用 Shift 进行多选,selectedTrObjArr 数组保持了本次选中的所有行的选中顺序, 不管是从上往下选,还是从下往上选,在 selectedTrObjArr 中存放顺序都是从起始行到本次 点击行依次存放在 selectedTrObjArr 数组中。 如果行选中回调函数在处理时,要对可编辑数据自动列表报表新增的数据行进行区分处 理,则可以通过判断被选中的 对象的 EDIT_TYPE 属性值是否为 add ,即 if(trObj.getAttribute('EDIT_TYPE')=='add'){则是新增行}。 通过被选中行的对象,可以取到这些选中行所有对象。 如果想在回调函数中获取被选中行某个单元格对应列的值,可以通过在配置此 td 对应的时,将的 rowselectvalue 属性配置为 true 即可,这样在回调函数中,通过 此对象的 getAttribute(“name”)即可获得当前对应的 column,通过此对象 的 getAttribute(“value”)即可获得当前单元格的数据,然后在回调函数中进行使用。 1.9 行排序 1.9.1 概述 对于数据自动列表报表,框架提供如下四种行排序功能:  通过拖动记录行进行排序  通过点击每一行的“上”“下”箭头进行排序  通过在每一行的输入框列输入排序值进行排序  通过点击“置顶”按钮进行排序 1.9.2 配置方法 配置行排序功能包括如下几步 通过的 rowordertype 属性指定所需的行排序类型 rowordertype 有四个配置值:drag、arrow、inputbox、top,分别表示拖动行、上下箭头、 输入框、置顶四种行排序方式,开发人员可经配置其中一种或多种,如果配置多种,则用“|” 分隔。 第 34 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 如果配置了 drag,则报表的数据行即可拖动; 如果配置了 arrow,则会自动在数据自动列表报表显示一列用于放置上下箭头列; 如果配置了 inputbox,则会自动在数据自动列表报表显示一列用于放置输入框,在其中 显示当前行的排序值,用户可以修改其中的排序值进行排序 如果配置了 top,则会自动在数据自动列表报表显示一列放置“置顶”按钮,点击它即 可将本行置顶。 从上面可以看出,只要 rowordertype 配置了 arrow、inputbox、top,框架就会自动为此 报表各生成一列用来存放相应的排序按钮或输入框,生成列的标题是框架根据 KEY: “roworder.arrow.label” 、“ roworder.inputbox.label” 、“ roworder.top.label”从资源文件中获取的, 这些资源项默认都定义在 jar 包中的 wabacus.resources.default.xml 文件中,用户可以修改它 们重新定义各排序列的标题,也可以在自己项目的资源文件中定义同名 key 的资源项,将会 覆盖掉 wabacus.resources.default.xml 中的定义。 框架会自动将行排序列生成在报表其它列的后面,各排序列之间的相对位置由它们出现 在 rowordertype 的顺序决定,比如如果某个报表配置为:rowordertype=”inputbox|top|arrow”, 则在报表的后面会依次显示三列:输入框、置顶、上下箭头,再比如某个报表配置为: rowordertype=”arrow|top|inputbox”,则在报表的后面会依次显示三列:上下箭头、置顶、输 入框。 开发人员也可以不使用框架自动生成的行排序列,而是自己定义相应的,这样可 以控制每个排序列的显示位置和显示样式,定义这三种行排序列时,它们的 column 属性分 别配置如下所示: arrow:{roworder-arrow} inputbox:{roworder-inputbox} top:{roworder-top} 这样就可以通过它们的 labelstyleproperty、valuestyleproperty 等属性来控制它们的样式或 者显示位置,还可以通过 label 来控制各列的标题。如果行排序类型为 inputbox,还有 一个 inputboxstyleproperty 属性,用于配置输入框的样式 为行某个行排序类型定义了,后则框架不会再自动为它生成相应的排序列,比如 定义了 column 为{roworder-inputbox}的,则不会再为它生成行排序用的输入框列。 指定参与行排序的列 稍后在服务器端存取某记录行的排序值时,需要通过哪些列的数据来定位这个数据行, 参与定位数据行的列即称为参与行排序的列。 如果某个列参与定位排序记录行,则将其的 rowordervalue 属性配置为 true,这样 在服务器端定位某记录行时,就可以根据其 column 属性从一 Map 中取到此列的值。 除了将参与定位记录行的列的 rowordervalue 属性配置为 true,一般还会配置一个 存放从数据库取出的每行的排序值,并将其 rowordervalue 属性配置为 true,以便在服务器端 轻易得到本记录行的旧排序值。 稍后会介绍如何使用参与行排序列的值。 开发一 J AVA 类,将排序值保存到数据库中 通过上面的配置,只是在客户端提供了行排序的功能,用户进行相应的行排序操作后, 新的排序值还没有保存起来。要保存某记录行排序后的新值,需要开发一 J AVA 类完成,此 类必须实现框架接口:com.wabacus.system.commoninterface.IListReportRoworderPersistence, 此接口包括好几个方法 ,开发人员可以根据自己的需求实现其中一个或多个方法。 此接口包括如下方法:  public String loadRoworder(Map mColValuesInRow); 第 35 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 功能:获取某记录行的排序值 参数 mColValuesInRow:存放本记录行中所有 rowordervalue 为 true 的的列的值。 以 column 为键,列值为值进行存放。 如果排序值已经与报表数据一起查出来了,并存放在某个中(可以是 displaytype 为 hidden 的 col),且 其 rowordervalue 配置为 true,则可以直接从 mColValues 中取到,即 return mColValues.get(column);如果此的 rowordervalue 没有配置,或配置为 false,则也可以 返回@{column}即可,这样框架会自动从这一列中取排序值,一般都是这两种情况。 此方法只有当 rowordertype 配置了 inputbox 时才会调用到,用于获取此行的排序值,其 它几种排序方式不会调用到此方法。  public void storeRoworderByDrag (ReportRequest rrequest,ReportBean rbean,Map mColValuesInRow, Map mColValuesInDestRow,boolean direct); 功能:此方法用于实现当通过行拖动进行行排序时保存排序值的功能  参数 mColValuesInRow:被移动行的所有 rowordervalue 为 true 的列的值,根据 它可以定位到被移动行的记录。  参数 mColValuesInDestRow:移动到目标位置行的所有 rowordervalue 为 true 的 列的值,根据它可以定位到要移动的目的位置的记录。  参数 direct:移动方向,即当前是移动到目标行的上面(值为 true),还是下面 (值为 false)。  public void storeRoworderByArrow(ReportRequest rrequest,ReportBean rbean,Map mColValuesInRow, Map mColValuesInDestRow,boolean direct); 功能:此方法用于实现当通过点击上下箭头进行行排序时保存排序值的功能  参数 mColValuesInRow:被移动行的所有 rowordervalue 为 true 的列的值,根据 它可以定位到被移动行的记录。  参数 mColValuesInDestRow:移动到目标位置行的所有 rowordervalue 为 true 的 列的值,根据它可以定位到要移动的目的位置的记录。  参数 direct:移动方向,即当前是移动到目标行的上面(值为 true),还是下面 (值为 false)。 注意:这种排序方式的 mColValuesInDestRow 参数可能为空,因为比如当前记录已 经是本页的第一行然后点击向上箭头,或本页的最后一行然后点击向下箭头,此时 目录记录行就为空,开发人员可以根据 mColValuesInRow 参数找到它的上一行或下 一行,然后再进行排序。  public void storeRoworderByInputbox(ReportRequest rrequest,ReportBean rbean,Map mColValuesInRow,String newrowordervalue); 功能:此方法用于直接在输入框中输入排序值时保存新排序值的功能  参数 mColValuesInRow:被排序行的所有 rowordervalue 为 true 的列的值,根据 它可以定位到被排序行的记录。  参数 newroworder:用户输入的新排序值  public void storeRoworderByTop(ReportRequest rrequest,ReportBean rbean,Map mColValuesInRow); 功能:此方法用于点击置顶时保存新排序值的功能  参数 mColValuesInRow:被排序行的所有 rowordervalue 为 true 的列的值,根据 它可以定位到被置顶行的记录。 第 36 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 开发完用于排序的 J AVA 类后,需要将此类配置到框架中,根据此类的通用性,配置方 式有两种: 如果此排序类比较通用,可以满足项目中很多报表的排序要求,则将它注册到 wabacus.cfg.xml 系统配置文件 name 为 default-roworderclass 的配置项中,在这里配置此类的 全限定类名。这样整个项目的行排序报表如果没有指定自己的行排序类都会使用这里配置的 全局类完成行排序的保存操作。 如果此类不通用,只用在当前报表中,则将此类的全限定类名配置在本报表的 roworderclass 属性中。 注意:某个报表只有不能用全局默认的行排序读写类时才需要开发自己的行排序类,并 且实现的方法根据自己的排序要求决定,比如某个报表配置的 roworder=”rowdrag”,即只要 行拖动排序,则只要实现 storeRoworderByDragOrArrow ()方法进行保存新排序值的操作,而 不需实现 storeRoworderByInputbox ()、storeRoworderByTop ()两个接口方法。 在配置查询数据的 SQL 语句时,将排序字段放入 order by 子句中 上面步骤完成了行排序的保存操作,但要数据根据行排序字段进行排序,还要在查询数 据的 SQL 语句中根据它来排序,才能在前台显示报表时反映出排序顺序。 1.9.3 其它说明  如果指定了行排序功能,则必须有一个或一个以上的配置了 rowordervalue 为 true, 因为在保存新顺序数据时,需要根据它们定位到被排序行的记录,然后修改它的顺序 值。  在实现 IListReportRoworderPersistence 接口的行排序读写类中的所有方法都没有直接传 入某行的旧排序值,如果需要用到,可通过如下两种方式得到: 1)、配置一个,将其 column 配置为排序字段,存放当前行的排序值(如果不 想显示在页面上,可以将 displaytype 配置为 hidden),然后将其 rowordervalue 配置为 true, 这样通过参数 mFromColValues、mToColValues、mColValues 就可以取到它们。 2)、自己根据 mFromColValues、mToColValues、mColValues 存放的其它列的值, 从数据库中取对应的排序字段的值。 一般用第一种方法即可,简单方便,性能也高。  对于 arrow、inputbox、top 三种行排序类型,排序列中显示的内容是分别根据 KEY: roworder.arrow.up、roworder.arrow.down、roworder.top 从资源文件中获取的,它们的 默认资源项定义在 wabacus.jar 包 wabacus.resources.default.xml 文件中,用户可以直接 修改,也可以在自己项目的资源文件中定义同名 KEY 的资源项,它会覆盖掉那里的 默认配置。  对于行拖动排序方式,必须要拖动非数据部分,不能拖动单元格的数据部分,否则不允 许拖动,这样设计是为了在提供行拖动时还允许用户选择单元格中的字符串。  对于通过输入框输入新排序值,即 rowordertype 为 inputbox(或者包括 inputbox)的报 表,排序方式为用户在输入框输入完顺序值后输入框失去焦点时立即触发更新后台顺 序值,如果用户想支持同时修改多个行的排序值,然后点击一个按钮统一保存到后台, 或者用户想在添加记录时也能输入排序值,则可以将报表类型配置为可编辑报表类 型,然后排序字段也做为普通可编辑列进行配置,这样就可以像普通列一样编辑 (DEMO 有相关演示)  开发人员想在用户对某行数据排完序后进行一下其它处理,可以在报表前置动作中完 成,因为如果本次是进行行排序操作,则会在执行前置动作前就将新排序值保存到数 据库中。 第 37 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 如果要在前置动作中对记录行排序操作完成后进行其它处理,一般会用到如下代 码: //取到本次的行排序类型,包括drag、arrow、inputbox、top四种 String rowordertype= rrequest.getStringAttribute(rbean.getId()+"_ROWORDERTYPE",""); if(rowordertype.equals("")||!Consts.lstAllRoworderTypes.contains(roworder type)) return;//当前没有进行行排序操作 //取到本次排序记录行上 rowordervalue 为 true 的所有列的参数字符串 String roworderparams= rrequest.getStringAttribute(rbean.getId()+"_ROWORDERPARAMS",""); if(roworderparams.equals("")) return; //下面将参数转换为Map,这样就可以根据的column取到其值 Map mColValuesInRow= EditableReportAssistant.getInstance().parseSaveDataStringToList(rowor derparams).get(0); 一般通过上面的代码即可定位到本次排序的是哪条记录,然后就可以对它进行处 理。 1.9.4 行排序功能授权 对于行排序功能,支持两种授权方式: 1)、通过在 rrequest.authoirze()方法第二个参数中指定”roworder”进行授权 这种方式只能授权 disabled 权限类型,不支持 display 和 readonly 两种权限类型的授权。 当授权 disabled 权限类型为 true 时,相应的行排序功能会被禁用。 例如: rrequest.authorize(“reportid”,”roworder”,null,”disabled”,”true”); 则本报表所有行排序功能列都被禁用,但仍显示,行拖动排序也不能使用。 rrequest.authorize(“reportid”,”roworder”,”drag”,”disabled”,”true”); 则本报表的行拖动排序功能不能使用 rrequest.authorize(“reportid”,”roworder”,”arrow”,”disabled”,”true”); 则本报表行箭头排序列将被禁用 rrequest.authorize(“reportid”,”roworder”,”inputbox”,”disabled”,”true”); 则本报表输入框排序列将被禁用 rrequest.authorize(“reportid”,”roworder”,”top”,”disabled”,”true”); 则本报表置顶排序列将被禁用 2)、通过在 rrequest.authorize()方法第二个参数中指定”data”进行授权 这种授权方式支持 display 和 disabled 两种权限类型的授权,不支持 readonly 权限类型授权。 这种授权方式是对行排序列进行授权,因为 drag 排序类型没有行排序列,因此不能通过此方式对它进 行授权。 即这种方式只能对 arrow、inputbox、top 三种行排序方式有效,因为它们才会有排序列。 如果执行如下代码: rrequest.authroize(reportid,”data”,“{roworder-arrow}”,”disabled”,”true”) rrequest.authroize(reportid, ”data”,“{roworder-top}”, ”disabled”,”true”) rrequest.authroize(reportid, ”data”,“{roworder-inputbox}”, ”disabled”,”true”) 则三种排序列都会被禁用,对于 inputbox 行排序列,则是输入框不允许编辑。 第 38 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 如果执行如下代码: rrequest.authroize(reportid,”data”,“{roworder-arrow}”,”display”,”false”) rrequest.authroize(reportid, ”data”,“{roworder-top}”, ” display”,” false”) rrequest.authroize(reportid, ”data”,“{roworder-inputbox}”, ” display”,” false”) 则三种排序列将会被隐藏不显示出来。 1.10 报表拦截器 1.10.1 概述 报表拦截器包括很多拦截方法,它们会在加载和显示报表的各个阶段被框架调用,开发人员 可以根据需要实现其中一个或多个方法,加入自己的实现,以便实现复杂的业务逻辑。可以说拦 截器是开发人员实现复杂业务的重要手段。 报表拦截器包括如下拦截方法:  报表前置动作:在报表初始化后,加载数据前由框架调用。  保存报表前置动作:可编辑报表在保存所有数据前由框架调用。  保存每条记录前置动作:可编辑报表在保存每条记录前由框架调用(对于可编辑细览 报表,只会有一条记录,因为它们一次只能显示一条记录)  执行每条保存 SQL 语句前置动作:在保存可编辑报表每条记录时,执行每条 SQL 语 句前由框架调用  执行每条保存 SQL 语句后置动作:在保存可编辑报表每条记录时,执行完每条 SQL 语句后由框架调用  保存完每条记录后置动作:可编辑报表在保存完每条记录后由框架调用(对于可编辑 细览报表,只会有一条记录,因为它们一次只能显示一条记录)  保存报表后置动作:可编辑报表类型在保存完所有数据后由框架调用。  加载数据前置动作:在查询报表数据(包括报表数据,下拉选项数据,列过滤选项数 据,总记录数数据等)时执行,执行每一条查询数据的 SQL 语句前都会调用。  加载完数据后置动作:在查询完报表数据(包括报表数据,下拉选项数据,列过滤选 项数据,总记录数数据等)后执行。  显示每行数据的前置动作:只对数据列表报表类型有效,显示每一行数据前(包括每 一行标题)调用。  显示每列数据的前置动作:显示每一列数据前调用。  报表后置动作:在将报表完整的显示到前台后由框架调用。 如果一个报表的拦截器实现了上面的所有拦截方法,则它们被框架调用的顺序依次为: “报表前置动作”――〉“保存报表数据前置动作”――〉“保存每条记录前置动作”――〉 “执行每条保存 SQL 语句前置动作”――〉“执行每条保存 SQL 语句后置动作”――〉“保存完 每条记录后置动作”――〉“保存报表后置动作”――〉“加载数据前置动作”――〉“加载完数 据后置动作”――〉“显示每行数据的前置动作”――〉“显示每列数据的前置动作”――〉“报 表后置动作” 第 39 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 用户可以根据报表的需要为它配置上面任意一个动作或几个动作,对于不可编辑的报表类 型,不能配置保存前/后置动作,配置了也永远不会执行。 为报表增加拦截器有三种方式:  开发拦截器 J AVA 类,然后通过标签的 interceptor 属性进行引用 拦截器类必须实现 com.wabacus.system.intercept.IInterceptor 接口,但这个接口的接 口方法比较多,框架提供了一个为所有拦截方法提供默认实现的类: com.wabacus.system.intercept.AbsInterceptorDefaultAdapter 父类,开发人员只要继承这个 类,然后覆写其中要实现的拦截方法即可。 AbsInterceptorDefaultAdapter 类包括上面所有拦截方法,在后面具体介绍每个拦截 方法时会介绍到相应方法的签名。  定义拦截器资源项,然后通过标签的 interceptor 属性进行引用 配置拦截器资源项时, 的 type 需要指定为 “com.wabacus.config.resource.InterceptorRes”,然后在其中配置子标签,在 此子标签中为每个拦截方法都提供了一个子标签,用户需要实现哪个拦截方法,就配置 相应的子标签即可。  在报表标签中配置一个子标签 这种方式配置的拦截器只能被这一个报表使用,不能共用,这里的 标签方法与拦截器资源项的子标签配置完全相同, 包括的子标签也相同,即每个拦截方法都有一个自己的子标签,用户根据需 要实现的拦截方法配置相应的标签即可。 上面三种实现拦截器的方式是在运行时都是完全等效的,只是实现方式不一样, 而且在标签中用拦截方法的标签配置代码时,也可以像在 J AVA 类中实 现拦截方法一样,通过同名的参数访问到相同的对象。例如:报表前置动作,在通 过 J AVA 类实现时,是实现方法 public void doStart(ReportRequest rrequest,ReportBean rbean),因此可以在此方法中通过 rrequest 和 rbean 两 个变量名访问到这两个对象,如果在中配置此拦截方法时,是使用 标签,在这个标签配置拦截器的 J AVA 代码时也可以通过 rrequest 和 rbean 两个变量名访问到这两个对象。如果拦截方法需要返回值,在 J AVA 类中实现和在配 置文件中配置返回的值和意义也完全相同。 下面根据各拦截方法的执行顺序依次进行详细介绍。 1.10.2 报表前置动作 执行时机 在报表刚初始化完,还没有进行任何其它操作时由框架调用,因此开发人员 可以在此修改查询条件、修改可编辑报表的访问模式,甚至对报表某个部分进行 授权(建议在页面拦截器的前置动作中授权)。 例如可以通过代码:rrequest.setAttribute(“name”,value)设置某个条件的值,其 中 name 为此条件所在 标签的 name 属性。还可以通过 第 40 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> rrequest.getStringAttribute(“name”,””)取到某个条件的值,等等。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public void doStart(ReportRequest rrequest,ReportBean rbean)  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明: 无 1.10.3 保存报表前置动作 执行时机 此方法只对可编辑报表有效,而且只有当前在做增、删、改报表数据的操作 时才会执行。它是在保存此报表所有数据前由框架调用,用户可以在此方法中增、 删、改此报表待保存的数据。还可以通过返回值中断保存操作。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public int beforeSave(ReportRequest rrequest,ReportBean rbean)  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  rrequest 参数:通过此参数,除了可以完成存取条件值、获取数据库连接、 向前台提示信息等操作外,还可以调用它的如下几类型接口方法:  public List> getLstUpdatedData(String reportid) 功能:传入某个可编辑报表 ID,获取此报表当前修改的数据列表。每条修 改的记录对应一个 Map 对象依次存放在 List 中,每条记录所有列的修改数据都 存放在此 Map 对象中,以 column 为键,以修改值为值。如果获取的 List 对象为 空,则说明当前没有修改数据进行保存。对于可编辑数据细览报表类型,如果修 改了记录,此 List 大小为 1,因为不可能同时修改多条记录。  public List> getLstUpdatedExternalValues (String reportid) 功能:如果某个可编辑报表的配置了标签,即配 置了参数值,通过这个接口方法可以获取到每条更新记录对应的各参数的真正 值。这里的每个 Map 元素与上面 getLstUpdatedData()方法获取的每条更新记录的 Map 对象一一对应,因此可以通过相同的下标获取到各条记录对应的真正参数 值。 第 41 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  public List> getLstInsertedData(String reportid) 功能:获取某个可编辑报表当前插入的数据列表。每条插入的记录对应一个 Map 对象,每条记录所有列的数据都存放在此 Map 对象中,以 column 为键,以 插入值为值。如果获取的 List 对象为空,则说明当前没有插入数据进行保存。 对 于可编辑数据细览报表类型,如果插入了记录,此 List 大小为 1,因为不可能同 时插入多条记录。  public List> getLstInsertedExternalValues(String reportid) 功能:如果当前报表的配置了标签,即配置了其它 参数值,通过这个接口方法可以获取到每条插入记录对应的各参数的真正值。这 里的每个 Map 元素与上面 getLstInsertedData()方法获取的每条插入记录 的 Map 对象一一对应,因此可以通过相同的下标获取到各条记录对应的真正参数 值。  public List> getLstDeletedData(String reportid) 功能:获取某个可编辑报表类型当前删除的数据列表,每条删除的记录对应 一个 Map 对象,每条记录所有列的数据都存放在此 Map 对象中。如果获取的 List 对象为空,则说明当前没有删除数据进行保存。 对于可编辑数据细览报表类型, 如果删除了记录,此 List 大小为 1,因为不可能同时删除多条记录。  public List> getLstDeletedExternalValues(String reportid) 功能:如果当前报表的配置了标签,即配置了其它 参数值,通过这个接口方法可以获取到每条被删除记录对应的各参数的真正值。 这里的每个 Map 元素与上面 getLstDeletedData 获取的每条插入记录的 Map 对象一一对应,因此可以通过相同的下标获取到各条记录对应的真正参数值。  public Map getMCustomizeEditData(String reportid) 功能:如果当前报表保存时,在客户端传入了自定义保存数据,则可以通过 此方法获取到,所有自定义保存数据都存放在返回的 Map 对象中,以参数名为键, 参数值为值。 注意: 1、在前置动作中通过上面接口方法取到任意参数的数据后,可以直接在 Map 中修改它 的值,保存时会使用修改后的值进行保存。 2、在 getLstUpdatedData ()、getLstInsertedData ()、getLstDeletedData () 三个方法中获取的某个参数的参数名如果以“[NOISSIMREP_YALPSIDNON]”为前缀,则 第 42 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 它的参数值可能是经过编码后的参数值,此时必须调用 com.wabacus.system.assistant.EditableReportAssistant 类的如下方法取得真正的参数值: public String getColParamRealValue(ReportRequest rrequest,ReportBean rbean,String paramname,String paramvalue)  paramname 参数:就是带[NOISSIMREP_YALPSIDNON]前缀的参数名  paramvalue 参数:就是根据 paramname 从 Map 对象取到的参数值 调用此方法的代码为: EditableReportAssistant.getInstance().getColParamRealValue(rrequest,rbean, paramname,paramvalue); 调用上面的方法后就能将 paramvalue 转换成真正的参数值返回。  public void disableAutoSuccessPrompt() 功能:对本次保存操作禁用框架自动提示保存成功信息。如果开发人员想自 己提供保存成功信息,则可以先调用此方法禁用掉框架的自动提示,再调用 rrequest.getWResponse().getMessageCollector().success("操作成功",false);方法自己 提示。  public void disableAutoFailedPrompt() 功能:本次保存操作是否要禁用掉框架自动提示保存失败信息。如果开发人 员想自己提供保存失败信息,则可以先调用此方法禁用掉框架的自动提示,再调 用 rrequest.getWResponse().getMessageCollector().error("操作失败",true/false);(true 表示立即停止后续所有操作)方法自己提示。  返回值: 保存报表前置动作的拦截方法必须返回如下三个值之一:  WX_TERMINATE:阻止框架完成在中配置的保存操作,且在保存 前置动作中也没进行任何保存操作,此时不会执行保存后客户端回调函 数(如果配置了的话),也不会在前台提示保存成功,所以返回此值表示 本次没有对此报表进行任何保存操作;  WX_IGNORE:表示用户在前置动作中自己完成了保存操作,但框架不 需要执行在中配置的保存操作,此时会执行保存后客户端回调函数 (如果配置了的话),也会在前台提示保存成功。  WX_CONTINUE:表示框架需要完成在中配置的保存操作,显示完 页面后会执行保存后客户端回调函数(如果配置了的话),也会在前台提 示保存成功 开发人员根据自己的需要在前置动作中返回相应的值。 注意:上面三个值是框架定义的常量,不是普通字符串,比如必须是 return WX_CONTINUE;格式,而不能是 return “WX_CONTINUE”;格式。 1.10.4 保存每条记录前置动作 执行时机 此方法只对可编辑报表有效,而且只有当前在做增、删、改报表数据的操作 时才会执行。它是在增、删、改此报表每条记录前由框架调用,用户可以在此方 第 43 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 法中增、删、改此此条记录待保存的数据。还可以通过返回值中断本条记录或整 个报表的保存操作。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public int beforeSavePerRow(ReportRequest rrequest,ReportBean rbean,Map mRowData,Map mExternalValues,int updatetype);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  rrequest 参数:在上面“保存报表前置动作”介绍的 rrequest 参数的所有方法 在此拦截方法中都可以使用,不过这个方法因为是相对于某一条记录,因此在取 当前保存记录的数据时可以直接从其它参数中取到,不需用到 getLstUpdateData() 等方法。  mRowData 参数:存放有此条记录所有列的新旧数据  如果是不可编辑列,则通过它们的 column 属性得到此列的值,因 为是不可编辑列,所以这里取出的永远是旧值;  如果是可编辑列,则分如下情况:如果当前是添加此条记录,则通过各 列的 column 取到此列的新数据,它们都没有旧数据;如果当前是修改此条记 录,则通过它们的 column 取到此列编辑后的新值,通过 column_old 得到此 列的旧值;如果是对此记录做删除操作,则通过此列的 column_old 取到此列 的旧数据,编辑后的新数据不会传入后台,也就是说通过 column 取此列的值 将会为空。 开发人员可以直接修改这个 Map 对象中的值,框架保存时会使用修改后的值 进行保存。  mExternalValues 参数:如果此标签配置了 子标签,并在其中定义了变量,则可以传入变量名从 mExternalValues 对象得到本条记录各变量的变量值,用户可以修改其中的变量 值,保存时会使用用户修改后的值。  updatetype 参数:对本条记录的操作类型,可取如下三个值:WX_INSERT、 WX_UPDATE、WX_DELETE,分别表示本次是在对此记录做添加、修改、删除 操作。  返回值: 保存每条记录前置动作的拦截方法必须返回如下三个值之一:  WX_TERMINATE:阻止框架完成在中配置的保存操作,且在保存 前置动作中也没进行任何保存操作,此时不会执行保存后客户端回调函 第 44 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 数(如果配置了的话),也不会在前台提示保存成功,所以返回此值表示 本次没有对此报表进行任何保存操作;  WX_IGNORE:通知框架不需对本记录执行在中配置的保存操作, 但不会影响前台执行保存后客户端回调函数,也不会影响前台提示保存 成功信息,开发人员可能在拦截方法中执行了对此记录的保存操作。  WX_CONTINUE:表示框架需要对本记录执行在中配置的保存操 作,不会影响前台执行保存后客户端回调函数,也不会影响前台提示保 存成功信息 1.10.5 保存每条SQL语句前置动作 执行时机 对保存的每条记录在执行每条保存 SQL 语句前由框架调用,因为不管是 哪一个更新类型,都可以配置一条或多条 SQL 语 句或存储过程(用分号;分隔),在保存每条记录时都会依次调用一次这里配置 的每条 SQL 语句和存储过程,在执行每条 SQL 语句和存储过程前就会调用一次 此拦截方法,并传入相应的参数值。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public int beforeSavePerSql(ReportRequest rrequest,ReportBean rbean,Map mRowData,Map mExternalValues,String sql);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  rrequest 参数:在上面“保存报表前置动作”介绍的 rrequest 参数的所有方法 在此拦截方法中都可以使用,不过这个方法因为是相对于某一条记录,因此在取 当前保存记录的数据时可以直接从其它参数中取到,不需用到 getLstUpdateData() 等方法。  mRowData 参数:存放执行当前 SQL 语句所保存的记录所有列的新旧数据, 与上面“保存每条记录前置动作”拦截方法的 mRowData 参数意义和数据结构完 全一样。  mExternalValues 参数:与上面“保存每条记录前置动作”拦截方法的 mExternalValues 参数意义和数据结构完全一样  sql 参数:当前要执行的保存数据 SQL 语句  返回值: 与上面“保存每条记录前置动作”拦截方法返回值及意义相同。不过这里当 返回WX_IGNORE 时,表示忽略框架自动执行此条SQL,如果还配置了其它 SQL, 则不影响框架执行它们 第 45 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 1.10.6 保存每条SQL语句后置动作 执行时机 与上面“保存每条 SQL 语句前置动作”相对应,不过此拦截方法是在执行完 每条 SQL 语句和存储过程后框架就会调用一次此拦截方法,并传入相应的参数 值。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public int afterSavePerSql(ReportRequest rrequest,ReportBean rbean,Map mRowData,Map mExternalValues,String sql);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  拦截方法参数:此拦截方法的所有参数与上面“保存每条 SQL 语句前置动作” 拦截方法的参数完全相同。  返回值: 此拦截方法必须返回 WX_TERMINATE 和 WX_CONTINUE 两个值,分别表 示本次没有进行任何保存操作,退出所有保存;继续执行其它保存此条记录的 SQL 语句。不支持 WX_IGNORE 返回值。 1.10.7 保存每条记录后置动作 执行时机 与上面“保存每条记录前置动作”对应,不过此拦截方法是在保存完每条记 录后由框架调用一次,并传入相应的参数。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public int afterSavePerRow(ReportRequest rrequest,ReportBean rbean,Map mRowData,Map mExternalValues,int updatetype);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  拦截方法参数:与上面“保存每条记录前置动作”拦截方法中各参数意义完 全一样。  返回值:与上面“保存每条 SQL 后置动作”返回值及意义完全相同,支持 WX_TERMINATE 和 WX_CONTINUE 两个返回值,不支持 WX_IGNORE 返回值。 1.10.8 保存报表后置动作 执行时机 第 46 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 与上面“保存报表前置动作”对应,不过此拦截方法是在保存完当前报表所 有数据后由框架调用,并传入相应的参数。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public void afterSave(ReportRequest rrequest,ReportBean rbean);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  拦截方法参数:与上面“保存报表前置动作”拦截方法中各参数意义完全一 样。不过这里不能修改保存值,修改也无效,因为调用此方法时,所有保存操作 已经完成。  返回值:无 1.10.9 加载数据前置动作 执行时机 在框架加载报表每类数据前由框架调用,目前在加载如下几类数据时会调用 拦截器中实现的此拦截方法:  加载报表显示数据  加载分页报表记录数数据  加载下拉框/单选框/复选框选项数据  加载输入联想选项数据  加载列过滤选项数据 在加载上述数据时,都会调用开发人员在拦截器中实现的此拦截方法。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public Object beforeLoadData(ReportRequest rrequest,ReportBean rbean,Object typeObj,String sql);  如果是在标签中配置拦截器,此拦截方法标签为: < beforeloaddata /> 拦截方法说明:  typeObj 参数:当前正在加载哪类数据的类型,包括如下几种:  如果当前是在加载报表显示数据或分页显示报表记录数的数据,则 typeObj 为 AbsReportType 类型的对象,从中可以取到当前报表类型对象 和报表配置对象;如果要进一步区分是加载哪类数据,可以根据 sql 参数 判断 SQL 语句 第 47 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  如果当前是在加载下拉框/单选框/复选框选项数据,则 typeObj 为 OptionBean 类型的对象;  如果当前是在加载输入联想选项数据,则 typeObj 为 SQLPromptDataSource 类型的对象;  如果当前是在加载列过滤选项数据,则 typeObj 为 AbsListReportFilterBean 类型的对象。  sql 参数:将要执行的加载数据 SQL 语句  返回值: 可返回的值包括如下类型:  返回 SQL 语句:返回原始 SQL 语句或修改后的 SQL 语句,如果开发人 员在此拦截方法中修改了 SQL 语句并返回,则框架将会执行开发人员修 改后的 SQL 语句。  返回 ResultSet 对象:如果用户自己在拦截方法中执行了 SQL 语句,然后 返回记录集 ResultSet 对象,则框架会直接使用用户返回的 ResultSet 对象, 不会再执行 SQL 语句从数据库取数据。  返回结果集对象:直接返回所需的数据对象,不同的加载类型需要的结 果集对象是不一样的,具体如下所示:  如果是加载报表显示数据,则结果集对象为一 List,里面存放每条记 录对应的 POJO 对象,一列数据在 POJO 中对应一个带 get/set 方法的 成员变量,用于保存此列的数据。  如果是加载分页报表记录数数据,则结果集对象为一 List 对象,里 面 只需存放一个 Integer 类型的元素,值为取出的当前记录数。  如果是加载下拉框/单选框/复选框选项数据,则结果集对象为一 List类型的对象,里面存放每个下拉选项数据,其中每个选 项数据存放在一个 String[]数组中,第一个元素存放的是选项数据的 显示 label,第二个元素存放的是选项数据的 value。  如果是加载输入联想选项数据,则结果集对象为一 List>类型的对象,里面存放每个联想选项数据的 label 和 value。存放 label 和 value 都是以配置的值为键,真正取出的 值为值存放在 Map 中。开发人员可以遍历它们查看数据结构。  如果是加载列过滤选项数据,则结果集对象为一 List类型的 对象,存放所有过滤选项数据。 如果在加载数据前置动作的拦截方法中直接返回了上述结果集,则框架 不再从数据库加载数据,而是直接使用开发人员返回的结果集。 1.10.10 加载数据后置动作 执行时机 在框架加载完报表每类数据后由框架调用,目前在加载完如下几类数据时会 调用拦截器中实现的此拦截方法: 第 48 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  加载报表显示数据  加载下拉框/单选框/复选框选项数据  加载输入联想选项数据  加载列过滤选项数据 在加载上述数据时,都会调用开发人员在拦截器中实现的此拦截方法,这里 相比上面“加载数据前置动作”少了一个类型,即加载完“分页报表记录数数据” 时不会调用拦截器的“加载数据后置动作”方法。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public Object afterLoadData(ReportRequest rrequest,ReportBean rbean,Object typeObj,Object dataObj);  如果是在标签中配置拦截器,此拦截方法标签为: < afterloaddata /> 拦截方法说明:  typeObj 参数:当前正在加载哪类数据的类型,包括如下几种:  如果当前是在加载报表显示数据,则 typeObj 为 AbsReportType 类型的对 象,从中可以取到当前报表类型对象和报表配置对象;如果要进一步区 分是加载哪类数据,可以根据 sql 参数判断 SQL 语句  如果当前是在加载下拉框/单选框/复选框选项数据,则 typeObj 为 OptionBean 类型的对象;  如果当前是在加载输入联想选项数据,则 typeObj 为 SQLPromptDataSource 类型的对象;  如果当前是在加载列过滤选项数据,则 typeObj 为 AbsListReportFilterBean 类型的对象。  dataObj 参数:已经加载好的数据对象,每类数据对应的数据对象类型如下 所示:  如果是加载报表显示数据,则 dataObj 对象为一 List,里面存放每条记录 对应的 POJO 对象,一列数据在 POJO 中对应一个带 get/set 方法的成员 变量,用于保存此列的数据。  如果是加载下拉框/单选框/复选框选项数据,则 dataObj 对象为一 List类型的对象,里面存放每个下拉选项数据,其中每个选项 数据存放在一个 String[]数组中,第一个元素存放的是选项数据的显示 label,第二个元素存放的是选项数据的 value。  如果是加载输入联想选项数据,则 dataObj 对象为一 List>类型的对象,里面存放每个联想选项数据的 label 和 value。存 放 label 和 value 都是以配置的值为键,真正取出的值为 值存放在 Map 中。开发人员可以遍历它们查看数据结构。 第 49 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  如果是加载列过滤选项数据,则 dataObj 对象为一 List类型的对 象,存放所有过滤选项数据。  返回值: 返回的数据对象为用户修改后的数据,如果没有修改,则直接返回 参数 dataObj 即可。 1.10.11 显示每行数据前置动作 执行时机 对于数据自动列表报表有效,在显示每一行数据(包括数据标题)时调用, 用户可以在此修改当前行的显示样式,最常用的方法就是修改指定行的背景色。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public String beforeDisplayReportDataPerRow(AbsListReportType reportTypeObj,ReportRequest rrequest,int rowindex);  如果是在标签中配置拦截器,此拦截方法标签为: < beforedisplay-perrow /> 拦截方法说明:  reportTypeObj 参数:当前报表类型对象,通过它的 getListReportData()方法 可以取到报表的所有数据;  rowindex 参数:当前显示的行号,数据行从 0 开始,如果为-1,则说明当前 是在显示标题行;  返回值:当前行对应的的样式字符串,比如 bgcolor=’red’ height=’30px’, 这样显示当前行的时就会有,如果不打算修 改行的样式,返回 null 即可。 示例: public String beforeDisplayReportDataPerRow(AbsListReportType reportTypeObj, ReportRequest rrequest,int rowindex) { if(rowindex<0) {//当前是在显示标题行 return null; } if(reportTypeObj.getLstReportData()!=null&&rowindex 取出sex列的数据 if(sex.equals("女")) { return "bgcolor='#CCCAFF'"; }else {//男 return "bgcolor='#FFFFFF'"; } } return null; } 上面拦截器方法代码是用于控制某个报表中数据行的背景色,如果为性别为 女的,则背景色设置为#CCCAFF,否则背景色为#FFFFFF。 1.10.12 显示每列数据前置动作 执行时机 显示报表每列数据(或数据标题)前由框架调用,开发人员可以在此控制当 前列的标题或数据的显示值、显示样式等。此拦截方法对所有报表类型有效。 拦截方法  如果是开发拦截器类,此拦截方法签名为: public ColDataByInterceptor beforeDisplayReportDataPerCol( AbsReportType reportTypeObj,ReportRequest rrequest,Object displayColBean,int rowindex,String value);  如果是在标签中配置拦截器,此拦截方法标签为: 拦截方法说明:  reportTypeObj 参数:当前报表类型对象,通过它的 getListReportData()方法 可以取到报表的所有数据;  displayColBean 参数:根据当前显示的列的类型,有如下几种情况:  如果当前是显示某一普通列的标题或数据,则它为 ColBean 类型的对象;  如果当前是显示某一列分组的标题(即的 label),则它为 UltraReportListGroupBean 类型的对象;  如果当前是显示某一统计列的数据,则它为 AbsListReportStatiColBean 类型的对象。 从这个对象中可以取到相应的配置信息,并根据此判断当前是在显示哪一列 的什么数据。  rowindex 参数:当前显示列所在的行号,如果为标题列(包括列表报表和细 第 51 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 览报表的标签列),则此值为-1,如果是数据列,则此值就是所在的行号,从 0 开始,细览报表的数据行号一直为 0。当前显示的行号,数据行从 0 开始。 此参数根据列的类型取值及意义如下所示:  如果 displayColBean 为 ColBean 类型:如果 rowindex 为-1,则当前是在 显示此列的标题部分;如果>=0,则当前在显示此列的相应行的数据;  如果 displayColBean 为 UltraReportListGroupBean 类型:因为没 有对应数据部分,所以它的 rowindex 一直-1  如果 displayColBean 为 AbsListReportStatiColBean 类型:则 rowindex 无 意义。;  value 参数:当前列要显示的值,如果当前是在显示某列的标题,则 value 即 为它的显示 label,如果是在显示数据,则是要显示的数据部分。这个值可以被修 改,这样框架就不会显示这里的值,而是显示用户修改后的值,修改方法请参看 下面返回值的介绍。  返回值:返回 ColDataByInterceptor 类型的对象,此对象包括如下几个成员变 量:  dynvalue:动态值,如果用户需要修改将要显示的当前列的数据,则将新 值存放此成员变量中,框架显示当前列数据时,就会用这个值,而不再 显示参数 value 中的数据。如果不想修改当前列要显示的值,则不在里面 存数据即可。  dynstyleproperty:当前列的动态样式字符串,用户存在这里的样式字符 串会在显示当前列时,附加到它的中。  styleOverwrite:是否覆盖静态配置的样式字符串,如果设置为 true,则 会 覆盖,如果为 false,则不覆盖,默认为 false。 如果当前是显示某列的标题,则会覆盖它的 labelstyleproperty 属性配 置的样式字符串,如果当前是显示某列的数据,则会覆盖它的 valuestyleproperty 属性配置值。 例如,某个拦截器的此方法代码如下所示: public ColDataByInterceptor beforeDisplayReportDataPerCol( AbsReportType reportTypeObj, ReportRequest rrequest,Object displayColBean, int rowindex,String value) { if(rowindex>=0) return null;//不是显示标题行的列 ColDataByInterceptor cbi=new ColDataByInterceptor(); if(displayColBean instanceof UltraReportListGroupBean) {//是显示的label UltraReportListGroupBean groupbean= 第 52 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> (UltraReportListGroupBean)displayColBean; if("姓名".equals(groupbean.getLabel())) {//如果是label为“姓名”的 cbi.setDynvalue("动态姓名"); } }else if(displayColBean instanceof ColBean) { ColBean cb=(ColBean)displayColBean; if("省份".equals(cb.getLabel())) {//如果是label配置为“省份”的 cbi.setDynvalue("动态省份"); }else if("城市".equals(cb.getLabel())) {//如果是label配置为“城市”的 cbi.setDynvalue("动态城市"); }else if("县城".equals(cb.getLabel())) {//如果是label配置为“县城”的 cbi.setDynvalue("动态县城"); } } return cbi; } 上面代码演示了如何在此方法中动态修改某些数据标题的显示值。 1.10.13 报表后置动作 执行时机 在报表全部显示到前台页面后由框架调用 拦截方法  如果是开发拦截器类,此拦截方法签名为: public void doEnd(ReportRequest rrequest,ReportBean rbean);  如果是在标签中配置拦截器,此拦截方法标签为: < postaction/> 拦截方法说明:  拦截方法参数:与上面“报表前置动作”的拦截方法参数完全一致。  返回值:无 1.10.14 拦截器实现方法比较 报表拦截器有三种方式,开发 JAVA 类、引用资源文件中的拦截器资源项、直接 在报表配置文件中配置拦截器,这三种实现方式的效果完全一样,只是实现方式不同, 它们的差异如下所示:  开发人员开发拦截器 J AVA 类: 第 53 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 优点:1)、方便开发、调试 2)、方便复用,一个拦截器类可以被很多报表引用。 缺点:上线不太方便,因为要更新程序,而不是只更新配置文件就可以维护 报表。  引用资源文件中配置的拦截器资源项 优点:1)、方便复用,一个拦截器资源项可以被很多报表复用。 2)、方便上线,只需更新配置文件就可以增删改拦截器逻辑。 缺点:不方便调试和单元测试。  在标签中配置标签 优点:方便上线,只需更新配置文件就可以增删改拦截器逻辑。 缺点:1)、不方便调试和单元测试。 2)、不能复用。 另外,当一个报表即配置了的 interceptor 属性,又配置了 标签,则不管 interceptor 属性配置为空还是配置为拦截器资源项,或配置为拦截器 J AVA 类,优先级都比标签高,而且此时,配置的拦截器不 起作用。有一个场合就要用上这种优先级特性:假如 A 报表继承 B 报表,B 报表配 置了一个拦截器(不管采用上面三种配置方式的哪一种),但 A 报表不需要 B 报表的 拦截器,此时只需将 A 报表的标签的 interceptor 属性配置为空即可,即 interceptor=””。 1.11 主从报表 1.11.1 概述 主从报表是指一个报表的数据依赖另一个报表的显示/选中的数据,依赖其它报表数据的报表 称为从报表,被其它报表依赖的报表称为主报表。 框架支持一个主报表被多个从报表依赖,被依赖的主报表又是从报表的情况,但不支持一个 从报表依赖多个主报表的情况。 主报表和从报表必须在同一个页面()中,但可以在同一个容器中,也可以分布在不同 的容器当中,还可以在不同的标签页中。 1.11.2 主报表为数据列表报表 是指主报表为 list、editablelist、editablelist2、listform 之一的报表,这种主从报表的从报表数 据是依赖某一条记录。 第一次访问或进行其它刷新页面的操作(比如翻页、查询等)时,从报表显示与本页面第一 条记录相应的数据,并将主报表第一条记录选中。 用户选中其它记录时,则将从报表更新为最新选中的一条记录相应的数据,如果取消选中最 新选中的记录,则从报表显示与最后一条选中记录相应的数据,如果已经没有选中数据,则显示 第一条记录相应的数据,并将主报表第一条记录选中。 在这种主从报表中,从报表永远是独立更新的,不会与其它报表一起更新显示,因此它不存 第 54 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 在与其它报表的条件关联、翻页关联的功能,也不能配置其的 refreshid 属性。 1.11.3 主报表为数据细览报表 是指主报表为 detail、editabledetail、editabledetail2、form 之一的报表,这种主从报表是从报 表依赖主报表当前显示的数据。 当对主报表进行搜索、翻页时,会切换从报表为当前显示的主报表的相应数据。 注意:  如果主报表是细览报表类型,则主从报表不能存在 name 属性相同的查询条件,即 不能存在关联的查询条件,否则可能导致显示不正常  如果一个数据细览报表依赖一个数据自动报表,则它不能再被其它报表依赖,即不 能再做为主报表,  依赖其它细览报表的从细览报表还可以被其它报表依赖,即仍可以做主报表。  数据自动列表报表不管依赖的主报表是细览报表还是列表报表,都可以被其它报表 依赖,即可以做主报表。 1.11.4 配置方法 不管被依赖的主报表是数据列表报表还是细览报表,配置方式都完全一样,通过从报表 标签的如下属性完成:  depends 属性:配置依赖的主报表的的 id 值  dependstype 属性:依赖类型,可配置值有两种:display 和 hidden,配置为 display 时表 示当主报表没有数据时,从报表仍显示出来,只是提示没有数据;配置为 hidden 时,当 主报表没有数据时,则从报表隐藏不显示。默认值为 display。  dependsparams 属性:配置查询或显示从报表数据时,需要用到主报表传过来的哪些参 数值。配置格式为 paramname=paramvalue,如果需要多个参数,用分号“;”分隔。 paramname 根据使用场合分为两种:  如果此参数值是传过来做为查询从报表数据的查询条件,则其必须是从报表某 个查询条件对应的 name 属性(这个查询条件必须是动态条件,且 source 必须为 request,不能是 session,但可以显示输入框,也可以不显示输入 框),这样框架就会将主报表传过来的此参数值做为条件来查询相应的报表数 据。  如果此参数值是用来显示或做其它处理,而不是做为查询从报表数据的查询条 件,则可以取任意值,只要在从报表使用它的时候根据此 paramname 取出参数 值即可。 paramvalue 也有两种:  @{col}格式的参数值,表示从主报表 column 属性为 col 的列取动态值做为参数 值  其它格式的参数值:常量,即除@{col}格式外的所有参数值均视为常量参数值。 注意: 1)、在一个从报表 dependsparams 属性中配置的依赖参数必须包含至少一个动态条 件,即值为@{col}格式的条件,否则无法在从报表中查询出与主报表数据对应的数据 进行显示。可以包含 0 个或多个常量查询条件。 2)、如果多个从报表依赖同一个主报表,则它们在自己的 dependsparams 属性配置 的动态参数中,如果某个动态参数是引用主报表同一列()数据做为参数值,则它 们的动态参数的参数名必须相同。 第 55 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 例如主报表 A 有一列 现在它有二个从报表 B、C,它们的配置如下所示: B 报表: C 报表: ” 因为上面 B、C 报表都依赖主报表 A,且都用到 A 报表的 sno 列做为动态参数 值,所以它们引用此参数值的参数名必须相同,这里都为 txtno,不能 A 叫 txtno1, B 叫 txtno2。  refreshparentonsave 属性:只对从报表为可编辑报表有效,用于配置当保存本从报表数据 时,需要刷新哪个主报表,这里指定需要刷新的报表 ID。 如果只是一层主从关系,则主报表只有一个,如果是多层次主从关系,可以通过此 属性指定保存从报表时刷新哪一个主报表。 在配置这个属性值时,除了可以指定主报表 ID,还可以在后面跟上“|”+true/false, 分别表示刷新主报表时,是否需要重新计算主报表记录数和页码,这对于主报表为分页 显示的报表有用,默认为 false,即不重新计算主报表的页码。 示例请参看 WabacusDemo 关于主从报表部分的演示。 1.12 报表统计 为数据自动列表报表配置数据统计功能是通过标签的子标签完成,针对此报 表的所有统计都配置在此子标签中,具体包括如下几步: 1.12.1 配置当前报表所要用到的所有统计项 所有统计项都定义在标签的子标签中,每个要用到的统计项在 中配置一个子标签 标签包括如下属性: 1) property 属性:用于标识此统计项,稍后格式化方法中也是通过这个配置值来存取此统 计项的数据; 2) value 属性:指定此统计项的值,即当前统计项是对哪个字段做什么类型的统计,wabacus 框架支持如下几种类型的统计: a) avg:取平均数 b) max:取最大值 c) min:取最小值 d) count:统计数量 e) sum:求和 比如 sum(age)、count(*)等等; 3) datatype:指定此统计项的数据类型,与的 datatype 配置方式及意义相同,默认为 字符串类型,即 varchar 类型。 标签包括一个或多个子标签,用于配置统计当前统计项时所需的条件, 每个条件配置一个子标签 这里的子标签与中的子标签配置方法完全一样,不过它有如下 特点:  hidden 属性必须为 true,即使配置为 false 也无效,因为这种条件肯定不会显示条件输入 框 第 56 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  只有一个子标签用于配置条件表达式,不能像中的一样可以配 置其它子标签  这种条件允许配置 constant 属性为 true,即在中配置常量条件表达式。 除上面之外,其它配置完全一样,也支持从 request/session 中取值,条件表达式中的占位 符也完全一样。 例如: sex=0 sex=1 ................... 上面有的统计项指定了数据类型,有的没有指定,这根据使用时是否运算来决定,如果要运算, 则用默认的字符串类型不太方便,需要先转换成数字类型再运算,而声明成相应的类型就可直接进行 运算处理,非常方便。 另外,这里配置统计性别为“男”和“女”的记录数时,为相应的统计项配置了条件, 这里都只配置了一个常量查询条件,如果要配置动态查询条件,则要在条件表达式中用#data#占 位符,同时的 constant 属性要么不配置,要么配置为 false。 中的条件表达式所用到的字段必须是中配置的查询数据 SQL 语句查出来 的字段,且不能带表名。 比如上面用到的 sex,必须是查询报表数据的 SQL 语句查出了名为 sex 的字段,且不能用“表 名.sex”这种格式。 注意:声明成 int 类型,它在 POJO 类中存放成 Integer 类型,声明成 float 类型时,它在 POJO 类中存 放成 Float 类型等等,也就是说数字类型都是存放成外覆类的形式,这一点在运算时需要注意。关于 数据类型的更多介绍,请参看文档中“数据类型的介绍。” 第 57 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 1.12.2 配置要显示的统计行及其上的所有统计列 报表统计分为三种情况: 1、 针对整个报表数据的统计 2、 针对普通行分组报表中某个分组数据的统计 3、 针对树形分组报表中某个分组数据的统计 这三种类型的统计配置方式基本一样,都是将统计信息显示成一行,下面分别介绍它们的配置  针对整个报表数据的统计 这种统计数据显示在报表数据的最后一行,如下图所示: 列一 列二 列三 列四 统计行显示信息  对于不提供列选择功能的报表,统计信息可以显示成一列,也可以配置成多列,每一列 在中配置一个子标签,在此标签中需要通过 colspan 属性指定当前统计 统计列占据的单元格数,必须确保所有统计列的总单元格数与报表的总单元格数相等。  对于提供列选择功能的报表,统计信息只能显示成一列,即只能在中配置一 个子标签,且不能指定其单元格数,,它将占据整行,具体单元格数框架会自动 根据用户当前选择的显示列数来决定。 标签具有如下属性: 1) property 属性:标识此显示列,稍后在格式化方法中读写此列显示信息时,都是通过此 property 属性进行; 2) colspan 属性:指定此统计列所占的单元格个数,如果本报表具有列选择功能,则不能配 置此属性,因为它只能占据整行,究竟占有几个单元格,框架会根据用户当前显示的列 数进行动态计算。如果当前报表没有列选择功能,则需要配置此属性,指定它占的单元 格数。 3) valuestyleproperty 属性:指定当前统计列所在的样式字符串。 例如:某个报表针对整个报表数据的统计配置如下所示: ............. 注意:这里只是配置每个统计列的显示位置信息及样式,具体显示内容需要在下面的 标签配置的格式化方法中对它的 property 属性进行字符串拼凑。  针对普通行分组报表中某个分组数据的统计 对于普通行分组报表,可以针对某个分组列的数据进行统计,这样此分组列中每个分组都会显示 第 58 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 一行统计信息,显示位置为当前分组列的最后一行,如下图所示: 省 市 县 其它列 江西 南昌 进贤 ... 进贤县分组统计信息 高安 ... 高安县分组统计信息 江西省分组统计信息 其它省 ... 全部统计信息 这种统计的配置方法是在标签中为需要统计的分组列配置子标签,它有如 下属性: 1) column 属性:指定当前统计是针对哪个分组列的数据,这里配置此分组列对应的 column 属性,此属性必须配置。 2) condition 属性:配置根据当前分组以及其所有父分组字段找到当前分组记录的条件表达式, 因为执行统计时要用这个条件放在 group by 的 having 子句中。配置条件表达式时,用“%分 组字段的 column 属性% ”做为数据的占位符。比如 condition="province='%province%'" 对于分组字段类型为字符串型、数字型等大部分字段类型,condition 属性是不需要配置的, 框架会自动根据行分组的配置自动生成统计这个分组查询条件。 对于分组列的字段类型为日期类型等有格式的字段类型,框架自动生成的条件表达式可能不 能正确匹配条件值,可能需要转换一下格式才能正确匹配,则需用户自己在 condition 属性中配置 统计此分组的条件表达式,比如 condition=”datediff(createdate,’%createdate%’)==0” 或者 condition=”to_char(createdate,’yyyy-MM-dd’)=’%createdate%’。 在中配置完后,就要配置此分组的统计显示信息,配置方式与上面介绍的 配置针对整个报表统计一样,分两种情况:  对于不提供列选择功能的报表,统计信息可以显示成一列,也可以配置成多列,每一列 在中配置一个子标签,在这里要指定当前统计列要占据的单元格数。  对于提供列选择功能的报表,统计信息只能显示成一列,即只能在中配置一 个子标签,且不能指定其单元格数,它将占据整行,具体单元格数框架会自动根 据用户当前选择的显示列数来决定。 注意:从上面显示行分组统计信息的示意图中可以看出,显示针对某个行分组列的统计信息是从 当前分组列的下一列开始,因此,对于不提供列选择功能的行分组报表,在指定某个分组列的统计信 息所占的 colspan 数时,需要让总的 colspan 数=报表总 colspan 数-当前分组列所在列数。 例如,某个行分组报表配置如下所示: 第 59 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 第 60 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面为 “省”和“县”两个分组列配置了行统计功能,并为整个报表也配置了行统计功能。但 没有为“市”分组列配置行统计功能, 从上面的配置可以看出,显示分组列“省”的行的统计信息的行的起始列为其下一列:“市”,所 以统计行共占据了 9+2=11 列的单元格。 而显示分组列“县”的统计信息的行的起始列为其下一列:“序号”列,所以它占据了 7+2=9 个 单元格。这里为了演示,为它配置了 condition 属性,包括了当前分组列及其所有父分组列的条件表达 式,其实在这里也可以不配置,因为它们的条件表达式都是标准的表达式,没有进行任何转换和运算。 显示整个报表统计信息的行的起始列还是第一列“省”,所以它占据了所有单元格,即 10+2=12 个单元格。 注意:对于不提供列选择功能的报表,即使只配置了一个统计列,也要指定它的 colspan 数。  针对树形分组报表中某个分组数据的统计 对于树形分组报表,也可以针对某个分组列的数据进行统计,配置方法与上面介绍的配置针对普 通行分组列的统计其本一样,但有如下两点不同:  针对树形分组列的统计是配置在标签的标签中,此标签只是名字与 不同,其它完全相同。  树形分组列都是显示在一列中,不像普通行分组,每个分组列显示在一个单独的列中,因此 在计算树形分组统计列的 colspan 时,所有树形分组列,不管处于哪个层次,它们的总 colspan 数都相同,均为报表总 colspan 数-1。 例如,某个树形分组报表配置如下所示: 第 61 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 上面为 “省”和“县”两个树形分组列配置了行统计功能,并为整个报表也配置了行统计功能。 但没有为“市”分组列配置行统计功能, 对于显示“省”和“县”两个树形分组列统计信息的行,其起始列均为“序号”列,即第一个非 树形行分组列,因此统计列的总 colspan 数均为 9 这里为了演示,为“countyname”分组列的配置了 condition,其实也可以不配置, 因为这里配置的条件表达式都是标准的,没有对它们进行任何转换和运算再比较。 上述配置显示效果如下图所示: 第 62 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 列一 列二 列三 列四 列五 - 江西 - 南昌 -进贤 + 福建 + 浙江 本组统计信息 本组统计信息 ... ... ... .... ... ... ... ... ... ... ... ... ... ... ... ... 全部统计信息 1.12.3 通过标签配置各统计列的显示信息 到目前为止,都只是把要用到哪些统计项,要显示哪些统计列,每个统计列显示在什么位置,显 示成什么样式定义好了,但还没有指定每个统计列具体显示信息。 指定每个统计列的显示信息就是通过标签的格式化子标签完成,在这里可以 配置格式化 J AVA 代码,能读写到任意统计列(包括针对分组的和针对整个报表的)的值。 这里的配置与标签中的配置完全相同,在标签中 配置的格式化方法可以对每一个列的数据进行读写,拼凑每一个列的显示(通过的 column/property 属性),同样在这里的格式化方法中,也可以对每一个统计列,统计项的 property 属性 进行读写,拼凑。 回顾上面关于统计列和统计项的配置,可以看到,所有都必须配置 property 属性,而且必须保持唯一,因为它们都会存放在一个 POJO 对象中,它们的 property 就是这个 POJO 相应的成员变量名,这里配置的格式化方法就是此 POJO 类的一个方法,因此可以对所有 property 进 行读写。 对于普通行分组报表和树形分组报表,在格式化相应分组的统计信息时,还可以根据分组列的 column 访问到当前统计数据对应的分组列数据和其所有父分组列的数据。后面会有相关示例 标签配置的 J AVA 代码会放在如下签名的方法中 public void format(ReportRequest rrequest,ReportBean rbean,String type) 框架会在运行时将这三个参数传入,因此用户可以在配置的格式化代码中使用它们。 前面两个参数比较容易理解,最后一个参数 type 表示当前统计的类型, 如果当前是在统计整个报表数据,则 type 属性为空; 如果当前是在统计某个分组列(普通行分组或树形分组),则此 type 传入相应分组列的 column 属性,即对应的的 column 属性值。 用户可以根据 type 决定对哪些的 property 进行赋值显示。 例如,某个树形分组报表部分配置如下所示: .................. 第 63 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> sex=0 sex=1 com.wabacus { colvalue=colvalue+"最大年龄:"+item2+"  "; colvalue=colvalue+"最小年龄:"+item6+"  "; } colvalue=colvalue+"总年龄:"+item4+"  "; colvalue=colvalue+" 最大日期:"+item5; if(type.equals("province")) {//当前正在统计某个“省”分组的数据 col1=province+"省:"+colvalue; }else if(type.equals("cityname")) {//当前正在统计某个“市”分组的数据 col2=province+"省"+cityname+"市:"+colvalue; }else if(type.equals("countyname")) {//当前正在统计某个“县”分组的数据 col3=province+"省"+cityname+"市"+countyname+"县: "+colvalue; }else {//当前正在统计整个报表的数据 col4=colvalue; } ]]> 此配置显示效果如下图所示: 1.12.4 小结 这里再总结一下配置报表统计需要注意的地方: 第 65 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com>  如果一个报表提供客户端动态列选择功能,则在配置统计功能时(不管是针对整个报表的统计、 针对某个普通行分组的统计、还是针对某个树形分组的统计),不能分多列显示这些统计信息, 即不能配置多个,只能配置一个,所有统计信息都显示在此中,此将 会占据整行的单元格(当然对于分组的统计,不会占据分组列所在的单元格),因此,此时的 的 startcolindex 和 colspan 两个属性无效,可以不用配置,因为它会占据整行。  如果一个报表不提供列选择功能,则需要指定每个统计列的 colspan 数 ,且 colspan 数总行必须为 报表显示的单元格数,如果当前报表提供了行选中功能,且行选中类型为单选框或复选框方式, 则需要考虑到自动生成的行选择列。  整个报表中,所有配置的 property 均不能为空,且必须唯一,不能重复。 1.13 交叉统计报表类型 交叉统计报表是一个新的报表类型,在其中必须将它的 type 属性配置“crosslist”。配置 这种类型的报表时,包括如下规则与约束: 1、一个报表中只能配置一个交叉,即一个带有 condition 属性的或。 2、如果交叉是配置在中,则其下所有的子或子配置带 condition 属性,即 不能是普通列。同样如果是配置普通列的,则其下也不能存在配置交叉列的子或 。 3、交叉列因为是动态生成,所以其或或中配置的 valuestyleproperty 或 labelstyleproperty 对所有动态生成的列都有效,且它们不能配置 hidden 属性,都必须为 0。 4、交叉列不能配置 filter 或 clickorderby 属性,不能提供这两种功能,也不能对它们进行搜索。 这些操作只能针对普通列 5、对于交叉列,如果有分组,则一个下面只可以配置一个子或一个,但 可以配置任意层级。不能在中直接配置,必须配置在下面。 6、交叉列的顶层或必须配置 tablename 属性,指定动态列是从哪个表中获取,如 果来自多个表,则 tablename 属性可以配置为从这几个表查询表头的 SQL 语句。 一个可以配置一个或多个,每个配置一个统计类型,统计类型包括如 下几种: avg:取平均数 max:取最大值 min:取最小值 count:统计数量 sum:求和 7、有如下属性: type:配置上面的统计类型之一; column:配置对哪个列进行统计; label:可以配置,也可以不配置,如果配置了,则会为它单独显示一个标题行,如果没有配 置,则不会单独显示标题行,不过如果一个下面配置了两个或以上的,则不管有没有 配置的 label,都会单独显示一个标题行。 labelstyleproperty:当前统计项对应的列标题显示样式,只有要显示它的 label 时才起作用。 valuestyleproperty:当前统计项对应的数据的显示样式。 horizontal:是否对于每一行的统计,都统计一整行的数据,如果配置为 true,则会为每行都 做一次统计,并且显示在每一行的最后。 horizontallabel:显示每一行的统计的列标题,如果配置了 horizontal 为 true,但没有配置此 第 66 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 属性,则会显示 label 配置值。 horizontallabelstyleproperty:显示整行统计列的列标题样式,默认与 labelstyleproperty 相同。 horizontalvaluestyleproperty:显示整行统计列的数据的样式,默认与 valuestyleproperty 相同。 8、配置 SQL 语句时,查询字段中,只需配置非动态列的字段,且在后面要对它们进行 group by。 9、在这种报表类型的的格式化方法中,可以对静态配置数据进行格式化,与其它 报表类型无异。同时还可以对取出的动态列的统计数据进行格式化显示。 所有动态列数据都存放在 POJO 对象的一 Map 对象中,对象名为 mData。此对象的所有 value 即为当前行的各动态列的统计数据。key 为动态列名,所以在中通过 mData 变量名可以格式 化其中的所有数据。 10、对于配置统计信息的,还有如下两个扩展属性: verticalstatistic:是否对于每一统计列,都统计一整列的数据,如果配置为 true,则会在数据 的最后一行,新增一行,显示每一列的统计数据。因为与针对每个整行的统计不同,对每一整列 进行统计必须对所有统计项有效,不能只统计部分统计项,所以此属性没有放在标签 中。而是配置在中。 verticallabel:统计整列的行中,显示的 label。 verticallabelstyleproperty:配置显示统计整列的行的标题样式。 注意,没有 verticavaluestyleproperty 属性,显示针对整列统计的数据的样式采用 中 valuestyleproperty 属性配置值。 11、搜索、列过滤、列排序等功能只能针对固定列,不能针对动态统计列。 12、在中增加一子标签,专门用于配置针对动态表头数据的格式化。 配置方式与普通的一样,也有一子标签和一子标签,分别用于配置导入的 外部包和格式化代码。 这里只能配置针对动态表头的格式化 JAVA 代码,不能配置针对数据的。所有动态表头数据存放 在一个名为 mData 的 HashMap 变量中。mData 的 key 为表头数据的 column 属性值前面加上“_”前 缀,后面加上“_序号”,value 为表头数据。 因此格式化时,先循环此 key,判断是不是以某个“_”+column+“_”为前缀,然后进行相应的 格式化。 例如: ........... 第 67 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> ............ 0) {//查询到了统计数据,对它进行格式化 Iterator itKeys=mData.keySet().iterator(); while(itKeys.hasNext()) { String key=(String)itKeys.next(); String value=(String)mData.get(key); if(key.indexOf("_year_")==0) {//如果是年 if(value!=null&&!value.trim().equals("")) mData.put(key,value+"年"); }else if(key.indexOf("_jd_")==0) {//如果是季度 if(value==null) value=""; if(value.equals("1")) value="第一季度"; else if(value.equals("2")) value="第二季度"; else if(value.equals("3")) value="第三季度"; else if(value.equals("4")) value="第四季度"; mData.put(key,value); } } } ]]> 如果当前报表是继承其它报表,在父报表中对表头数据进行了格式化,而在子报表中不想进行格 式化,则可以将它的配置如下所示: 即将其配置为空字符串即可。这样就会将从父报表中继承过来的针对动态表头数据的格 式化方法去掉。 1.14 输入联想功能  简介:  当用户在文本框中输入数据时,可以一边输入,一边给出提示,相当于 google 搜索框的 第 68 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 功能。  此功能只对文本框有效,对其它输入框类型无效  任意用处的文本框都可以为它配置输入联想功能,配置方式完全一样,包括查询条件输 入框、列编辑输入框等,只要是文本框类型,都支持输入联想功能。  配置: 当没有配置 type 属性,或配置为 textbox,即为文本框时,它支持子标签 ,用于配置输入联想功能,标签包括如下属性:  count 属性:指定显示提示的条数;  width 属性:如果不配置或配置为-1,则与对应文本框保持一致,否则显示为所配 置的宽度。  callbackmethod 属性:配置选中一个选项后,执行的一个客户端回调 JS 函数,此 JS 函数签名如下所示: function callbackmethod(textObj) { } 其中的 textObj 参数就是文本框对象,通过此对象可以取到文本框中选中的选 项数据,因为框架会在将选项数据回填到输入框后再调用这里配置的回调函数 除了上述属性,标签还包括如下子标签:  标签: 配置输入联想的数据源,用于取选项数据。提供数据源的方式有两种:  配置一条 SQL 语句从数据库中查询选项数据 此时,可以直接在的标签内容中配置查询选项数据的 SQL 语句, 也可以在中再配置一个子标签,在其中配置查询选项数据的 SQL 语句,效果完全相同。 在这条 SQL 语句中必须指定如何根据选项列进行条件匹配,以便用户输入时 能将用户输入的字符做为条件传入 sql 语句中取到相应的数据列表。 在 SQL 语句的条件表达式中,以#data#做为用户输入字符的占位符,用户输入 时就会将输入值传到后台做为条件取出相应选项数据出来供用户选择。 例如: select sno,name from tbl_student where sno like '%#data#%' or name like '#data#%' 上面的“学号”的 matchmode 为 2,即任意位置匹配用户输入,所以用 sno like '%#data#%',“中文名”的 matchmode 为 1,即从起始位置开始匹配,所以用 name like '#data#%' 查询数据的 SQL 语句也可以配置动态查询条件,只要先在 SQL 语句的条件 表达式中用{#condition#}做为动态条件占位符,然后为配置一个或多 个子标签,每个子标签配置一个条件及其对应的条件表达式。 第 69 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 这里的与查询下拉框选项数据的配置方式完全相同,不过有一个区 别,就是这里的的 source 必须配置为 session,即只能配置为从 session 中取条件值,不能从 request 中取条件值,例如某个输入框配置如下所示: select no,name from tbl_baseinfo where (no like '%#data#%' or name like '#data#%') and {#condition#} name like '%#data#' sex =#data# 比如在页面拦截器中编写如下代码: rrequest.getRequest().getSession().setAttribute("consex","0"); 则取联想数据时,只会取 sex=0 的记录的“工号”和“姓名”出来做为选项数 据供用户选择。  开发一个继承 AbsTypePromptDataSource 的类,在实现的 getResultDataList()方 法中返回符号条件的结果,在配置时,只需将此标签的 type 属性 配置为此类的全限定类名即可。这种方式可以实现从缓存或其它途径中取选项 数据,非常灵活。 如果自己提供的数据源类需要额外配置,也可以覆写父类的 public void loadExternalConfig(XmlElementBean eleDataSourceBean){}方法进行启动时加载, eleDataSourceBean 对应标签。 具体可以参考测试类com.wabacus.test.TestTypePromptDataSource和框架内置的 数据源类 com.wabacus.config.typeprompt.SQLPromptDataSource 类。  标签 配置输入联想时,提示的每列选项配置为一子标签,此子标签包括如 下属性:  matchmode 属性,当前选项列的匹配模式,如果配置为 0(默认情况),则当前 列不参与输入匹配,只是显示,如果为 1,则从起始位置开始匹配,如果为 2,则 从任意位置匹配用户输入。 一个文本框的输入联想功能,至少要有一提示列的 matchmode 配置为 1 或 第 70 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 2,不能都配置为 0 另外,这里的 matchmode 的匹配模式只对客户端匹配时起作用,在服务器 端的匹配不在此控制,如果是 SQL 语句,就通过条件是用 like 还是用=号进行 匹配,如果是 J AVA 类,则 indexOf()方法是>0 还是==0 决定匹配模式,具体可 以参看 WabacusDemo 的相关演示。  label 属性:配置当前输入联想选项列的显示 label,如果是根据 SQL 语句从数 据库取数据,则这里指定取显示 label 的字段名,如果是从内存中取选项数据,则 这里指定从 Map 对象中取显示 label 的 key。此属性是必需配置的属性  value 属性:配置当前输入联想选项列的值(即选中选项后填到输入框的数据), 如果是根据 SQL 语句从数据库取数据,则这里指定取选项值的字段名,如果是从 内存中取选项数据,则这里指定从 Map 对象中取选项值的 key。只有 matchmode 不为 0,即此列参与匹配时才此属性的配置才有效,因为不参与匹配的列不会将数 据填到输入框中。 如果没有配置 value 属性,或配置为空字符串,则默认为 label 的值,即显示 label 就是它的值,选中此选项后,会把此选项的显示值填到输入框中。  title 属性:配置此输入联想选项列显示在第一行的标题,如果本输入框的输入 联想功能的所有选项都没有配置 title 属性,或者都配置为空字符串,则不会显示标 题行。只要有一个选项列配置了 title 属性且不为空,则会显示标题行。 例如,某列的编辑文本框配置如下所示: select sno,name from tbl_student where sno like '%#data#%' or name like '#data#%' sno 的 matchmode 配置为 2,即从任意位置匹配,所以 sql 语句中用 like '%#data#%'进行 匹配 name 的 matchmode 配置为 1,所以 sql 语句中用 like '#data#%'进行匹配。 如果某个选项列不参与匹配,即 matchmode 为 0,则它不用出现在 where 子句中。 另外,“中文名”选项列配置的 label 为 name,value 为 sno,说明选中匹配的中文名后, 会将对应的 sno 数据填到输入框中。 1.15 常用输入框类型 1.15.1 密码框 密码框配置比较简单,和普通文本框类似,只要将的 type 属性配置为 passwordbox 第 71 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 即可。 在 wabacus 框架中,支持两种类型的密码框:普通密码框和加密密码框。  普通密码框 普通密码框就是一般的密码框,指定的 type 属性配置为 passwordbox 即可, 不用做其它配置。 在前台显示时,密码是什么就会在密码框中显示什么,也就是说密码框中显示的密码就 是真正的密码。  加密密码框 加密密码框在显示密码时,会将密码进行加密后再显示,而不是直接显示密码真正字符 串,不管密码有多少位,都会统一显示成指定位数的密文。在后台保存它们时会将它们解密 成真正的密码进行存储。 配置加密密码框是通过的 encodelength 属性,指定加密后的位数,必须大于 等于 5 位。比如如果配置为 6,则所有密码都会显示成 6 位的密文,而不会显示真正密码到 密码框中。 对于加密密码框,如果编辑旧密码,则需先将密码框中的旧密码全部删除(因为里面存 的是密码加密后的密文),然后重新输入新的密码进行保存,这也比较符合修改密码的习惯。 1.15.2 弹出新窗口输入框 简介 这种输入框类型在主容器是显示为一文本框,点击时会弹出一新层窗口(注意不是新页面),此 窗口嵌入一个开发人员自己的 JSP 页面或 servlet,开发人员在 JSP/servlet 页面中组织选项,当用户选 中好选项后,开发人员调用框架的一个 JS 函数将用户选中的选项值设置到主页面输入框中。 设置值到主页面时,可以只设置到源输入框中,也可以设置到其它输入框中,后面会介绍设置用 户选中值的方法。 配置 这种类型的输入框的有如下属性: width 属性:配置弹出窗口的宽度 height 属性:配置弹出窗口的高度 styleproperty:不是配置弹出窗口的显示样式字符串,而是配置源输入框的显示样式字符串, 也就是 textbox 的样式,比如下面配置为 size=30。 另外,弹出窗口的页面 URL,配置在此标签内容中,即 弹出页面的 URL 在 URL 中可以带上静态和动态参数,动态参数是指以某列的数据做为参数,格式为“参数 名=@{某列对应的的 property}”,例如: 上面的 sname 和 sno 两个参数名对应的参数值分别从 property 为 name 和 sno 的中对应 的字段动态获取,testparam 参数值为一常量 testparamvalue。 第 72 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 开发弹出页面  弹出的页面,即可以是一 JSP,也可以是一 servlet。在此页面程序中,除了可以获取配 置 URL 中所带的参数值,比如获取上面 URL 中传入的两个参数的值: request.getParameter(“sname”)、request.getParameter(“sno”)之外,还可以通过如下几个特 定参数名从 request 中获取到相应的参数值: SRC_PAGEID:当前弹出窗口所属页面 ID; SRC_REPORTGUID:当前弹出窗口所属报表 GUID; INPUTBOXID:源输入框 ID; OLDVALUE:弹出输入框的数据 上面几个参数数据可以按需获取。  在弹出页面的任意位置,调用一下此自定义标签。  在弹出的页面中,可以以任意形式组织数据选择方式,比如以树菜单、表格、单纯复选 框等形式。当选中完后,如果要设置选中值到源输入框,只要调用框架的 javascript 接 口方法 selectOK,传入被选好数据的字符串即可,下面会着重介绍此方法的使用。 selectOK 是框架提供的一个供开发人员在弹出页面设置用户选中值到源页面的输入框上的 接口方法,它的签名如下所示: function selectOK(value,name,label) 说明:  参数 value:需要设置到源页面输入框的值,一般是用户在弹出窗口选中的值,也可以 是其它值;  参数 name:如果用户只是设置新值到弹出窗口的源输入框,即此弹出窗口是点击它才 弹出的,则不用传入此参数,或传入 null 即可。如果用户是设置新值到其它列或输入框, 则需要传入此属性,指定要设置新值到哪个输入框或列中,此参数值分如下几种情况:  如果此弹出新窗口输入框是一个查询条件输入框,则在弹出页面中只能通过 selectOK 方法设置值到本输入框或其它查询条件输入框,如果要设置到其它查询条 件输入框,则在此 name 参数中传入其它查询条件输入框所在的 name 属性即可;  如果此弹出新窗口是可编辑报表的某个编辑列,则在弹出页面中可以通过 selectOK() 方法设置值到本弹出窗口对应的源输入框中,也可以设置到其它列或其上的输入框 中,如果要设置到其它列中,则在此 name 参数中传入其它列的的 column 属 性。被设置的列可以是可编辑列、也可以是不可编辑列,还可以是隐藏列。对于 editablelist2 或 listform 报表类型,只能设置与弹出窗口源输入框所在同一行的其它 列,不能跨行设置到其它列中。 参数 label:此参数对于查询条件上的弹出新窗口输入框没有用,对于可编辑报表上的弹出窗 口输入框,在如下几种情况时,需要通过此参数传入新值对应的显示 label:  本次要设置值的列是不可编辑列,且为其设置的值与显示在上的值不同,则要通过 此参数指定此列使用新值时的显示 label。 比如某个可编辑报表中,有一个 column 为“sex”的不可编辑列,用户显示人员性 别,它的值为 1 时,显示为男,值为 0 时,显示为女,现在要在弹出窗口页面中为它设 置新值“0”,则为了不让它在中显示为“0”,而是显示为“女”,则可以在弹出窗 口中如下调用 selectOK 方法: selectOK(‘0’,’sex’,’女’);  此弹出窗口输入框是在 editablelist2/editabledetail2 其中之一的报表类型的可编辑列中, 第 73 页 Wabacus 框架开发指南(二) 共 200 页 Copyright (C) 2010-2012 星星<349446658@qq.com> 如果需要为其上的下拉框或单选框所在的列设置新值,且新值对应的选项的 value 和 label 不同,则需要为设置的新值指定显示 label。 这是因为这两种报表类型显示时不显示输入框,而是在点击单元格时才显示输入 框,对于值与显示 label 相同的输入框,这没有什么问题,但对于值与显示 label 不同的 输入框,比如下拉框或单选框,则为其设置新值时,不想在单元格中也显示这个值,而 是显示此值对应的 label,此时就要在弹出窗口页面中为要设置的新值指定显示 label。 例如,editablelist2/editabledetail2 有一个 column 为 sex 的性别列,是可编辑的,显 示为单选框,“0”值对应“女”,“1”值对应“男”,现在在弹出窗口页面需要为它设置 新值“1”,则需要如下方法调用 selectOK 才能确保它的值被设置为“1”,显示单元格时 显示为“男”:selectOK(‘1’,’sex’,’男’); 对于设置其它类型输入框或列的值,只要调用 selectOK(value,name)或 selectOK(value)即可, 注意:不仅可以设置参与本次显示的列的值,还可以设置隐藏列的值。 小结:  在弹出窗口设置值到源输入框时,只要调用 selectOK(value)即可,后面的 name 和 label 参数不需要。  如果要在弹出窗口设置值到其它输入框或列,只能设置到与弹出窗口的源输入框同 类的列或输入框中,具体包括如下几个方面:  查询条件上的弹出窗口输入框弹出的页面上,只能设置值到其它查询条件输入 框中,不能设置到编辑列中;  可编辑细览报表的编辑列上的弹出窗口输入框弹出的页面上,只能设置值到本 报表的其它编辑列或输入框中;  可编辑数据自动列表报表或列表表单中上的弹出窗口输入框的弹出页面上,只 能设置值到与弹出窗口源输入框所在同一行的其它列或输入框中,不能跨行设置, 如果要跨行设置,则通过后面介绍的专门设置数据到编辑列或输入框的接口方法完 成。 1.15.3 单选框 单选框即 html 中的 radio,在 wabacus 框架中声明某个输入框为单选框时,只需将 的 type 指定为 radiobox 即可。 一个单选框会包括很多单选项,为配置单选项是通过