JSF应用程序,如果先前已调用了其他动作,则该动作将不起作用

问题描述

|| 我正在JBoss6上学习Java EE 6和JSF 2.0,并构建了一个非常简单的1页“ Todo \”应用程序,该应用程序可以运行,但有一个非常奇怪的错误。在Safari 5.0.5和Firefox 5中进行了测试。 您可以执行两个操作(添加待办事项和选中/取消选中待办事项)。一切正常,但是在执行不同的操作后第一次执行操作并非如此。 用法示例可能如下所示: 尝试添加待办事项=成功 尝试添加待办事项=成功 尝试检查待办事项=失败 尝试检查待办事项=成功 尝试添加待办事项=失败 尝试添加待办事项=成功 尝试检查待办事项=失败 该应用程序具有以下基本文件(以及其他片段): 实体/Todo.java <-JPA实体 manager / TodoManager.java <-用于处理Todo实体的EJB,@ Stateless controllers / TodoController.java <-页面@SessionScoped的托管bean todos.xhtml <-JSF页面 没有faces-config.xml 添加待办事项的表单如下所示:
<h:panelGroup id=\"projects\">
   <h:message for=\"newtitle\" />
   <h:form id=\"newtodo\">
    <h:panelGrid columns=\"5\">
            <h:outputText value=\"New Todo: \"/>
            <h:inputText id=\"newtitle\" value=\"#{todoController.todo.title}\" />
            <h:outputText value=\"Due: \"/>
            <h:inputText id=\"newDueDate\" value=\"#{todoController.todo.dueDate}\">
                <f:convertDateTime pattern=\"dd/mm/yyyy\"/>
            </h:inputText>
            <h:commandButton action=\"#{todoController.addTodo}\" value=\"add\">
                <f:ajax execute=\"@form\" render=\":projects\"/>
            </h:commandButton>
用于检查/取消选中待办事项“完成”状态的表单如下所示:
<h:form>
    <h:dataTable id=\"todolist\" var=\"t\" value=\"#{todoController.todolist}\">
        <h:column>
            <h:selectBooleanCheckBox id=\"rowCheckBox\" value=\"#{t.done}\" >
                <f:ajax event=\"click\" listener=\"#{todoController.updateDone(t)}\" render=\":projects\"/>
            </h:selectBooleanCheckBox>
        </h:column>
TodoController看起来像这样:
@ManagedBean(name=\"todoController\")
@SessionScoped
public class TodoController 
{
    @EJB
    private TodoManager todoManager;
    private Todo todo = new Todo();
    private ArrayList<Todo> todolist = new ArrayList<Todo>();

    public String addTodo()
    {
        todo.setDone(false);
        todo.setUser(this.getLoggedInUser());
        todoManager.addTodo(todo);
        todo = null;
        return \"todos.xhtml\";
    }

    public String updateDone(Todo t)
    {
        t.setDone(!t.getDone());
        todoManager.updatetodo(t);
        return \"todos.xhtml\";
    }
我确实将日志消息添加到addTodo()和updateDone(Todo t)以验证何时调用它们。当这些动作“不起作用”时,它们实际上似乎根本没有被调用。 :-(     

解决方法

        当您有2种形式,而通过累加第一种形式重新呈现第二种形式时,就会发生这种情况。这样,第二种形式的JSF视图状态将完全丢失(您可以通过在Ajax响应中缺少名称为
javax.faces.ViewState
的隐藏输入字段来自己确定它)。在由第一份表单的提交者重新呈现后提交第二份表单在视觉上将无效。没有视图状态,JSF将不会处理表单的提交。只有新的表单(具有正确的视图状态!)才会恢复原位,因此第二个提交工作。 您需要以这种方式微调
render
属性,以便仅重新呈现第二种形式的内容,而不是整个形式本身。 例如。
<h:form id=\"form1\">
    <h:panelGroup id=\"content\">
        ...
        <h:commandButton value=\"Submit\">
            <f:ajax execute=\"@form\" render=\"@form :form2:content\" />
        </h:commandButton>
    </h:panelGroup>
</h:form>
<h:form id=\"form2\">
    <h:panelGroup id=\"content\">
        ...
        <h:commandButton value=\"Submit\">
            <f:ajax execute=\"@form\" render=\"@form :form1:content\" />
        </h:commandButton>
    </h:panelGroup>
</h:form>
在您的特殊情况下,将第一种形式的
<h:panelGrid>
和第二种形式的
<h:dataTable>
固定为
id
,然后从另一种形式重新渲染。