远程命令(p:remoteCommand)销毁@ViewScoped受管Bean。

3

我在给表单添加p:remoteCommand时遇到了问题。代码大致如下:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:util="http://java.sun.com/jsf/composite/components/util"
    xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions"
    xmlns:p="http://primefaces.org/ui">
    <h:head>
        <title>Reset Test</title>
        <link type="text/css" rel="stylesheet" href="/treetable-sscce/css/example.css" />
        <h:outputScript library="primefaces" name="jquery/jquery.js"/>
    </h:head>

    <div class="box">
        <h2>Box</h2>
        <h:panelGroup id="mypanel">
            Headline: <h:outputText value="#{resetBean.headline}" />
            <br/>
            Message : <h:outputText value="#{resetBean.message}" />
            <br/>
        </h:panelGroup>
    </div>

    <div class="box">
        <h2>Form</h2>
        <h:form id="myform" acceptcharset="utf-8">

            <p:growl id="growl" showDetail="true" sticky="false" severity="info, warn" />       

            <!--  register custom validate event -->
            <f:event listener="#{resetBean.validateForm}" type="postValidate" />

            <p:remoteCommand name="resetByEscape" action="#{resetBean.resetAction}" 
                immediate="true" update=":myform :mypanel" />

            <h:outputLabel for="headline">Meldungsüberschrift</h:outputLabel>
            <h:inputText id="headline" value="#{resetBean.headline}" />
            <br/>

            <h:outputLabel for="message">Meldungsüberschrift</h:outputLabel>
            <h:inputTextarea id="message" value="#{resetBean.message}" />
            <br/>

            <h:commandButton action="#{resetBean.resetAction}"  
                        value="Reset" immediate="true" onclick="resetForm()"/>

            <h:commandButton action="#{resetBean.submitAction}" value="Submit"  immediate="false"/>

        </h:form>
    </div>

    <script type="text/javascript">
        <!--//--><![CDATA[//><!--

        var resetForm = function()
        {
            $("[id$='headline']").val(null)
            $("[id$='message']").val(null)
        }

        var escapePressed = function()
        {
            resetForm();
            resetByEscape();
        } 

        $(document).keyup(function(e) {if (e.keyCode == 27) escapePressed();});

        //--><!]]>
    </script>
</html>

以下是Bean代码:

package de.example.beans;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.validator.ValidatorException;

import org.apache.log4j.Logger;

@ViewScoped
@ManagedBean
public class ResetBean implements Serializable 
{
    private static final long serialVersionUID = 7282752623428425109L;
    private static final Logger log = Logger.getLogger(ResetBean.class);

    protected String headline = null;
    protected String message = null;

    public ResetBean() {
        log.error("ResetBean");
    }

    @PostConstruct
    public void postConstruct() {
        log.error("postConstruct");
    }

    @PreDestroy
    public void preDestroy() {
        log.error("preDestroy");
    }

    public void resetAction() {
        log.error("resetAction");
        headline = null;
        message = null;
    }

    public void submitAction() {
        log.error("submitAction headline="+headline+" message="+message);
    }

    public void validateForm(ComponentSystemEvent event) throws ValidatorException {
        log.error("validateForm");
    }

    public String getHeadline() {
        return headline;
    }

    public void setHeadline(String headline) {
        this.headline = headline;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

h:command按钮和p:remoteCommand以相同的方式执行相同的操作。区别是,h:command按钮响应鼠标单击,而按ESC键会通过javascript触发p:remoteCommand

问题在于,通过p:remoteCommand的路由似乎会破坏后端bean(该bean为@ViewScoped)。但是,@PreDestroy注释的方法从未被调用,然而:在使用p:remoteCommand后,页面上的下一个动作将强制重新创建组件!将调用默认构造函数和@PostConstruct。现在自然缺少一些重要参数,整个视图都变得混乱。

你有任何想法吗?为什么在这种情况下p:remoteCommmandh:commandButton之间有差异?有没有解决问题的机会?


我已经在演示项目中复现了这个问题。我将在一分钟内相应地编辑问题描述。 - Jürgen Simon
你能提供更多关于问题的信息吗?JSF实现版本,您正在使用的浏览器...我已经尝试了Chrome并且按预期工作,虽然Firefox带来了意外的行为。但是,与您的问题无关,您不需要使用JS清除表单。只需在Java代码中清除其模型值,当从post返回时,您将获得清除的输入。 - Aritz
问题在于当单击ESC键时,视图状态参数(JSF实现用于保持视图具有状态性的参数)被移除。只需查看客户端生成的表单即可。我敢打赌,这实际上是与p:remoteCommand有关的问题,因为该问题似乎与所有键相关,而不仅仅是ESC。也许你应该在PF论坛上开一个帖子... - Aritz
1
不确定,可能与Mojarra有关。您应该在PrimeFaces论坛上向Cagatay团队提出通知。他们会协助您解决此问题。 - Aritz
1
谢谢。一旦我有答案,我会在这里发布。 - Jürgen Simon
显示剩余8条评论
1个回答

1
我可以重现这个问题。在我的情况下,可能与这里的情况相同(问题仅提供“示例”代码,而不是真实代码),它是由嵌套表单模板->页面引起的。
如果您有类似于ui:composition模板的东西,在客户端生成的HTML末尾,它可能会创建像这样的嵌套表单:
<h:form>
...
  <h:form>
   ...
  </h:form>
...
</h:form>

这是无效的HTML代码。

删除不必要的表单或重新组织代码并再次测试。当通过JavaScript调用p:remoteCommand时,不应调用@postConstruct方法。


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jürgen Simon
好的,也许它能帮助其他人。如果你记得的话,可以发表你的解决方案吗?谢谢! - Gabriel Pegoraro
如果我没记错的话,这是Primefaces中的一个bug,他们已经修复了。 - Jürgen Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接