在 WebLogic Workshop 中使用 ICEfaces 入门
页面: 1, 2

现在,表格内容类似于以下代码:

<ice:dataTable rows="5"

               value="#{customers.customers}" 
               var="customer"
              id="custTable"
              sortColumn="#{customers.sortColumnName}"
              sortAscending="#{customers.sortAscending}">
  <h:column>
    <f:facet name="header">
      <ice:panelGroup>
        <ice:commandSortHeader columnName="id" arrow="true">
          <h:outputText value="Id"/>
        </ice:commandSortHeader>
      </ice:panelGroup>
    </f:facet>
    <h:outputText value="#{customer.id}"/>
  </h:column>
  <h:column>
    <f:facet name="header">
      <h:outputText value="First"/>
    </f:facet>
    <h:outputText value="#{customer.first}"/>
  </h:column>
  <h:column>
    <f:facet name="header">
      <ice:panelGroup>
        <ice:commandSortHeader columnName="LastName" arrow="true">
          <h:outputText value="Last"/>
        </ice:commandSortHeader>
      </ice:panelGroup>
    </f:facet>
    <h:outputText value="#{customer.last}"/>
  </h:column>
  ...
</ice:dataTable>

视图选项卡中的最后一个组件将用于向表格中添加分页(pagination)。选择dataTable标记,然后在属性视图中将行数设置为5从而限制每页所显示的行数。接下来,拖动一个dataPaginator标记到数据表格下方。在对话框中,将For字段设置为表格的id(在本例中为custTable),然后选中Paginator筛选框(如果未选中这个筛选框,则该控件可用于显示“Page 1 of 12”之类的信息而不是支持切换页面的按钮)。单击Navigator属性旁边的“...”按钮可以为各个控件(first, next, last, previous)指定图像或文本。完成这些操作之后,标记内容将类似于以下代码:

<ice:dataPaginator id="custTableScroller"
                   for="custTable"
                   paginator="true">
  <f:facet name="first">
    <h:graphicImage style="border:none;"
                    url="/css/xp/css-images/arrow-first.gif"/>
  </f:facet>
  <f:facet name="previous">
    <h:graphicImage style="border:none;" 
                    url="/css/xp/css-images/arrow-previous.gif"/>
  </f:facet>
  ...
</ice:dataPaginator>

此处引用的图像是直接复制到Web应用程序中的,不过它也包含在运行时中并且可以作为./xmlhttp/css/xp/css-images/x.gif被引用。但是,Workshop JSP设计视图引用它时会有些问题,因为它不知道如何转换该路径并在运行时jar文件中找到该图像。因此我们将在示例中使用本地副本以保证设计视图可以正常运行。

Datatable
图2.设计视图中的用户设计表格

再重申一次,project.zip中含有完整的代码。现在,我们可以再次运行应用程序并验证一下排序和分页功能。

使用异步请求添加数据

第二个选项卡将包含一个表单,用于向列表添加用户。对于本例而言,我们只需将用户添加到一个由后备bean维护的列表中,不过在实际应用程序中该数据将存储在数据库或一些其他的后备存储器中。要演示ICEfaces的异步特性,数据将以异步请求的方式发送,并且将显示出一个模式对话框通知用户新用户已添加。

在tabset中的第二个选项卡中,拖放出一个panelGrid标记并将其设置为三行两列。列和行是隐藏的。panelGrid的子节点是一组panelGroup标记,行/列布局是根据方格(grid)中的列数目而决定的。在本例中,每行都需要有一个标签和一个文本框,对应于用户的姓氏(last name)和名称(first name)属性。通过绑定到customers.newCustomer.address.*属性,我们还可以添加更多行以表示新用户的地址。最后一行需要使用一个commandButton来真正保存数据:

<ice:panelGrid columns="2" width="100%">
  <ice:panelGroup>
    <f:verbatim>First Name:</f:verbatim>
  </ice:panelGroup>
  <ice:panelGroup>
    <ice:inputText value="#{customers.newCustomer.first}"/>
  </ice:panelGroup>
  <ice:panelGroup>
    <f:verbatim>Last Name:</f:verbatim>
  </ice:panelGroup>
  <ice:panelGroup>
    <ice:inputText value="#{customers.newCustomer.last}"/>
  </ice:panelGroup>
  <ice:panelGroup>
    <ice:commandButton
           actionListener="#{customers.customerSaved}"
           value="Add"/>
  </ice:panelGroup>
  <ice:panelGroup></ice:panelGroup>
</ice:panelGrid>

Customers后备bean中有一个newCustomer属性,该属性是添加的Customer对象的占位符。此处的输入文本框与该对象的属性绑定在一起。后备bean还有一个动作监听方法customerSaved,单击命令按钮(command button)时将调用该方法。这样将会“保存”新用户,并重置newCustomer对象从而清除表单中的内容。

Customer Form
图3.设计视图中的用户输入表单

现在,我们还需要实现通知用户新用户已添加的对话框。ICEfaces提供了一个panelPopup标记,该标记可以使用样式模拟常规HTML DOM中的对话框。它有一个visible属性,可以绑定后备bean属性中的数据。customers bean将公开一个此处可以使用的属性,当添加了一个用户时该属性将被设置为true;当对话框解除后该属性将重置为false。

考虑到模式对话框的作用域,我们必须将其包含在它自己的form标记中。因此,首先在表单下面创建一个新表单用于封装数据表格。接下来,拖放一个panelPopup标记到该表单中。在属性视图中,将visible属性绑定到customers后备bean中的popupVisible属性。panelPopup使用了两个面(facet)——header和body——来设置对话框的标题栏和主体内容。在这两个面中加入消息,并在主体(body)中添加一个commandButton标记,用于调用后备bean中的closeNewCustomerPopup动作监听方法。其代码如下所示:

<ice:form>
  <ice:panelPopup visible="#{customers.popupVisible}"
                  modal="true">
    <f:facet name="header">
      <f:verbatim>Customer Added</f:verbatim>
    </f:facet>
    <f:facet name="body">
      <ice:panelGrid columns="1" width="100%">
        <ice:panelGroup>
          <ice:outputFormat
               value="Customer {0} {1} added with id {2}">
            <f:param value="#{customers.lastCustomer.first}"/>
            <f:param value="#{customers.lastCustomer.last}"/>
            <f:param value="#{customers.lastCustomer.id}"/>
          </ice:outputFormat>
        </ice:panelGroup>
        <ice:panelGroup>
          <ice:commandButton
               actionListener="#{customers.closeNewCustomerPopup}"
               value="Close"/>
        </ice:panelGroup>
      </ice:panelGrid>
    </f:facet>
  </ice:panelPopup>
</ice:form>

设计视图中也将呈现该对话框,如图4所示。

Customer Dialog
图4.设计视图中的用户通知对话框

再次运行应用程序,这时可以添加用户了,并且可以切换回第一个选项卡查看数据表格中的改动,而不需要刷新整个页面。图5显示了输入表单。

Customer Form Runtime
图5.运行时的用户输入表单

添加一个用户后将出现图6所示的对话框。

Customer Dialog Runtime
图6.运行时的用户通知对话框

故障排除

有一点值得谨记于心:由于ICEfaces在服务器中保存了一个可呈现的DOM(将会在JSF生命周期中更新),因此在迭代开发过程中这个DOM会比较难以同步。发生这种情况时,服务器会报错:非法的DOM层次结构请求。一般而言,可以重新发布应用程序,或者(如果该方法不起作用)重新启动服务器绕过这一错误。

在进行ICEfaces开发时还有一点值得注意:即所有的JSP文件都是有效的XML格式。ICEfaces解析器将不会接受任何JSP指令。

最后,使用JSF开发时通常需要确保使用适当的扩展名发起页面请求——在本例中为*.iface。如果使用*.jsp扩展名发起请求,那么将无法调用ICEfaces servlet,而且JSP也无法正确执行。

结束语

通过这个示例应用程序,我们了解了ICEfaces框架的一些基本功能。ICEfaces中还提供了许多其他的控件,并且还有很技巧(比如说部分表单提交)并没有在本文中介绍。

要进一步熟悉ICEfaces,也可以使用一个无格式的JSF应用程序,将其中的JSF HTML标记替换为等价的ICEfaces标记。在一些情况下,这种简单的步骤可以赋予应用程序一些Ajax功能,而不需要额外的工作。ICfcs发行版中含有一些示例和教程,可以将它们导入Workshop内部支持ICEfaces的Web应用程序中。

参考资料