一个JSF清单示例
这是使用JSF 2.0(JavaServer Faces)构建的示例列表应用程序。 该应用程序是待办事项列表。 该应用程序具有添加,编辑或删除列表中项目的功能。 待办事项具有名称和描述属性。
完成的应用程序的JSF页面具有:
- 使用
h:selectOneListbox
html标记实现的待办事项列表。 - 使用
f:selectItems
核心标签填充列表数据。 - 待办事项名称和描述字段分别使用
h:inputText
和h:inputTextarea
标记实现。 - 新增,编辑,保存,删除和取消功能通过
h:commandButton
标记实现。 - 使用
h:outputText
标记实现的状态消息。
应用中使用的类:
- 待办事项:代表待办事项,并具有名称和描述属性。
- TodosBean:这是一个托管bean; 它具有运行应用程序的代码,包括组件的侦听器和访问器方法。
- TodoConverter:这是一个自定义转换器,将字符串todo名称转换为Todo对象,反之亦然。
下图显示了完成的应用程序的用户界面:
此示例应用程序分三个步骤进行说明。 第一步说明基本列表的实现。 该应用程序的功能在接下来的步骤中得到了增强。 这些步骤是:
- 步骤1:待办事项列表显示项目,并在选择时显示选定的待办事项属性。
- 第2步:列出待办事项,并具有将项目添加到列表的功能。
- 第3步:列出待办事项和添加,编辑和删除列表项的功能。
步骤1:待办事项列表显示项目,并在选择时显示选定的待办事项属性。
以下是此应用程序的代码组件:
-
Todo.java
类表示待办事项。 -
index.xhtml
是带有列表框的JSF页面,以及一条状态消息,用于显示列表中的选定项目。 -
TodosBean.java
托管Bean具有获取列表数据,运行列表的值更改侦听器以及显示状态消息的功能。
Todo.java:
此类表示待办事项。 它具有两个属性-名称和描述。 注意Object
类的重写toString()
方法。
Package com.javaquizplayer.example; public class Todo { private String name; private String desc; public Todo() { } public Todo(String name, String desc) { this.name = name; this.desc = desc; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } @Override public String toString() { return this.name; } }
index.xhtml:
此JSF页面显示待办事项列表。 列表可以滚动,可以选择一个项目。 所选项目名称显示在状态消息中。
列表框是使用h:selectOneListbox
html标记实现的。 列表框的当前选定项目值由以下属性指定: value="#{bean.todo}"
。 选择项通过f:selectItems
核心标签指定:
<f:selectItems value="#{bean.data}"/>
该标记位于h:selectOneListbox tag
。 列表框的项目是从TodosBean
的getData()
方法填充的,该方法返回List
集合。 列表框显示标签–待办事项的名称值,即toString()
方法中Todo对象的String
值。
列表框的值更改侦听器使用以下属性指定:
valueChangeListener=""#{bean.valueChanged}"
选择列表项后,将提交表单并执行此侦听器代码。 在此示例中,当选择一个列表项时,待办事项的名称在状态消息中显示为“ todo_item_name selected”。
每次在列表框中选择一个项目时,都会提交该表单。 这是通过列表框的属性指定的: onchange="submit()"
。
状态消息与输出组件一起显示:
<h:outputText id="msg" value="#{bean.message}" />
。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>A JSF List Example</title> </h:head> <h:body> <h:form> <h3>TODOs List</h3> <h:selectOneListbox id="list" size="10" value="#{bean.todo}" valueChangeListener="#{bean.valueChanged}" οnchange="submit()"> <f:selectItems value="#{bean.data}"/> </h:selectOneListbox> <h:outputText id="msg" value="#{bean.message}" /> </h:form> </h:body> </html>
TodosBean:
此托管bean类具有以下功能:
- 创建初始待办事项数据并填充待办事项列表。
- 值更改侦听器,以获取当前选定的列表项。
- 在列表中捕获当前选定的项目值。
- 设置状态消息。
package com.javaquizplayer.example; import javax.faces.bean.SessionScoped; import javax.faces.bean.ManagedBean; import javax.faces.event.ValueChangeEvent; import java.io.Serializable; import java.util.List; import java.util.ArrayList; @ManagedBean(name="bean") @SessionScoped public class TodosBean implements Serializable { private List<Todo> data; // todo list data private String todo; // the currently selected item value private String msg; // status message public TodosBean() { loadData(); // select the first item in the list Todo t = data.get(0); setTodo(t.getName()); setMessage(t.getName() + " selected."); } private void loadData() { data = new ArrayList<>(); Todo t = new Todo("item 1", "item 1 description"); data.add(t); t = new Todo("item 2", "item 2 description"); data.add(t); t = new Todo("item 3", "item 3 description"); data.add(t); t = new Todo("item 4", "item 4 description"); data.add(t); } public List<Todo> getData() { return data; } public String getTodo() { return todo; } public void setTodo(String t) { todo = t; } // value change listener for list item selection public void valueChanged(ValueChangeEvent e) { String t = (String) e.getNewValue(); setMessage(t + " selected."); } public void setMessage(String s) { msg = s; } public String getMessage() { return msg; } }
步骤2:列出待办事项,并具有将项目添加到清单的功能。
在此步骤中,应用程序具有添加新的待办事项的功能。 单击新建按钮,在名称和描述文本字段中输入待办事项数据并保存。 通过单击取消按钮或通过选择列表中的另一个项目来取消新的待办事项数据输入。
代码组成与上一步相同,但是增加了新功能。 新的自定义转换器类将添加到应用程序。
-
Todo.java
类表示待办事项,未更改。 -
index.xhtml
是带有列表框的JSF页面,以及显示列表中所选项目的状态消息。 此外,还有一些小部件可以输入新的待办事项并保存。 -
TodosBean.java
托管Bean具有获取列表数据,运行列表值更改侦听器并显示消息的代码。 此外,还有用于新动作,保存动作和取消动作的动作侦听器。 - 转换器
TodoConverter.java
将数据从todo字符串值转换为Todo对象,反之亦然。
Todo.java:
此类保持不变。
index.xhtml:
以下是更改:
列表框当前选择的项目值指定为: value="#{bean.todo}"
。 在上一步1中,项目值解析为todo的名称字符串。 现在,该值解析为Todo的一个实例。
以下是新添加的:
待办事项的名称和描述字段分别通过h:inputText
和h:inputTextarea
标记实现。 请注意,只有在编辑待办事项数据时(即,新的待办事项功能),这些字段才可编辑: readonly="#{not bean.editable}"
。 当列表处于选择模式时,这些字段是只读的。
转换器附加到列表中,以使用f:converter
核心标记将选定的项目名称转换为Todo对象,反之亦然:
<f:converter converterId="todoConvertor"/>
请注意,为转换器设置了一个属性:
<f:attribute name="beanattr" value="#{bean}"/>
; 用于访问转换器类中的Todo数据。
使用h:commandButton
标签为新的,保存和取消操作添加了三个命令按钮。 每个按钮都有其各自的动作侦听器。 例如:
<h:commandButton value="New" actionListener="#{bean.newListener}"/>
。
最后,使用f:ajax
核心标记将列表框的Submit更改为Ajax调用: onchange="submit()"
替换为
<f:ajax execute="@this" render="msg name desc" />
为什么会有这种变化?
使用提交选项时,如果通过选择另一个列表项取消了“新建”操作,则不会使用所选项目填充text和textarea字段。 值将保持编辑状态。 这是因为编辑后的文本值也随表格一起提交。 这些值将不会更改为所选项目的值。 但是,对于Ajax,不提交表单,仅更新文本值( f:ajax
标记的render属性指定要更新的字段:状态消息,待办事项名称和描述)。
注意:在以下代码中,突出显示了上一步1中新添加和删除的代码行。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>A JSF List Example</title> </h:head> <h:body> <h:form> <h3>TODOs List</h3> <h:panelGrid> <h:inputText id="name" value="#{bean.todoName}" size="30" readonly="#{not bean.editable}"/> <h:inputTextarea id="desc" value="#{bean.todoDesc}" rows="2" cols="40" readonly="#{not bean.editable}"/> <h:selectOneListbox id="list" size="10" value="#{bean.todo}" valueChangeListener="#{bean.valueChanged}" οnchange="submit()"> <f:ajax execute="@this" render="msg name desc"/> <f:selectItems value="#{bean.data}"/> <f:attribute name="beanattr" value="#{bean}"/> <f:converter converterId="todoConvertor"/> </h:selectOneListbox> </h:panelGrid> <h:commandButton value="New" actionListener="#{bean.newListener}"/> <h:commandButton value="Save" actionListener="#{bean.saveListener}"/> <h:commandButton value="Cancel" actionListener="#{bean.cancelListener}"/> <h:outputText id="msg" value="#{bean.message}" /> </h:form> </h:body> </html>
TodoConverter.java:
这是一个自定义转换器类,将Todo对象转换为字符串(todo名称),反之亦然。
package com.javaquizplayer.example; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.ConverterException; import javax.faces.convert.FacesConverter; import java.util.Map; @FacesConverter(value="todoConvertor") public class TodoConverter implements Converter { private static final long serialVersionUID = 1L; @Override public Object getAsObject(FacesContext context, UIComponent component,String value) throws ConverterException { if (value == null) { return null; } Map<String, Object> attrs = component.getAttributes(); TodosBean bean = (TodosBean) attrs.get("beanattr"); Todo todo = bean.getTodoForName(value); return todo; } @Override public String getAsString(FacesContext context, UIComponent component,Object value) throws ConverterException { if (value == null) { return null; } Todo todo = (Todo) value; return todo.getName(); } }
TodosBean.java:
此托管bean类具有以下功能:
- 填充待办事项列表。
- 值更改侦听器,以获取当前选定的列表项。
- 在列表中捕获当前选定的项目值。
- 设置状态消息。
这些是更改:
- 将列表中当前选择的项目值捕获为Todo对象(而不是先前使用的todo名称字符串)。
- 更改值更改侦听器以获取Todo对象,而不是字符串值todo名称。
这些是新添加的:
- 待办事项名称,描述及其可编辑性的访问器方法。
- 动作侦听器,用于新动作,保存动作和取消动作。
package com.javaquizplayer.example; import javax.faces.bean.SessionScoped; import javax.faces.bean.ManagedBean; import javax.faces.event.ValueChangeEvent; import javax.faces.event.ActionEvent; import java.io.Serializable; import java.util.List; import java.util.ArrayList; @ManagedBean(name="bean") @SessionScoped public class TodosBean implements Serializable { private List<Todo> data; private Todo todo; // selected item value private String msg; private String name; // text field value private String desc; private String actionFlag = "NONE"; // specifies the current action (NEW, NONE) private boolean editable; public TodosBean() { loadData(); if (data.size() == 0) { return; } Todo t = data.get(0); selectRow(t); // select the first item in the list } private void selectRow(Todo t) { setTodo(t); setTodoName(t.getName()); setTodoDesc(t.getDesc()); setMessage(t.getName() + " selected.");); } private void loadData() { data = new ArrayList<>(); } public List<Todo> getData() { return data; } public Todo getTodo() { return todo; } public void setTodo(Todo t) { todo = t; } public void valueChanged(ValueChangeEvent e) { if (! actionFlag.equals("NONE")) { setEditable(false); actionFlag = "NONE"; } Todo t = (Todo) e.getNewValue(); setMessage(t.getName() + " selected.");); setTodoName(t.getName()); setTodoDesc(t.getDesc()); } public void setMessage(String msg) { this.msg = msg; } public String getMessage() { return msg; } public String getTodoName() { return name; } public void setTodoName(String n) { name = n; } public String getTodoDesc() { return desc; } public void setTodoDesc(String d) { desc = d; } // returns the Todo object for a given todo name // method used in converter public Todo getTodoForName(String name) { for (Todo t : data) { if (name.equals(t.getName())) { return t; } } return null; } public void setEditable(boolean b) { editable = b; } public boolean getEditable() { return editable; } public void newListener(ActionEvent e) { setEditable(true); setMessage("Enter new todo. Name must be uniquie and at least 5 chars."); setTodoName("NEW Todo"); setTodoDesc(""); actionFlag = "NEW"; } public void saveListener(ActionEvent e) { if (! actionFlag.equals("NEW")) { return; } String name = getTodoName(); String desc = getTodoDesc(); if (name.length() < 5) { setMessage("Name must be at least 5 chars long."); return; } if (duplicateName(name)) { setMessage("Name must be unique."); return; } Todo t = new Todo(name, desc); data.add(t); setMessage(name + " saved."); setTodo(t); // select the saved item setEditable(false); actionFlag = "NONE"; } private boolean duplicateName(String name) { for (Todo t : data) { if (t.getName().equals(name)) { return true; } } return false; } public void cancelListener(ActionEvent e) { if (actionFlag.equals("NONE")) { return; } actionFlag = "NONE"; setMessage(actionFlag + " action cancelled"); if (data.size() == 0) { setTodoName(""); setTodoDesc(""); setEditable(false); return; } // populate text fields with selected item setTodoName(todo.getName()); setTodoDesc(todo.getDesc()); setEditable(false); } }
第3步:列出待办事项和添加,编辑和删除列表项的功能。
这是完成的应用程序。 它具有选择,添加,编辑和删除列表项的功能。
在此步骤中,添加了两个新功能–编辑,删除列表项。 要进行编辑,请选择一个待办事项列表项,然后单击“编辑”按钮。 这样可以更改名称和描述值,并保存。 可以通过单击取消按钮或选择另一个列表项来取消编辑。 删除功能允许删除选定的待办事项列表项。
这些代码组件与前面的步骤2相同,但是通过新功能进行了增强。
-
Todo.java
类表示待办事项。 这没有改变。 - 转换器
TodoConverter.java
将数据从todo字符串值转换为Todo对象,反之亦然。 这没有改变。 -
index.xhtml
是具有列表框,待办事项属性和状态消息的JSF页面,该状态消息显示列表中的选定项目。 此外,还有一些小部件可用于添加,编辑所选项目或将其删除。 -
TodosBean.java
托管bean具有用于获取列表数据,运行列表的值更改侦听器并显示消息的代码。 此外,还有用于新动作,编辑动作,删除动作,保存动作和取消动作的动作监听器。
Todo.java:
此类保持不变。
TodoConverter.java:
此类保持不变。
index.xhtml:
以下是新添加的:
添加了两个命令按钮以进行编辑和删除操作。 每个按钮都有其各自的动作侦听器。
TodoBean.java:
此托管bean类具有以下功能:
- 填充待办事项列表。
- 值更改侦听器,以获取当前选定的列表项。
- 在列表中捕获当前选定的项目值。
- 设置状态消息。
- 待办事项名称,描述及其可编辑性的访问器方法。
- 动作侦听器,用于新动作,保存动作和取消动作。 增强了这些功能以适应编辑和删除功能。
这些是新添加的:
- 编辑和删除操作的操作侦听器。
代码下载:
这些是下载完整的应用程序的WAR文件和源代码的链接。
注释和参考:
该应用程序是使用Apache MyFaces 2.0开发的(MyFaces 2.0实现了JavaServer Faces 2.0)。 该应用程序已在Tomcat 6 Web服务器和GlassFish 3应用程序服务器(GlassFish 3实现Java EE 6)上进行了测试。
有用的链接:
翻译自: https://www.javacodegeeks.com/2015/02/jsf-list-example.html