在基于 JSF 的富企业应用程序中实现单元格高亮显示(第 1 部分)

作者:Lucas Jellema ACE 总监

在您的 JavaServer Faces 应用程序中,通过实现单元格高亮显示来帮助您的最终用户整理信息。

2008 年 11 月发表

面向数据的应用程序趋向于用信息淹没最终用户。一行行的数据,虽然整齐地排列在列和单元格内,但是多少有一点让人应接不暇。某些数据记录的重要性通常会因彩色高亮显示单元格而变得更加明显。不同的颜色指明不同的记录状态。颜色可以让那些由于某种原因需要特别注意的记录很容易被找到。

Oracle Discoverer、Microsoft Excel 和 Oracle Application Express 等工具提供了允许最终用户指定筛选条件然后用于彩色高亮显示的功能。例如,阈值高亮显示,不同的值范围用不同的颜色标识:少于 2000、在 2000 到 3000 之间和高于 3000 的工资都拥有各自指定的颜色。另一种高亮显示基于筛选表达式:例如 JOB <> 'MANAGER' and SAL > 3000 或 JOB = 'CLERK' or SAL < 1500 等表达式。每一个筛选表达式都可以和一种颜色相关联。

本文是系列文章(共两篇)中的第一篇,在本文中,您将了解如何在 JavaServer Faces (JSF) 应用程序中实现此类高亮显示,尤其是如何在 Oracle 应用开发框架 (ADF) Faces 表组件中实现此类高亮显示。您将了解使用 Oracle ADF 11g Rich Faces 作为 JSF 实施如何添加用户控制的阈值或红绿灯高亮显示。用户指定支持阈值高亮显示的每一列和要使用的颜色。在重新查询数据和对记录进行排序时,仍然保留这些设置。当数据发生更改时,高亮显示也随之进行相应调整。

系列中的第二篇文章为最终用户带来了更多功能:文章描述了如何添加最终用户功能以动态添加、更新和删除所需数量的阈值。文章不仅介绍了简单的阈值模式,还提供了基于表达式的筛选。最终用户可以设置一个或多个引用数据记录中所有属性的表达式。记录满足的第一个表达式将决定单元格的颜色。

在本文中,您将使用一个简单的 Oracle ADF Faces 表页面。您可以自己轻松创建,也可以下载带有起始点的 ZIP 文件。后一种方法的优势是不需要在数据库中检索数据。

自行创建起始点(使用数据库)

启动 Oracle JDeveloper。选择 File, New 然后选择 General 类别下的 Application 项目启动 Greate Application 对话框,使用该对话框创建一个新的应用程序。选择 Web Application (JSF, ADF BC) 模板。向导会自动创建一个 Model 和一个 ViewController 项目。

在 New Gallery 中,从 Tables 中选择选项 (Business Tier, ADF Business Components) Business Components。选择(如果需要,首先创建)一个到其他数据库中的 SCOTT 模式的数据库连接。为表 EMP 创建一个 Entity Object Emp 并为 Emp Entity 创建一个默认的 ViewObject EmpView。调用应用程序模块 HrmManager。

Oracle ADF 业务组件中用于 NUMBER 数据类型列的默认数据类型是 oracle.jbo.domain.Number。JSF 中的 EL 引擎并不识别此高度灵活、功能丰富的类型。因此,我们要编辑 Emp Entity Object 并将 Sal 属性的类型从 Number 改为 Double。对于 Comm 属性重复上述操作。最后,设置 Deptno 属性的类型为 Integer。

当您查看 Data Control Palette 时,您将在 HrmManager 数据控件中看到 EmpView 集合 — 这正是我们开始使用您的 Web 应用程序所需要的。

使用给定起始点(无需数据库)

使用给定的 Oracle JDeveloper Application ADFCellHighlighting_StartingPoint 来实现单元格高亮显示将简单一些且具有同样的指导性。它包括一个 Model 和 ViewController 项目。后者为空,前者包含三个类:HrmManager、EmpManager(单体)和 Emp。Emp 和 EmpManager 类从 EMP 表生成,产生一个离线(无数据库)数据源。本网志条目详细解释如何完成此操作并且还提供了从数据库表中生成这些非连接数据源的代码。

HrmManager 类作为 DataControl 发布。因此,empscollection 将出现在 Data Control Palette 上。

第 1 步:创建 EMP 表页面

我们首先创建将应用单元格高亮显示的 JSF 页面。在 ViewController 项目中,选择 New Gallery 中的 (Web Tier, JSF) JSF JSP。调用新文件 EmpTable.jspx 并单击 Finish

现在,一个空页面将显示在页面编辑器中。从 Data Control Palette 中,拖动 EmpView 集合(基于 ADF BC 和 数据库)或 emps 集合(在 empManager 下,基于非连接 Bean)并将其作为 ADF Table 放下。在 Edit Table Columns 对话框中,指定列顺序和提示定义(如下图所示)并启用 Sorting:

图
图 1 Edit Table Columns 对话框

单击 OK。页面编辑器显示。从鼠标右键菜单中,选择 Go to Page Definition。将 EmpView iterator(基于 ADF BC)或 empsIterator accessorIterator(基于 Bean)上的 rangeSize 属性从 10 更改为 -1(以便在页面中所有记录显示)。

从鼠标右键菜单中选择 Run 查看活动的页面。这时,您应该可以看到此页面在您的浏览器中处于运行状态。(注:您可能需要为一些 inputText 元素调整列属性以便让所有列都拥有合适的宽度):

图
图 2 显示所有记录的页面

 

第 2 步:基于静态阈值的单元格高亮显示

您的第一步将是向 EmpTable 页面添加静态单元格高亮显示。主要是 Salary 单元格。为了快速深入了解工资的分发,您希望将少于 1000 的工资高亮显示为绿色,高于 3000 的显示为红色,而其余的显示为浅灰色。

给单元格着色的最简单方法是通过 inputText Sal 元素上的 contentStyle 属性,如下所示:

contentStyle="background-color:#{(row.sal lt 1000)?'green':(row.sal gt 3000?'red':'lightgray')};"
现在使用用于设置 CSS 属性背景颜色的 EL 表达式内的一个三重表达式,指定当 row.sal (显示在当前单元格内的值)小于 1000 时,表达式将会等于绿色。否则,由嵌套的表达式判断 row.sal 是否大于 3000 来决定结果。如果是肯定的,结果将为红色,如果是否定的,结果将为浅灰色。

图
图 3 Salary 值高亮显示

如果您的 Data Control 基于 EmpView 集合而不是离线 HrmManager Bean,您需要将 row.sal 改为 row.Sal — S 大写。

您可以运行页面并查看高亮显示的工资。如果您更改工资值并单击任一列标题进行排序,您将看到高亮显示随更新的值进行调整:

图
图 4 对 Salary 值的调整

 

第 3 步:允许动态阈值和颜色

第一步提供了单元格高亮显示。然而,这样的高亮显示是非常静态的 — 基于 JSF 页面中的硬编码值 1000 和 3000。明显不是最动态的方法。让我们用托管 Bean 属性引用代替硬编码的阈值,之后您可以允许我们的最终用户操作这些属性。

首先,将 Sal 的 inputText 中的 contentStyle 属性更改为:

contentStyle="background-color:#{(row.Sal lt EmpThresholdHighlighter.lowThreshold)
        ?EmpThresholdHighlighter.lowAreaColor:
   (( row.Sal gt EmpThresholdHighlighter.highThreshold)
            ?EmpThresholdHighlighter.highAreaColor:EmpThresholdHighlighter.middleAreaColor)};"
注:当您使用基于数据控件的 Bean 时,请使用 row.sal(小写字母 S)。

您将会注意到您不仅用 Bean 引用替换了硬编码的阈值,而且您也替换了颜色。表达式现在指向 EmpThresholdHighlighter.lowAreaColor 和 EmpThresholdHighlighter.highAreaColor,而不是红色和绿色。

托管 Bean EmpThresholdHighlighter 在 adfc config.xml 中的配置如下:
<managed-bean>
    <managed-bean-name>EmpThresholdHighlighter</managed-bean-name>
    <managed-bean-class>otn.cellhighlighting.jsf.ThreshholdHighlightBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>
它基于的类是一个拥有以下五个属性的 JavaBean:lowThreshold、highThreshold 和三种颜色:lowAreaColor、middleAreaColor 和 highAreaColor。
package otn.cellhighlighting.jsf;
public class ThreshholdHighlightBean {

    private Long lowThreshold = new Long(1000);
    private Long highThreshold = new Long(3000);

    private String lowAreaColor ="green";
    private String middleAreaColor ="lightgray";
    private String highAreaColor ="red";

    public ThreshholdHighlightBean() {
    }
... accessor methods (getters and setters) for all properties
}
现在,您可以运行页面,得到的结果与第一步一样。不同的是,您已允许用户更改阈值和颜色。

您需要向页面添加一个面板,以便用户指定这些值。添加下列 showDetailHeader 到页面中,将它插入下列表:

<af:showDetailHeader text="Highlight Settings for Employees Table"
                             disclosed="true"
                             inlineStyle="border-color:Gray; border-style:double; width:367px;">
              <af:panelFormLayout>
                <af:inputText label="Lower Threshold"
                              value="#{EmpThresholdHighlighter.lowThreshold}"/>
<af:inputText label="High Threshold"
value="#{EmpThresholdHighlighter.highThreshold}"/>
<af:objectSpacer width="10" height="10"/>
<af:inputText label="Low Area Color"
value="#{EmpThresholdHighlighter.lowAreaColor}"/>
<af:inputText label="Medium Area Color"
value="#{EmpThresholdHighlighter.middleAreaColor}"/>
<af:inputText label="High Area Color"
value="#{EmpThresholdHighlighter.highAreaColor}"/>
</af:panelForm>
</af:panelHeader>
<af:commandButton text="Apply Highlighting" partialSubmit="true"
id="doHighlight"/>
</af:showDetailHeader>
commandButton doHighlight 使得 partialSubmit 属性被设为“true”。单击该按钮时,这个面板中的设置就会立即应用。如果表对按下按钮做出响应,部分页面刷新可以更新表里的高亮显示设置。当您将按钮的 ID 添加到表的 partialTriggers 属性时就会发生以上情况:
<af:table value="#{bindings.EmpManageremps.collectionModel}" var="row"
                    partialTriggers="doHighlight"
                   ...
现在,当您运行页面时,您可以对以下三个范围内的阈值设置和颜色进行操作:低、中和高。

图
图 5 操作阈值设置和颜色

 

第 4 步:使用颜色选择器来选择高亮显示颜色

通过键入颜色的 CCS 术语名称来设置颜色看起来有些奇怪,尤其是当 Oracle ADF Faces 有一个颜色选择器组件时。那么,现在就让我们使用这个组件以一种更友好的方式来设置颜色。

颜色选择器组件设置的值属于 java.awt.Color 类型。您需要修改 ThreshholdHighlightBean 来适应这一设置。首先,删除现有颜色属性(lowAreaColor、middleAreaColor、highAreaColor)以及它们的 setter 办法。

然后,添加这些属性并生成相关访问器:

    private Color lowColor = new Color(153, 255, 153); // greenish
    private Color middleColor = new Color(255, 255, 150); // yellow
    private Color highColor = new Color(255, 190, 190); // red
实施 getter 方法 getLowAreaColor、getMiddleAreaColor 和 getHighAreaColor,如下所示:
public String getLowAreaColor() {
        return this.lowAreaColor == null ? "" :
               "rgb(" + this.lowColor.getRed() + "," +
               this.lowColor.getGreen() + "," +
               this.lowColor.getBlue() + ")";
    }
删除三个 inputText 元素。现在您需要添加颜色选择器组件以设置三个阈值颜色。下面是一个设置 Low Area Color 选择器的例子;另外两个与其相似:
<af:panelLabelAndMessage label="Low Area Color">
              <af:inputColor id="lowAreaColor" chooseId="chooseLow"
                             value="#{EmpThresholdHighlighter.lowColor}"
                             compact="true"/>
<af:chooseColor id="chooseLow" defaultVisible="false"
lastUsedVisible="false"/>
</af:panelLabelAndMessage>
注:inputColor 组件显示其值属性内当前设置的颜色。它接受在具有 chooseId 属性指定的 ID 的 chooseColor 组件中所做的新颜色选择。

现在,继续为 Medium Area Color 和 High Area Color 添加颜色选择器。您需要稍微重新组织 Highlight Settings 面板以适应 Choose Color 组件的大小。完成上述操作的一种方法是使用 \。

<af:panelGroupLayout layout="horizontal" valign="top">
      <af:panelFormLayout rows="2">
         ... the two inputText elements ...   
      </af:panelFormLayout>
      the three panelLabelAndMessage components with the inputColor & chooseColor
</af:panelGroupLayout>
当您接下来运行 EmpTable 页面时,您将看到可以简化高亮显示颜色选择的 Color Picker 面板。

图
图 6 颜色选择器面板

 

第 5 步:在弹出面板中进行高亮显示设置

最终用户在其表中设置单元格高亮显示的简便性无可置疑。然而,用于高亮显示设置的面板在页面上占用了太多的空间 — 并且这只用于单一列的设置。至少,我们希望仅在需要检查或更改的时候出现此面板,或者让它不要占用过多的空间。在这最后一步,您将引入一个可以从 Sal 列标题调用的弹出面板。这也为多列单元格高亮显示做好了铺垫。多列高亮显示以及基于表达式的高亮显示都是本系列第二部分的一个主题。

ADF 11g Rich Faces 还给我们提供了一个真正的弹出组件。我们将使用此组件将单元格高亮显示控件放入一个只在显式调用时显示的 panelWindow 中。

我们向 Salary 列标题中添加一个单击后显示弹出窗口的图标。要完成此操作,先删除列的 headerText 属性,然后将 header facet 添加到列内,并将其内容配置为:

<af:column sortProperty="sal" sortable="true">
            <f:facet name="header">
              <af:panelGroupLayout layout="horizontal">
                <af:outputText value="#{bindings.emps.hints.sal.label}"/>
<af:image shortDesc="Open Cell Highlight Settings Window"
source="/highlightIcon.gif">
<af:showPopupBehavior popupId=":CellHighlightThresholdSettings"
triggerType="click"/>
</af:image>
</af:panelGroupLayout>
</f:facet>
af:image 中的 showPopupBehavior 子元素是显示弹出窗口的关键。它通过 triggerType 属性指定,单击它的父元素(图标)时,ID 为 CellHighlightThresholdSettings 的弹出窗口将显示。弹出窗口自身将会用所有高亮显示的输入组件替代 showDetailHeader 容器。只需以下编码即可替代 showDetailHeader 组件:
        <af:popup id="CellHighlightThresholdSettings">
          <af:panelWindow title="Highlight Settings for Employees Table">
... same contents as before
          </af:panelWindow>
        </af:popup>
您现在已经创建了一个含有 panelWindow 的弹出窗口。弹出窗口最初不显示;只有在某些操作显式调用它时,它才会显示 — 例如单击列标题中的高亮显示图标。

现在,当您运行页面时,它看起来将会是一个非常普通的表页面,只是在 Sal 列标题中有一个小图标:

图
图 7 Sal 列标题中的“高亮显示”图标

将鼠标移动至高亮显示图标上,高亮显示设置面板现在就会出现:

图
图 8 高亮显示设置面板

用户可以进行所需的更改,然后单击 Apply Highlighting 使修改后的表重新显示。

结论

在这个关于 Oracle ADF 单元格高亮显示的系列(共两篇)文章的第一篇中,您已经了解了如何快速地向 Oracle ADF Faces 数据表中添加静态高亮显示。使用 EL 表达式让高亮显示变得简单。之后,您扩展了该功能,为最终用户提供了更多控制:通过托管 Bean 我们将阈值和相关联颜色动态化,并且提供给用户一个用于操作这些设置的面板。在最后一步,您将此面板内嵌入在列自身中。该面板现在仅在用户需要时显示,让页面使用起来更加方便。

第 2 部分通过几种方式扩展高亮显示功能。您将在同一个表中添加多列高亮显示支持,使 Hiredate 列根据经验(绿色明显表示出经验较少的)高亮显示,并使 Salary 列指明员工的收入类别。您还将允许动态阈值定义:用户可以添加所需数量的阈值,而本次安装中只支持两个。最后,最令人感兴趣的是添加基于表达式的高亮显示。可以基于在一条记录中引用所有属性(甚至包括未显示的属性)的公式高亮显示单元格。

 请阅读本系列的第 2 部分


Lucas Jellema 是荷兰 Nieuwegein AMIS 的 CTO 和 Oracle ACE 总监(开发人员工具)。他参加的项目主要涉及 ADF 和 SOA。此外,他经常出席甲骨文全球大会和 JavaOne,同时也是一位经常发表文章的网志作者