使用 JSF 下钻编辑屏幕
作者: Duncan Mills,Oracle Corporation
2005 年 4 月
定义问题
作为一项技术,JavaServer Faces 真正出色的特性之一是能够使用各种 dataTable 组件非常简单地创建多行可编辑表格。但有时您可能需要采用 老式 方法执行操作,即您拥有一个只读数据的表格视图,从中您选择一个命令链接(超链接)或某个其他 UI 元素来下钻编辑屏幕,从而获取该特定记录。以下是此种情形的一个示例:
![显示下钻操作访问的初始表格屏幕和编辑屏幕的下钻 UI 图像]()
图 1:下钻 UI
(请注意,为了便于理解,我在上图中叠放了这两个屏幕。就目前情况而言,此解决方案将在与表格列表相同的窗口中显示编辑屏幕。但如果您使用 ADF Faces 组件集,则可以显示弹出窗口版本的编辑屏幕)
但重要的是,我想用同一下钻屏幕编辑或创建新记录,并希望能够选择保存我的更改或通过从编辑/下钻屏幕向后导航取消更改。
设置
为了用简单的方式来说明这些内容,我将使用一个简单的 Contact bean 集合:
Contact Bean
package com.groundside.jsf;
public class Contact {
String _firstName;
String _lastName;
int_age;
int_contactId = 0;
public Contact( intcontactId,
String firstName,
String lastName,
intage)
{
_contactId = contactId;
_firstName = firstName;
_lastName = lastName;
_age = age;
}
/* Getters and setters for the fields */
è′... |
单击此处可以获取完整的类
此外,还有一个由这些联系人对象组成的集合,为方便起见,还创建了一些示例数据
Neighbors Bean
package com.groundside.jsf;
import java.util.ArrayList;
public class Neighbors {
ArrayList _contacts = new ArrayList();
int_maxContactId;
public Neighbors()
{
_contacts.add(new Contact(1,"Fred","Flintstone",35));
_contacts.add(new Contact(2,"Wilma","Flintstone",32));
_contacts.add(new Contact(3,"Barney","Rubble",33));
_contacts.add(new Contact(4,"Betty","Rubble",33));
_maxContactId = 4;
}
public void setContacts(ArrayList contacts){...}
public ArrayList getContacts() {...}
public void updateContact(Contact updatedContact) {...}
public void addContact(Contact newContact) {...}
public void deleteContact(int contactId){...}
} |
( 单击此处可以获取完整的类)
页面流
本示例只需要两个页面,一个用于显示摘要表格的 tabular.jsp;一个是用于编辑特定行的 edit.jsp:
![两个示例页面的 JSF 导航图]()
托管的 Bean
这些页面中的每一个都有一个请求范围辅助 bean,此外 Neighbors 对象作为一个会话范围的 bean 提供,并存在一个 Contact 类型的请求范围 editContact 托管的 bean,用于将表格屏幕中的当前行传输到编辑屏幕。此处提供完整的 faces-config。为便于参考,此处提供了这两个页面的辅助 bean:
调用编辑屏幕
切换到包含新记录的编辑屏幕并不复杂,我们只需导航到那里并让 Faces 负责为该页面创建一个新的空白 Contact bean 即可:
public String newButtonAction()
{
return "drilldown";
} |
导航到包含现有记录的编辑页面涉及从 dataTable 控件中获取当前行。Faces 将基于您单击的行正确处理当前行的设置。拥有联系人对象后,我们使用它的内容预先提供给 editContact 托管 bean:
public String editLinkAction()
{
/* Pull out the currently selected contact */
Contact editContact= (Contact)this.getDataTable().getRowData();
/* Pre-seed the managed bean */
FacesContext ctx= FacesContext.getCurrentInstance();
ValueBinding binding= ctx.getApplication().createValueBinding("#{editContact}");
binding.setValue(ctx,editContact);
return "drilldown";
} |
从编辑屏幕返回
编辑屏幕行包含两个按钮:
- 一个是 Cancel 按钮,此按钮拥有一个硬编码的返回导航动作,并将 immediate 设置为 true。
- 一个是 Save 按钮,用于查找 Neighbors 集合并将更改后的 Contact 记录返回给此集合。在此实现中,Neighbors 对象上的 updateContact 方法能够识别这实际上是一个更新还是一个添加的新记录。
此处是该 Save 动作的代码:
public String saveAction()
{
FacesContext ctx= FacesContext.getCurrentInstance();
Application app= ctx.getApplication();
ValueBinding editedContactBind = app.createValueBinding("#{editContact}");
ValueBinding contactListBind= app.createValueBinding("#{neighbors}");
Contact contact=(Contact)editedContactBind.getValue(ctx);
Neighbors neighbors=(Neighbors)contactListBind.getValue(ctx);
neighbors.updateContact(contact);
return "return";
} |
总结
以上是 一种使用原始 JSF 处理此方案的方法。它是一个非常简单的解决方案,并清楚地演示了如何使用 ValueBindings 保持代码的整洁性并免受 servlet API 的影响。