数 据 表 DataTable

数 据 表
  
  
  
  
  
  
  本章主题
● 数据表标签——h:dataTable
● 一个简单的表
● 表头、表尾和标题
● JSF组件
● 编辑表元
● 样式
● 数据库表
● 表模型
● 滚动技术
  经典Web应用程序常用于处理表格数据。以前,除了作为页面的布局管理器之外,HTML表格最适合这个任务。多数情况下,页面布局都由CSS来完成,但显示制表数据仍然非常重要。
  本章讨论h:dataTable标签,它是一个能够操作制表数据、适合显示数据但功能有限的组件。

  说明
  h:dataTable标签表示一个合格的组件/呈现器对。例如,可以在表元中非常容易地显示JSF组件、添加表头和表尾、使用CSS类操作表的外观。但是,h:dataTable缺乏一些高端特性,这些特性可能是即开即用的,例如,如果想排序表的列,那么必须写一些代码来完成它。参考5.8.2节的“排序和过滤”获得关于如何完成排序的更多细节。
  
5.1 数据表标签——h:dataTable
  h:dataTable标签遍历数据来创建HTML表格。下面的代码片段演示了如何使用它:
<h:dataTable value='#{items}' var='item'>
<h:column>
<%-- left column components --%>
<h:output_text value='#{item.propertyName}'/>
</h:column>

<h:column>
<%-- next column components --%>
<h:output_text value='#{item.anotherPropertyName}'/>
</h:column>

<%-- add more columns, as desired --%>
</h:dataTable>
  其中,Value属性表示h:dataTable遍历的数据;这些数据必须是下列之一:
● 一个Java对象
● 一个数组
● java.util.List的一个实例
● java.sql.ResultSet的一个实例
● javax.servlet.jsp.jstl.sql.Result的一个实例
● javax.faces.model.DataModel的一个实例
  当h:dataTable遍历的时候,它将数组、列表、结果集中的每个项都放到该标签的主体中。项的名称由h:dataTable的var属性指定。在上面的代码段中,当h:dataTable在集合中迭代的时候,集合(项集)中的每个项都依次可用。使用当前项的属性填充为当前行产生列的值。
  也可以为h:dataTable的value属性指定任何Java对象,尽管这样做的有效性值得怀疑。如果对象是分等级的(意味着它不是某种集合),h:dataTable遍历一次,对象就能在标签的主体中使用。
  h:dataTable标签的主体可以仅包含h:column标签;h:dataTable忽略所有其他组件标签。除了可选的表头和表尾组件之外,每个列可以包含任意多个的组件。
  h:dataTable将一个UIData组件和一个表呈现器配对。这种结合提供了功能强大的表格生成能力,包括支持CSS样式、数据库访问、自定义表模型和更多的特性。我们以一个简单表为例开始h:dataTable的学习。
5.2 一个简单的表
  图5-1显示了一个包含人名的表。

图5-1 一个简单表
  图5-1所示程序的目录结构显示在图5-2中。程序的JSF页面在程序清单5-1中给出。

图5-2 简单表的目录结构
  在程序清单5-1中,我们使用h:dataTable来遍历names(名字)数组。姓后面是逗号,它们位于左列,名则放在右列。
  本例中的名称数组由JSF管理的bean来实现。该Bean是com.corejsf.TableData的实例,程序清单5-3显示了这个类。程序清单5-2显示了Name类。faces配置文件和消息资源包相应地显示在程序清单5-4和5-5中。
程序清单5-1 simple/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <title>
7. <h:outputText value="#{msgs.windowTitle}"/>
8. </title>
9. </head>
10.
11. <body>
12. <h:outputText value="#{msgs.pageTitle}"/>
13. <p>
14. <h:form>
15. <h:dataTable value="#{tableData.names}"
16. var="name">
17. <h:column>
18. <h:outputText value="#{name.last}, "/>
19. </h:column>
20.
21. <h:column>
22. <h:outputText value="#{name.first}"/>
23. </h:column>
24. </h:dataTable>
25. </h:form>
26. </body>
27. </f:view>
28. </html>
  
程序清单5-2 simple/src/java/com/corejsf/Name.java
1. package com.corejsf;
2.
3. public class Name {
4. private String first;
5. private String last;
6.
7. public Name(String first, String last) {
8. this.first = first;
9. this.last = last;
10. }
11.
12. public void setFirst(String newValue) { first = newValue; }
13. public String getFirst() { return first; }
14.
15. public void setLast(String newValue) { last = newValue; }
16. public String getLast() { return last; }
17. }
  
程序清单5-3 simple/src/java/com/corejsf/TableData.java
1. package com.corejsf;
2.
3. public class TableData {
4. private static final Name[] names = new Name[] {
5. new Name("William", "Dupont"),
6. new Name("Anna", "Keeney"),
7. new Name("Mariko", "Randor"),
8. new Name("John", "Wilson")
9. };
10.
11. public Name[] getNames() { return names;}
12. }
  
程序清单5-4 simple/web/WEB-INF/faces-config.xml
1. <?xml version="1.0"?>
2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
5. http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
6. version="1.2">
7. <application>
8. <resource-bundle>
9. <base-name>com.corejsf.messages</base-name>
10. <var>msgs</var>
11. </resource-bundle>
12. </application>
13.
14. <managed-bean>
15. <managed-bean-name>tableData</managed-bean-name>
16. <managed-bean-class>com.corejsf.TableData</managed-bean-class>
17. <managed-bean-scope>session</managed-bean-scope>
18. </managed-bean>
19. </faces-config>
  
程序清单5-5 simple/src/java/com/corejsf/messages.properties
1. windowTitle=A Simple Table
2. pageTitle=An array of names:
  
  图5-1中的表固然简单,但本章后面,我们将探讨如何为表添加额外的特性,例如CSS样式和列表头。首先,我们简单介绍一下h:dataTable的属性。

  注意
  h:dataTable数据是基于行的——例如,程序清单5-3中的名字对应于表的行,但是名字并未说明在每列中如何存储——这取决于页面作者指定的列内容。基于行的数据可能与读者使用的数据不同;例如,Swing表模型跟踪每行和列中的数据。
  
5.2.1 h:dataTable属性
  h:dataTable属性列在表5-1中。
表5-1 h:dataTable的属性
属 性
描 述
bgcolor
表的背景色
border
表边框的宽度
captionClass (JSF 1.2)
表标题的CSS类
captionStyle (JSF 1.2)
表标题的CSS样式
cellpadding
表格单元的填充
cellspacing
表格单元的间隔
columnClasses
用于列,逗号分隔的CSS类列表
dir
未继承方向性文本的文本方向;有效值:LTR(从左到右)和RTL(从右到左)
first
在表中显示的相对0索引的第一行
footerClass
表尾的CSS类
frame
表周围框架的边的说明;有效值:none、above、below、hsides、vsides、lhs、rhs、box、border
headerClass
表头的CSS类
rowClasses
列的CSS类列表,由逗号分隔
rows
在表中显示的行数,以first属性指定的行开始;如果将该值设置为0,所有表行都将显示。
rules
表元间绘制的线的说明;有效值:groups、rows、columns、all
summary
表格用途及结构的概述,用于非可视反馈设备,如语音阅读器
var
由数据表创建的变量的名称,它表示当前项的值。
binding、id、rendered、styleClass、value
基本属性
lang、style、title、width
HTML 4.0
onclick、ondblclick、onkeydown、onkeypress、onkeyup、onmousedown、onmousemove、onmouseout、onmouseover、onmouseup
DHTML事件
  
  binding和id属性在第4章4.2节中“ID和绑定”部分讨论,rendered属性在第4章4.2节“JSF HTML标签概述”中讨论。
  h:dataTable也拥有完整的DHTML事件和HTML 4.0传递属性。可以在第4章中看到关于这些属性的信息。
  first属性在表中指定一个相对于0索引的可视行。value属性指向h:dataTable遍历的数据。在每次遍历的开始,h:dataTable创建一个请求作用域的变量,使用这个变量命名h:dataTable的var属性。在h:dataTable标签的主体中,可以使用这个名称引用当前项。
5.2.2 h:column属性
  h:column属性列在表5-2中。
表5-2 h:column的属性
属 性
描 述
footerClass (JSF 1.2)
列表尾的CSS类
headerClass (JSF 1.2)
列表头的CSS类
binding、id、rendered、styleClass、value
基本属性
  
5.3 表头、表尾和标题
  如果像我们在5.2节“一个简单表”中做的那样显示一个名字的列表,那么需要将姓与名相区别。可以通过添加列标题来完成,如图5-3中所示。

图5-3 指定列表头和表尾
  除了表头之外,图5-3中的列还包含说明相应列数据类型的表尾,两列都是[alpha],用于文字和数字的混合格式。
  列表头和表尾都是由约束指定的,如下所示:
<h:dataTable>
...
<h:column headerClass="columnHeader"
         footerClass="columnFooter">
<f:facet name="header">
<%-- header components go here --%>
</f:facet>

<%-- column components go here --%>

<f:facet name="footer">
<%-- footer components go here --%>
</f:facet>
</h:column>
...
</h:dataTable>
  
  h:dataTable将由表头和表尾约束指定的组件分别放到HTML表格的表头和表尾中。这里使用h:column的headerClass 和footerClass属性为列表头和表尾指定CSS样式。这些属性对于JSF 1.2是新属性。
  JSF 1.2将表标题添加到了h:dataTable。添加一个标题约束到h:dataTable标签,如下所示:
<h:dataTable ...>
<f:facet name="caption">
An array of names:
</f:facet>
</h:dataTable>
  
  如果将这个约束添加到图5-3所示的表中,将看到如图5-4所示的结果:

图5-4 一个表标题
  可以使用captionStyle和captionClass为标题指定样式或CSS类:
<h:dataTable ... captionClass="caption">
<f:facet name="caption">
An array of names:
</f:facet>
</h:dataTable>

  在上述代码段中,我们为约束使用了一些普通文本,但,与所有约束一样,可以指定一个JSF组件替代。
  图5-4中JSF页面的全部代码在程序清单5-6中给出。程序的资源包显示在程序清单5-7中。程序的目录结构与图5-2显示的结构相同。
  读者可能注意到了,我们为输出组件使用style属性并通过它格式化列表头和表尾。参考第4章的“HTML 4.0属性”获得更多关于style属性的知识,以及5.6节“样式”中关于CSS样式类和JSF表的知识。
程序清单5-6 headersAndFooters/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <link href="styles.css" rel="stylesheet" type="text/css"/>
7. <title>
8. <h:outputText value="#{msgs.windowTitle}"/>
9. </title>
10. </head>
11. <body>
12. <h:form>
13. <h:dataTable value="#{tableData.names}"
14. var="name"
15. captionStyle="font-size: 0.95em; font-style:italic"
16. style="width: 250px;">
17.
18. <f:facet name="caption">
19. <h:outputText value="An array of names:"/>
20. </f:facet>
21.
22. <h:column headerClass="columnHeader"
23. footerClass="columnFooter">
24. <f:facet name="header">
25. <h:outputText value="#{msgs.lastnameColumn}"/>
26. </f:facet>
27.
28. <h:outputText value="#{name.last}"/>
29.
30. <f:facet name="footer">
31. <h:outputText value="#{msgs.alphanumeric}"/>
32. </f:facet>
33. </h:column>
34.
35. <h:column headerClass="columnHeader"
36. footerClass="columnFooter">
37. <f:facet name="header">
38. <h:outputText value="#{msgs.firstnameColumn}"/>
39. </f:facet>
40.
41. <h:outputText value="#{name.first}"/>
42.
43. <f:facet name="footer">
44. <h:outputText value="#{msgs.alphanumeric}"/>
45. </f:facet>
46. </h:column>
47. </h:dataTable>
48. </h:form>
49. </body>
50. </f:view>
51. </html>
  
程序清单5-7 headersAndFooters/src/java/corejsf/messages.properties
1. windowTitle=Headers, Footers, and Captions
2. lastnameColumn=Last Name
3. firstnameColumn=First Name
4. editColumn=Edit
5. alphanumeric=[alpha]
  

  提示
  为了在表头或表尾放置多个组件,必须在h:panelGroup标签中将它们分组,或者使用h:panelGrid 或h:dataTable将它们放在容器组件中。如果在约束中放置了多个组件,那么只有第一个组件会显示。
5.4 JSF组件
  到现在为止,我们仅在表列中使用了输出组件,但也可以在表元中放置任何JSF组件。图5-5显示了表中使用不同组件的应用。

图5-5 表元中的JSF组件
  h:dataTable对数据进行遍历,因此图5-5中的表提供了一列整数来表示这一结果。我们使用当前整型来配置"Number", "Textfields", "Buttons"和"Menu"列的组件。
  表中的组件与表外的组件没有不同;可以以任何喜欢的方式操作它们,包括使用rendered属性来呈现它们、处理事件之类。
  图5-5中程序的目录结构显示在图5-6中。JSF页面、约束配置文件和属性资源包在程序清单5-8~5-10中给出。

图5-6 组件例子的目录结构
程序清单5-8 components/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <link href="styles.css" rel="stylesheet" type="text/css"/>
7. <title>
8. <h:outputText value="#{msgs.windowTitle}"/>
9. </title>
10. </head>
11. <body style="background: #eee">
12. <h:form>
13. <h:dataTable value="#{numberList}" var="number">
14. <h:column>
15. <f:facet name="header">
16. <h:outputText value="#{msgs.numberHeader}"/>
17. </f:facet>
18. <h:outputText value="#{number}"/>
19. </h:column>
20. <h:column>
21. <f:facet name="header">
22. <h:outputText value="#{msgs.textfieldHeader}"/>
23. </f:facet>
24. <h:inputText value="#{number}" size="3"/>
25. </h:column>
26. <h:column>
27. <f:facet name="header">
28. <h:outputText value="#{msgs.buttonHeader}"/>
29. </f:facet>
30. <h:commandButton value="#{number}"/>
31. </h:column>
32. <h:column>
33. <f:facet name="header">
34. <h:outputText value="#{msgs.checkboxHeader}"/>
35. </f:facet>
36. <h:selectBooleanCheckbox value="false"/>
37. </h:column>
38. <h:column>
39. <f:facet name="header">
40. <h:outputText value="#{msgs.linkHeader}"/>
41. </f:facet>
42. <h:commandLink>
43. <h:outputText value="#{number}"/>
44. </h:commandLink>
45. </h:column>
46. <h:column>
47. <f:facet name="header">
48. <h:outputText value="#{msgs.graphicHeader}"/>
49. </f:facet>
50. <h:graphicImage value="images/dice#{number}.gif"
51. style="border: 0px"/>
52. </h:column>
53. <h:column>
54. <f:facet name="header">
55. <h:outputText value="#{msgs.menuHeader}"/>
56. </f:facet>
57. <h:selectOneMenu>
58. <f:selectItem itemLabel="#{number}" itemValue="#{number}"/>
59. </h:selectOneMenu>
60. </h:column>
61. <h:column>
62. <f:facet name="header">
63. <h:outputText value="#{msgs.radioHeader}"/>
64. </f:facet>
65. <h:selectOneRadio layout="LINE_DIRECTION" value="nextMonth">
66. <f:selectItem itemValue="yes" itemLabel="yes"/>
67. <f:selectItem itemValue="no" itemLabel="no" />
68. </h:selectOneRadio>
69. </h:column>
70. <h:column>
71. <f:facet name="header">
72. <h:outputText value="#{msgs.listboxHeader}"/>
73. </f:facet>
74. <h:selectOneListbox size="3">
75. <f:selectItem itemValue="yes" itemLabel="yes"/>
76. <f:selectItem itemValue="maybe" itemLabel="maybe"/>
77. <f:selectItem itemValue="no" itemLabel="no" />
78. <f:selectItem itemValue="ok" itemLabel="ok" />
79. </h:selectOneListbox>
80. </h:column>
81. </h:dataTable>
82. </h:form>
83. </body>
84. </f:view>
85. </html>
  
程序清单5-9 components/web/WEB-INF/faces-config.xml
1. <?xml version="1.0"?>
2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
5. http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
6. version="1.2">
7. <application>
8. <resource-bundle>
9. <base-name>com.corejsf.messages</base-name>
10. <var>msgs</var>
11. </resource-bundle>
12. </application>
13.
14. <managed-bean>
15. <managed-bean-name>numberList</managed-bean-name>
16. <managed-bean-class>java.util.ArrayList</managed-bean-class>
17. <managed-bean-scope>session</managed-bean-scope>
18. <list-entries>
19. <value>1</value>
20. <value>2</value>
21. <value>3</value>
22. <value>4</value>
23. <value>5</value>
24. </list-entries>
25. </managed-bean>
26. </faces-config>
  
程序清单5-10 components/src/java/com/corejsf/messages.properties
1. windowTitle=Using JSF Components in Tables
2.
3. numberHeader=Number
4. textfieldHeader=Textfields
5. buttonHeader=Buttons
6. checkboxHeader=Checkboxes
7. linkHeader=Links
8. menuHeader=Menu
9. graphicHeader=Graphics
10. radioHeader=Radio Buttons
11. listboxHeader=List Boxes
  
5.5 编辑表元
  为了编辑表元,需要为相应的表元提供一个输入组件。图5-7中的程序允许编辑所有表元。单击复选框以编辑一行,然后单击“Save Changes”按钮来保存修改。图5-7按顺序从上到下显示了编辑表元的过程。

图5-7 编辑表元
  编辑表元时,表元使用一个输入组件;未被编辑时,使用一个输出组件。下面是它如何被实现的代码:
...
<h:dataTable value='#{tableData.names}' var='name'>
<!-- checkbox column -->
<h:column>
<f:facet name='header'>
<h:output_text value='#{msgs.editColumn}'
style='font-weight: bold'/>
</f:facet>

<h:selectBooleanCheckbox value='#{name.editable}'
οnclick='submit()' />
</h:column>

<!-- last name column -->
<h:column>
...
<h:inputText value='#{name.last}'
rendered='#{name.editable}'
size='10'/>

<h:outputText value='#{name.last}'
rendered='#{not name.editable}'/>
</h:column>
...
</h:dataTable>
<p>
<h:commandButton value="#{msgs.saveChangesButtonText}"/>
...
  上述代码段仅列出了复选框和名字列的代码。复选框的值与当前名字是否可编辑对应;如果可编辑,复选框选中。为名字指定两个组件:h:inputText 和h:outputText。如果名字是可编辑的,会显示输入组件。如果名字不可编辑,则会显示输出组件。
  图5-7中JSF页面的全部代码在程序清单5-11中给出。程序的消息资源包显示在程序清单5-12中。程序的目录结构与图5-2显示的相同。
程序清单5-11 editing/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <title>
7. <h:outputText value="#{msgs.windowTitle}"/>
8. </title>
9. </head>
10. <body>
11. <h:form>
12. <h:dataTable value="#{tableData.names}" var="name">
13. <h:column>
14. <f:facet name="header">
15. <h:outputText value="#{msgs.editColumn}"
16. style="font-weight: bold"/>
17. </f:facet>
18. <h:selectBooleanCheckbox value="#{name.editable}"
19. οnclick="submit()"/>
20. </h:column>
21. <h:column>
22. <f:facet name="header">
23. <h:outputText value="#{msgs.lastnameColumn}"
24. style="font-weight: bold"/>
25. </f:facet>
26. <h:inputText value="#{name.last}" rendered="#{name.editable}"
27. size="10"/>
28. <h:outputText value="#{name.last}"
29. rendered="#{not name.editable}"/>
30. </h:column>
31. <h:column>
32. <f:facet name="header">
33. <h:outputText value="#{msgs.firstnameColumn}"
34. style="font-weight: bold"/>
35. </f:facet>
36. <h:inputText value="#{name.first}"
37. rendered="#{name.editable}" size="10"/>
38. <h:outputText value="#{name.first}"
39. rendered="#{not name.editable}"/>
40. </h:column>
41. </h:dataTable>
42. <h:commandButton value="#{msgs.saveChangesButtonText}"/>
43. </h:form>
44. </body>
45. </f:view>
46. </html>
  
程序清单5-12 editing/src/java/com/corejsf/messages.properties
1. windowTitle=Editing Table Cells
2. lastnameColumn=Last Name
3. firstnameColumn=First Name
4. editColumn=Edit
5. alphanumeric=[alpha]
6. saveChangesButtonText=Save changes
  

  说明
  表元编辑,如5.5节“编辑表元”中展示的,可以用于所有有效表数据类型:Java对象、数组、列表、结果集和结果。但是,对于数据库表,与表相关的结果集必须对于JSF实现可更新以更新数据库。
  
5.6 样式
  h:dataTable具有指定CSS类的属性,如下所示:
● 作为一个整体的表(styleClass)
● 列表头和表尾(headerClass和footerClass)
● 单列(columnClasses)
● 单行(rowClasses)
  图5-8中的表使用了styleClass、headerClass和columnClasses。

图5-8 为列和表头应用样式
  

  说明
  h:dataTable的rowClasses和columnClasses属性是互斥的。如果两个都指定,columnClasses具有高优先级。
  
5.6.1 列样式
  下面是指定图5-8中CSS类的代码:
<link href='styles.css' rel='stylesheet' type='text/css'/>
...
<h:dataTable value="#{order.all}" var="order"
styleClass="orders"
headerClass="ordersHeader"
columnClasses="oddColumn,evenColumn">
  
  下面列出了这些CSS类:
.orders {
border: thin solid black;
}
.ordersHeader {
text-align: center;
font-style: italic;
color: Snow;
background: Teal;
}
.oddColumn {
height: 25px;
text-align: center;
background: MediumTurquoise;
}
.evenColumn {
text-align: center;
background: PowderBlue;
}
  
  我们仅指定了两个列类,但是却有五列。在这个例子中,h:dataTable重用列类,从第一个开始。通过仅指定前两个列的类,可以为奇数和偶数列(基于1计数)设置CSS类。
5.6.2 行样式
  可以使用rowClasses属性为行而不是列指定CSS类,如图5-9所示。这个数据表的实现如下:
<link href='styles.css' rel='stylesheet' type='text/css'/>
...
<h:dataTable value="#{order.all}" var="order"
styleClass="orders"
headerClass="ordersHeader"
rowClasses="oddRow,evenRow">

图5-9 为行应用样式
  像列类一样,h:dataTable在类数小于行数的时候重用行类。在上述代码段中,我们已经利用了这个特性来为奇数和偶数行指定CSS类。

  注意
  为了演示,我们在样式类中使用了颜色名称,例如PowderBlue和Medium-Turquoise。也可以给出相应的十六进制常数,因为它们是可以移植的,而颜色名称则不是。
  
5.7 数据库表
  数据库在表中存储信息,因此,JSF数据表组件非常适合显示数据库中存储的数据。在本节,我们将演示如何显示数据库的结果。
  图5-10展示了一个显示数据库表的JSF程序。
  图5-10中的JSF页面使用h:dataTable,如下所示:
<h:dataTable value="#{customer.all}" var="currentCustomer"
styleClass="customers"
headerClass="customersHeader"
columnClasses="custid,name">
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.customerIdHeader}"/>
</f:facet>
<h:outputText value="#{currentCustomer.Cust_ID}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.nameHeader}"/>
</f:facet>
<h:outputText value="#{currentCustomer.Name}"/>
</h:column>
...
</h:dataTable>


图5-10 显示数据库表
  Customer bean是一个受JSF管理的bean,它知道如何连接数据库并在数据库中完成所有的顾客查询。CustomerBean.all方法完成这个查询。
  上述JSF页面通过应用列名访问列数据——例如,#{customer.Cust_ID}引用Cust_ID列。
  数据库例子的目录结构显示在图5-11中。程序的列表在程序清单5-13~5-16中给出。

图5-11 数据库例子的目录结构
程序清单5-13 database/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <link href="styles.css" rel="stylesheet" type="text/css"/>
7. <title>
8. <h:outputText value="#{msgs.pageTitle}"/>
9. </title>
10. </head>
11. <body>
12. <h:form>
13. <h:dataTable value="#{customer.all}" var="customer"
14. styleClass="customers"
15. headerClass="customersHeader" columnClasses="custid,name">
16. <h:column>
17. <f:facet name="header">
18. <h:outputText value="#{msgs.customerIdHeader}"/>
19. </f:facet>
20. <h:outputText value="#{customer.Cust_ID}"/>
21. </h:column>
22. <h:column>
23. <f:facet name="header">
24. <h:outputText value="#{msgs.nameHeader}"/>
25. </f:facet>
26. <h:outputText value="#{customer.Name}"/>
27. </h:column>
28. <h:column>
29. <f:facet name="header">
30. <h:outputText value="#{msgs.phoneHeader}"/>
31. </f:facet>
32. <h:outputText value="#{customer.Phone_Number}"/>
33. </h:column>
34. <h:column>
35. <f:facet name="header">
36. <h:outputText value="#{msgs.addressHeader}"/>
37. </f:facet>
38. <h:outputText value="#{customer.Street_Address}"/>
39. </h:column>
40. <h:column>
41. <f:facet name="header">
42. <h:outputText value="#{msgs.cityHeader}"/>
43. </f:facet>
44. <h:outputText value="#{customer.City}"/>
45. </h:column>
46. <h:column>
47. <f:facet name="header">
48. <h:outputText value="#{msgs.stateHeader}"/>
49. </f:facet>
50. <h:outputText value="#{customer.State}"/>
51. </h:column>
52. </h:dataTable>
53. </h:form>
54. </body>
55. </f:view>
56. </html>
  
程序清单5-14 database/src/java/com/corejsf/CustomerBean.java
1. package com.corejsf;
2.
3. import java.sql.Connection;
4. import java.sql.ResultSet;
5. import java.sql.SQLException;
6. import java.sql.Statement;
7. import javax.naming.Context;
8. import javax.naming.InitialContext;
9. import javax.naming.NamingException;
10. import javax.servlet.jsp.jstl.sql.Result;
11. import javax.servlet.jsp.jstl.sql.ResultSupport;
12. import javax.sql.DataSource;
13.
14. public class CustomerBean {
15. private Connection conn;
16.
17. public void open() throws SQLException, NamingException {
18. if (conn != null) return;
19. Context ctx = new InitialContext();
20. DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
21. conn = ds.getConnection();
22. }
23.
24. public Result getAll() throws SQLException, NamingException {
25. try {
26. open();
27. Statement stmt = conn.createStatement();
28. ResultSet result = stmt.executeQuery("SELECT * FROM Customers");
29. return ResultSupport.toResult(result);
30. } finally {
31. close();
32. }
33. }
34.
35. public void close() throws SQLException {
36. if (conn == null) return;
37. conn.close();
38. conn = null;
39. }
40. }
  
程序清单5-15 database/web/WEB-INF/web.xml
1. <?xml version="1.0"?>
2. <web-app xmlns="http://java.sun.com/xml/ns/javaee"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
5. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
6. version="2.5">
7. <servlet>
8. <servlet-name>Faces Servlet</servlet-name>
9. <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
10. <load-on-startup>1</load-on-startup>
11. </servlet>
12.
13. <servlet-mapping>
14. <servlet-name>Faces Servlet</servlet-name>
15. <url-pattern>*.faces</url-pattern>
16. </servlet-mapping>
17.
18. <welcome-file-list>
19. <welcome-file>index.html</welcome-file>
20. </welcome-file-list>
21.
22. <resource-ref>
23. <res-ref-name>jdbc/mydb</res-ref-name>
24. <res-type>javax.sql.DataSource</res-type>
25. <res-auth>Container</res-auth>
26. </resource-ref>
27. </web-app>
程序清单5-16 database/src/java/com/corejsf/messages.properties
1. pageTitle=Displaying Database Tables
2. customerIdHeader=Customer ID
3. nameHeader=Name
4. phoneHeader=Phone Number
5. addressHeader=Address
6. cityHeader=City
7. stateHeader=State
8. refreshFromDB=Read from database
  
JSTL结果与结果集比较
  h:dataTable的值可以是其他类型,javax.servlet.jsp.jstl.Result的实例或java.sql.ResultSet的实例——就像5.7节“数据库表”中的例子一样。h:dataTable将这些对象包装在ResultDataModel 和ResultSetDataModel的实例中。那么,模型有什么不同呢?读者喜欢哪个呢?
  如果使用结果集,则需要知道它们是临时存在的对象,需要许多编程控制。JSTL结果类是一个bean,它包装结果集并且实现编程控制;结果要比结果集易于控制。
  另一方面,在结果中包装结果集会导致创建结果对象的额外开销;应用程序可能无法经受性能的下降。
  在5.7节“数据库表”部分讨论的程序中,我们按照上述建议,从CustomerBean.all方法中返回了一个JSTL Result对象。
5.8 表模型
  当使用一个Java对象、数组、列表、结果集或结果对象来表示表数据的时,h:dataTable在一个继承javax.faces.model.DataModel类的模型中封装这些对象。下列模型类都位于javax.faces.model包中:
● ArrayDataModel
● ListDataModel
● ResultDataModel
● ResultSetDataModel
● ScalarDataModel
  h:dataTable处理上述列出的模型;它不直接访问对象——数组、列表等,需要使用value属性来指定。但是,也可以使用DataModel.getWrappedData方法来访问这些对象。这个方法用于添加和删除表行。
5.8.1 编辑表模型
  使用所有数据模型都提供的两个方法:getWrappedData() and setWrappedData(),来添加和删除表行是非常容易的。现在,我们来看看在程序中如何运用它,如图5-12所示,它使用户能够从表中删除行。

图5-12 删除表行
  从上到下,图5-12显示了删除一行的过程。当用户单击“Delete selected names”按钮的时候,JSF实现调用删除选定行的动作监听器方法。这个方法如下所示:
public String deleteNames() {
if (!getAnyNamesMarkedForDeletion())
return null;

Name[] currentNames = (Name[]) model.getWrappedData();
Name[] newNames = new Name[currentNames.length -
getNumberOfNamesMarkedForDeletion()];

int i=0;
for (Name name : currentNames) {
if (!name.isMarkedForDeletion()) {
newNames[i++] = name;
}
}
model.setWrappedData(newNames);
return null;
}
}
  
  deleteNames方法通过调用模型的getWrappedData方法得到名字当前集合的引用。然后,它创建一个新数组,数组的大小是当前数组大小减去标记为删除名字的数量。接着,这个方法将每个当前名字添加到新数组,删除标记为删除的名字。最后,这个方法调用模型的setWrappedData方法以使用新名字数组重置模型。
  当单击“Delete selected names”的时候,JSF实现调用TableData.deleteNames方法。deleteNames方法通过调用数据模型的getWrappedData方法获得当前名字数组的引用。deleteNames方法接着创建一个新数组——不包含标记为删除的名字——它使用setWrappedData方法将数组存储到模型中。
  尽管上述例子没有演示添加行,但是它却演示了这个原则:获取当前对象,模型使用getWrappedData()来包装它,修改它(通过添加或删除行),然后使用setWrappedData()重置包装的对象。
  图5-13显示了程序的目录结构。程序清单5-17~5-19列出了图5-12中程序的相关文件。

图5-13 删除例子的目录结构


  说明
  调用模型的方法来重置模型的数据,是删除行的一个方法。我们也可以这样重置模型本身:
model = new ArrayDataModel(newNames);  
  
程序清单5-17 delete/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <link href="styles.css" rel="stylesheet" type="text/css"/>
7. <title>
8. <h:outputText value="#{msgs.windowTitle}"/>
9. </title>
10. </head>
11. <body>
12. <h:form>
13. <h:dataTable value="#{tableData.names}" var="name"
14. styleClass="names" headerClass="namesHeader"
15. columnClasses="last,first">
16. <h:column rendered="#{tableData.editable}">
17. <f:facet name="header">
18. <h:outputText value="#{msgs.deleteColumnHeader}"/>
19. </f:facet>
20. <h:selectBooleanCheckbox value="#{name.markedForDeletion}"
21. οnchange="submit()"/>
22. </h:column>
23. <h:column>
24. <f:facet name="header">
25. <h:outputText value="#{msgs.lastColumnHeader}"/>
26. </f:facet>
27. <h:outputText value="#{name.last},"/>
28. </h:column>
29. <h:column>
30. <f:facet name="header">
31. <h:outputText value="#{msgs.firstColumnHeader}"/>
32. </f:facet>
33. <h:outputText value="#{name.first}"/>
34. </h:column>
35. </h:dataTable>
36. <h:outputText value="#{msgs.editPrompt}"/>
37. <h:selectBooleanCheckbox οnchange="submit()"
38. value="#{tableData.editable}"/>
39. <h:commandButton value="#{msgs.deleteButtonText}"
40. rendered="#{tableData.editable}"
41. action="#{tableData.deleteNames}"
42. disabled="#{not tableData.anyNamesMarkedForDeletion}"/>
43. </h:form>
44. </body>
45. </f:view>
46. </html>
  
程序清单5-18 delete/src/java/com/corejsf/Name.java
1. package com.corejsf;
2.
3. public class Name {
4. private String first;
5. private String last;
6. private boolean markedForDeletion = false;
7.
8. public Name(String first, String last) {
9. this.first = first;
10. this.last = last;
11. }
12.
13. public void setFirst(String newValue) { first = newValue; }
14. public String getFirst() { return first; }
15.
16. public void setLast(String newValue) { last = newValue; }
17. public String getLast() { return last; }
18.
19. public boolean isMarkedForDeletion() { return markedForDeletion; }
20. public void setMarkedForDeletion(boolean newValue) {
21. markedForDeletion = newValue;
22. }
23. }
  
程序清单5-19 delete/src/java/com/corejsf/TableData.java
1. package com.corejsf;
2.
3. import javax.faces.model.DataModel;
4. import javax.faces.model.ArrayDataModel;
5.
6. public class TableData {
7. private boolean editable = false;
8. private ArrayDataModel model = null;
9.
10. private static final Name[] names = {
11. new Name("Anna", "Keeney"),
12. new Name("John", "Wilson"),
13. new Name("Mariko", "Randor"),
14. new Name("William", "Dupont"),
15. };
16.
17. public TableData() { model = new ArrayDataModel(names); }
18.
19. public DataModel getNames() { return model; }
20.
21. public boolean isEditable() { return editable; }
22. public void setEditable(boolean newValue) { editable = newValue; }
23.
24. public String deleteNames() {
25. if (!getAnyNamesMarkedForDeletion())
26. return null;
27.
28. Name[] currentNames = (Name[]) model.getWrappedData();
29. Name[] newNames = new Name[currentNames.length
30. - getNumberOfNamesMarkedForDeletion()];
31.
32. for(int i = 0, j = 0; i < currentNames.length; ++i) {
33. Name name = (Name) currentNames[i];
34. if (!name.isMarkedForDeletion()) {
35. newNames[j++] = name;
36. }
37. }
38. model.setWrappedData(newNames);
39. return null;
40. }
41.
42. public int getNumberOfNamesMarkedForDeletion() {
43. Name[] currentNames = (Name[]) model.getWrappedData();
44. int cnt = 0;
45.
46. for(int i = 0; i < currentNames.length; ++i) {
47. Name name = (Name) currentNames[i];
48. if (name.isMarkedForDeletion())
49. ++cnt;
50. }
51. return cnt;
52. }
53.
54. public boolean getAnyNamesMarkedForDeletion() {
55. Name[] currentNames = (Name[]) model.getWrappedData();
56. for(int i = 0; i < currentNames.length; ++i) {
57. Name name = (Name) currentNames[i];
58. if (name.isMarkedForDeletion())
59. return true;
60. }
61. return false;
62. }
63. }
  我们已经学习了如何在数据模型上完成简单的操作。有时,需要一些更复杂的操作——例如,当对模型数据分类和选取的时候。
5.8.2 排序和过滤
  为了使用h:dataTable分类和选取表格,需要实现一个表模型,它修饰(decorate)前面列出的表模型中的一个模型。图5-14显示了修饰表模型的意思。

图5-14 数据模型过滤器
  UIData的实例——与h:dataTable相关联的组件——调用它们模型的方法。当修饰模型的时候,模型截取这些方法调用。修饰器模型向前提交方法调用到原始模型,除了setRowIndex方法之外,它返回排序的索引而不是原始模型的索引。接下来,我们看看它如何工作。
  图5-15显示了5.5节“编辑表元”中讨论的程序,重写以支持可排序表列。

图5-15 排序表列
  图5-15中的程序通过修饰表数据模型来分类表格的列。首先,我们指定h:dataTable的value属性,如下:
<h:dataTable value="#{tableData.names}" var="name" ...>
...
  
  TableData.names方法返回一个数据模型:
public class TableData {
private DataModel filterModel= null;
private static final Name[] names = {
new Name("Anna", "Keeney"),
new Name("John", "Wilson"),
new Name("Mariko", "Randor"),
new Name("William", "Dupont"),
};

public TableData() {
ArrayDataModel model = new ArrayDataModel(names);
filterModel = new SortFilterModel(model);
}
public DataModel getNames() {
return filterModel;
}
}
  
  当创建tableData对象的时候,它创建一个ArrayDataModel实例,将名字数组传递给它。这就是原始模型。然后,TableData构造器将该模型封装到分类(sorting)模型中。随后,当调用getNames方法来产生数据表时,方法返回分类的模型。分类模型的实现如下:

public class SortFilterModel extends DataModel {
private DataModel model;
private Row[] rows;
...
public SortFilterModel(DataModel model) {
this.model = model;
int rowCnt = model.getRowCount();
if (rowCnt != -1) {
rows = new Row[rowCnt];
for (int i=0; i < rowCnt; ++i) {
rows[i] = new Row(i);
}
}
public void setRowIndex(int rowIndex) {
if (rowIndex == -1 || rowIndex >= model.getRowCount()) {
model.setRowIndex(rowIndex);
}
else {
model.setRowIndex(rows[rowIndex].row);
}
}
...
}
  
  注意,我们创建了一个表示排序索引的索引数组。如果需要的索引在范围内,我们从setRowIndex方法返回一个排序索引。
  那么排序是如何发生的呢?SortFilterModel类提供了两个方法,sortByFirst() 和sortByLast():
public String sortByLast() {
Arrays.sort(rows, byLast);
return null;
}

public String sortByFirst() {
Arrays.sort(rows, byFirst);
return null;
}

  byLast和byFirst变量是比较符。前者比较姓,后者比较名。可以参考程序清单5-21中比较符的实现。
  图5-16显示了排序例子的目录结构。程序清单5-20~5-26提供了程序的完整列表。

图5-16 排序例子的目录结构

  说明
  JSF 1.2规范建议,具体的DataModel类至少提供两个构造器:一个调用setWrappedData(null)的无参数构造器和传递包装数据到setWrappedData()的构造器。参考程序清单5-21中构造器的例子。
程序清单5-20 sorting/web/index.jsp
1. <html>
2. <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
3. <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
4. <f:view>
5. <head>
6. <link href="site.css" rel="stylesheet" type="text/css"/>
7. <title>
8. <h:outputText value="#{msgs.windowTitle}"/>
9. </title>
10. </head>
11. <body>
12. <h:form>
13. <h:dataTable value="#{tableData.names}" var="name"
14. styleClass="names" headerClass="namesHeader"
15. columnClasses="last,first">
16. <h:column>
17. <f:facet name="header">
18. <h:outputText value="#{msgs.deleteColumnHeader}"/>
19. </f:facet>
20. <h:selectBooleanCheckbox
21. value="#{name.markedForDeletion}"
22. οnchange="submit()"/>
23. </h:column>
24.
25. <h:column>
26. <f:facet name="header">
27. <h:commandLink action="#{tableData.names.sortByLast}">
28. <h:outputText value="#{msgs.lastColumnHeader}"/>
29. </h:commandLink>
30. </f:facet>
31. <h:outputText value="#{name.last}, "/>
32. </h:column>
33. <h:column>
34. <f:facet name="header">
35. <h:commandLink action="#{tableData.names.sortByFirst}">
36. <h:outputText value="#{msgs.firstColumnHeader}"/>
37. </h:commandLink>
38. </f:facet>
39. <h:outputText value="#{name.first}"/>
40. </h:column>
41. </h:dataTable>
42. <h:commandButton value="#{msgs.deleteButtonText}"
43. action="#{tableData.deleteNames}"
44. rendered="#{tableData.anyNamesMarkedForDeletion}"/>
45. </h:form>
46. </body>
47. </f:view>
48. </html>
程序清单5-21 sorting/src/java/com/corejsf/SortFilterModel.java
1. package com.corejsf;
2.
3. import java.util.Arrays;
4. import java.util.Comparator;
5. import javax.faces.model.DataModel;
6. import javax.faces.model.DataModelEvent;
7. import javax.faces.model.DataModelListener;
8.
9. public class SortFilterModel extends DataModel {
10. private DataModel model;
11. private Row[] rows;
12.
13. private static Comparator<Row> byLast = new
14. Comparator<Row>() {
15. public int compare(Row r1, Row r2) {
16. Name n1 = (Name) r1.getData();
17. Name n2 = (Name) r2.getData();
18. return n1.getLast().compareTo(n2.getLast());
19. }
20. };
21.
22. private static Comparator<Row> byFirst = new
23. Comparator<Row>() {
24. public int compare(Row r1, Row r2) {
25. Name n1 = (Name) r1.getData();
26. Name n2 = (Name) r2.getData();
27. return n1.getFirst().compareTo(n2.getFirst());
28. }
29. };
30.
31. private class Row {
32. private int row;
33. public Row(int row) {
34. this.row = row;
35. }
36. public Object getData() {
37. int originalIndex = model.getRowIndex();
38. model.setRowIndex(row);
39. Object thisRowData = model.getRowData();
40. model.setRowIndex(originalIndex);
41. return thisRowData;
42. }
43. }
44.
45. public SortFilterModel() { // mandated by JSF spec
46. this((Name[])null);
47. }
48. public SortFilterModel(Name[] names) { // recommended by JSF spec
49. setWrappedData(names);
50. }
51. public SortFilterModel(DataModel model) {
52. this.model = model;
53. initializeRows();
54. }
55.
56. public String sortByLast() {
57. Arrays.sort(rows, byLast);
58. return null;
59. }
60.
61. public String sortByFirst() {
62. Arrays.sort(rows, byFirst);
63. return null;
64. }
65.
66. public void setRowIndex(int rowIndex) {
67. if(rowIndex == -1 || rowIndex >= model.getRowCount()) {
68. model.setRowIndex(rowIndex);
69. }
70. else {
71. model.setRowIndex(rows[rowIndex].row);
72. }
73. }
74.
75. // The following methods delegate directly to the
76. // decorated model
77.
78. public boolean isRowAvailable() {
79. return model.isRowAvailable();
80. }
81. public int getRowCount() {
82. return model.getRowCount();
83. }
84. public Object getRowData() {
85. return model.getRowData();
86. }
87. public int getRowIndex() {
88. return model.getRowIndex();
89. }
90. public Object getWrappedData() {
91. return model.getWrappedData();
92. }
93. public void setWrappedData(Object data) {
94. model.setWrappedData(data);
95. initializeRows();
96. }
97. public void addDataModelListener(DataModelListener listener) {
98. model.addDataModelListener(listener);
99. }
100. public DataModelListener[] getDataModelListeners() {
101. return model.getDataModelListeners();
102. }
103. public void removeDataModelListener(DataModelListener listener) {
104. model.removeDataModelListener(listener);
105. }
106. private void initializeRows() {
107. int rowCnt = model.getRowCount();
108. if(rowCnt != -1) {
109. rows = new Row[rowCnt];
110. for(int i=0; i < rowCnt; ++i) {
111. rows[i] = new Row(i);
112. }
113. }
114. }
115. }
  
程序清单5-22 sorting/src/java/com/corejsf/Name.java
1. package com.corejsf;
2.
3. public class Name {
4. private String first;
5. private String last;
6. private boolean markedForDeletion = false;
7.
8. public Name(String first, String last) {
9. this.first = first;
10. this.last = last;
11. }
12.
13. public void setFirst(String newValue) { first = newValue; }
14. public String getFirst() { return first; }
15.
16. public void setLast(String newValue) { last = newValue; }
17. public String getLast() { return last; }
18.
19. public boolean isMarkedForDeletion() { return markedForDeletion; }
20. public void setMarkedForDeletion(boolean newValue) {
21. markedForDeletion = newValue;
22. }
23. }
  
程序清单5-23 sorting/src/java/com/corejsf/TableData.java
1. package com.corejsf;
2.
3. import javax.faces.model.DataModel;
4. import javax.faces.model.ArrayDataModel;
5.
6. public class TableData {
7. private DataModel filterModel = null;
8. private static final Name[] names = {
9. new Name("Anna", "Keeney"),
10. new Name("John", "Wilson"),
11. new Name("Mariko", "Randor"),
12. new Name("William", "Dupont"),
13. };
14.
15. public TableData() {
16. filterModel = new SortFilterModel(new ArrayDataModel(names));
17. }
18. public DataModel getNames() {
19. return filterModel;
20. }
21. public String deleteNames() {
22. if (!getAnyNamesMarkedForDeletion())
23. return null;
24.
25. Name[] currentNames = (Name[]) filterModel.getWrappedData();
26. Name[] newNames = new Name[currentNames.length
27. - getNumberOfNamesMarkedForDeletion()];
28.
29. for(int i = 0, j = 0; i < currentNames.length; ++i) {
30. Name name = (Name) currentNames[i];
31. if (!name.isMarkedForDeletion()) {
32. newNames[j++] = name;
33. }
34. }
35. filterModel.setWrappedData(newNames);
36. return null;
37. }
38.
39. public int getNumberOfNamesMarkedForDeletion() {
40. Name[] currentNames = (Name[]) filterModel.getWrappedData();
41. int cnt = 0;
42.
43. for(int i = 0; i < currentNames.length; ++i) {
44. Name name = (Name) currentNames[i];
45. if (name.isMarkedForDeletion())
46. ++cnt;
47. }
48. return cnt;
49. }
50.
51. public boolean getAnyNamesMarkedForDeletion() {
52. Name[] currentNames = (Name[]) filterModel.getWrappedData();
53. for(int i = 0; i < currentNames.length; ++i) {
54. Name name = (Name) currentNames[i];
55. if (name.isMarkedForDeletion())
56. return true;
57. }
58. return false;
59. }
60. }
  
程序清单5-24 sorting/web/WEB-INF/faces-config.xml
1. <?xml version="1.0"?>
2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
5. http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
6. version="1.2">
7. <application>
8. <resource-bundle>
9. <base-name>com.corejsf.messages</base-name>
10. <var>msgs</var>
11. </resource-bundle>
12. </application>
13.
14. <managed-bean>
15. <managed-bean-name>tableData</managed-bean-name>
16. <managed-bean-class>com.corejsf.TableData</managed-bean-class>
17. <managed-bean-scope>session</managed-bean-scope>
18. </managed-bean>
19. </faces-config>
  
程序清单5-25 sorting/web/styles.css
1. .names {
2. border: thin solid black;
3. }
4. .namesHeader {
5. text-align: center;
6. font-style: italic;
7. color: Snow;
8. background: Teal;
9. }
10. .last {
11. height: 25px;
12. text-align: center;
13. background: MediumTurquoise;
14. }
15. .first {
16. text-align: left;
17. background: PowderBlue;
18. }
19. .caption {
20. font-size: 0.9em;
21. font-style: italic;
22. }
  
程序清单5-26 sorting/src/java/com/corejsf/messages.properties
1. windowTitle=Sorting Java Beans
2. pageTitle=An array of names:
3. firstColumnHeader=First Name
4. lastColumnHeader=Last Name
5. deleteColumnHeader=Delete
6. deleteButtonText=Delete selected names
  
   javax.faces.model.DataModel
● int getRowCount()
  如果知道的话,返回行总数;否则,返回-1。ResultSetDataModel总是从这个方法中返回-1。
● Object getRowData()
  返回与当前行相关的数据。
● boolean isRowAvailable()
  如果在当前行索引中包含有效数据,则返回true。
● int getRowIndex()
  返回当前行的索引。
● void setRowIndex(int index)
  设置当前行索引并更新表示集合中当前项的范围变量(变量由h:dataTable的var属性指定)。
● void addDataModelListener(DataModelListener listener)
  添加数据模型监听器,当行索引改变时,通知监听器。
● void removeDataModelListener(DataModelListener listener)
  删除数据模型监听器。
● void setWrappedData(Object obj)
  设置数据模型包装的对象。
● Object getWrappedData()
  返回数据模型包装的数据
5.9 滚动技术
  对于有许多行的表,有两种在表中滚动的方式:提供滚动条或其他对行移动进行控制的方式。本节将讨论这两种方式。
5.9.1 使用滚动条滚动表
  使用滚动条滚动表是最简单的解决方法。在HTML div中包装h:dataTable,如下:
<div style="overflow:auto; width:100%; height:200px;">
<h:dataTable...>
<h:column>
...
</h:column>
...
</h:dataTable>
</div>
  除了数据表是放置在一个可滚动的div中,图5-17中的程序与5.7节“数据库表”中的程序相同,如上所示。

图5-17 使用可滚动的div滚动表
  从可用的角度看,滚动条是非常好的,但是对于大型表来说这种方法的性能消耗比较大,因为要一次性加载所有的表数据。一种更节省资源的方法,是通过使用带有分页组件的表来滚动,这个方法每次仅需一页数据。
5.9.2 使用分页组件滚动
  使用分页组件滚动要比使用可滚动的DIV滚动更有效,但是它还是比较复杂的。在第13章,我们将演示如何实现一个分页组件,读者可以将它用于任何由h:dataTable创建的表(参考第13章13.1.6节“如何在一个页面中显示大型数据集?”)。图5-18显示了一个分页的例子。

图5-18 使用JSF分页来滚动
  图5-18显示的程序使用了一个数据表,这个数据表显示各地区的ISO国家代码。我们通过调用java.util.Locale.getISO-Countries()来获得列表,它是一个返回字符串数组的静态方法。
  
  
??
  
  
  ??
  
  ??
  
  ??
  
148
JavaServer Faces核心编程(第2版)
  
  
149
第5章 数 据 表
  
  
  
  
  
  
  
  
  
  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值