p:remoteCommand 销毁 @ViewScoped 托管 bean

Posted

技术标签:

【中文标题】p:remoteCommand 销毁 @ViewScoped 托管 bean【英文标题】:p:remoteCommand destroys @ViewScoped managed bean 【发布时间】:2014-02-24 10:57:23 【问题描述】:

我在将 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 键在使用 ESC 键时通过 javascript 触发 p:remoteCommand

问题是,通过p:remoteCommand 的路由似乎以某种方式破坏了支持bean(bean 是@ViewScoped)。但是,@PreDestroy 注释方法永远不会被调用:使用p:remoteCommand 后页面上的下一个操作会强制从头开始创建组件!调用默认构造函数和@PostConstruct。自然,现在缺少一些重要参数,整个视图都被枪杀了。

知道发生了什么吗?为什么在这种情况下p:remoteCommmandh:commandButton 之间存在差异?有没有机会解决这个问题?

【问题讨论】:

你能发布你的 bean 代码吗? 抱歉,我有一段时间不在办公室。恐怕我不能发布完整的代码,因为它太大了。我将发布一段摘录,其中包含所涉及的操作方法。 尝试在较小的上下文中重现错误。如果你能做到,那就没问题了。发布摘录可能很难得到明确的答案。 完全不确定,可能与 Mojarra 有关。您应该在 PrimeFaces 论坛上通知 Cagatay 的团队。他们将帮助您解决问题。 谢谢。找到答案后,我会在这里发布。 【参考方案1】:

我可以重现该问题。在我的情况下,也许这里的情况相同(问题仅提供“示例”代码,而不是真实的)它是由嵌套表单模板->页面引起的。

如果你有一个 ui:composition 模板或类似的东西,在客户端生成的 HTML 的末尾可能会创建这样的嵌套表单:

<h:form>
...
  <h:form>
   ...
  </h:form>
...
</h:form>

这是无效的 HTML 代码。

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

【讨论】:

谢谢。已经一年多了,所以我不能 100% 确定,但我认为这与堆叠表格无关。 好吧,也许它可以帮助别人。如果你记得,你能发布你的解决方案吗?谢谢! 如果没记错的话,这是 Primefaces 中的一个错误,已被他们修复。

以上是关于p:remoteCommand 销毁 @ViewScoped 托管 bean的主要内容,如果未能解决你的问题,请参考以下文章

从 p:remoteCommand 的 oncomplete 处理程序调用 JavaScript 函数 - 使用一些 JavaScript 代码模拟相同的函数

是否有销毁方法的路线?

PHP7中如何设置session和销毁session

SQL 编译错误:模式对象标识符 'ALL_VIEWS.TABLE_CATALOG.ALL_VIEWS.TABLE_SCHEMA.ALL_VIEWS.TABLE_NAME' 有太多限定符

ASP.NET系列详解Views

xml [Views] Views XML Snippet #android #xml #view #ui