【问题标题】:How can a JSF/ICEfaces component's parameters be updated immediately?如何立即更新 JSF/ICEfaces 组件的参数?
【发布时间】:2012-06-08 15:13:06
【问题描述】:

我有一个 ICEfaces Web 应用程序,其中包含一个组件,该组件的属性链接到一个支持 bean 变量。理论上,变量值是通过程序修改的,组件会看到变化并相应地更新其外观/属性。

但是,似乎直到 JSF 周期结束时组件才“注意到”变量的变化(根据我的基本理解,它是 render response phase)。

问题是,我有一个很长的文件复制操作要执行,我希望 inputText 组件显示定期状态更新。但是,由于组件仅在渲染响应阶段更新,因此在 Java 方法执行完成之前它不会显示 任何 输出,并且会同时显示所有累积的更改。

我尝试过使用FacesContext.getCurrentInstance().renderResponse()和其他函数,例如PushRenderer.render(String ID)来强制XmlHttpRequest提前初始化,但无论如何,组件的外观在Java代码执行完成之前不会改变。

想到的一个可能的解决方案是在某个地方有一个不可见的按钮,当长操作的第 1 步完成时,bean 会自动“按下”该按钮,单击它,它会调用第 2 步,依此类推向前。看起来它会起作用,但是当我希望 JSF/ICEfaces 中内置一个更优雅的解决方案时,我不想花时间一起破解这样一个不优雅的解决方案。

是我遗漏了什么,还是求助于丑陋的黑客行为是实现所需行为的唯一方法?

【问题讨论】:

    标签: ajax jsf xhtml components icefaces


    【解决方案1】:

    多线程是缺失的环节,与 PushRenderer 和 PortableRenderer 结合使用(请参阅 http://wiki.icesoft.org/display/ICE/Ajax+Push+-+APIs)。

    我现在在我的支持 bean 中有三个线程——一个用于执行长操作,一个用于轮询状态,一个“主”线程用于生成新线程并将 UI 控制返回给客户端浏览器。

    一旦主线程启动执行和轮询线程,它就会终止并完成原始 HTTP 请求。我的 PortableRenderer 被声明为 PortableRender portableRenderer; 并且在我的 init() 方法(由类构造函数调用)中包含:

    PushRenderer.addCurrentSession("fullFormGroup");    
    portableRenderer = PushRenderer.getPortableRenderer();
    

    对于线程部分,我在课堂上使用了implements Runnable,并且为了在单个类中处理多个线程,我关注了这篇 StackOverflow 帖子:How to deal with multiple threads in one class?

    这里有一些源代码。我无法透露我使用的明确源代码,但这是一个简化版本,不会透露任何机密信息。我还没有测试过它,我是在 gedit 中编写的,所以它可能会有一两个语法错误,但它至少应该让你朝着正确的方向开始。

    public void init()
    {
        // This method is called by the constructor.
        // It doesn't matter where you define the PortableRenderer, as long as it's before it's used.
        PushRenderer.addCurrentSession("fullFormGroup");
        portableRenderer = PushRenderer.getPortableRenderer();
    }   
    
    
    public void someBeanMethod(ActionEvent evt)
    {
        // This is a backing bean method called by some UI event (e.g. clicking a button)
        // Since it is part of a JSF/HTTP request, you cannot call portableRenderer.render
    
        copyExecuting = true;
    
        // Create a status thread and start it
    
        Thread statusThread = new Thread(new Runnable() {
            public void run() {
            try {
                            // message and progress are both linked to components, which change on a portableRenderer.render("fullFormGroup") call
                message = "Copying...";
                // initiates render. Note that this cannot be called from a thread which is already part of an HTTP request
                portableRenderer.render("fullFormGroup"); 
                do {
                    progress = getProgress();
                    portableRenderer.render("fullFormGroup"); // render the updated progress
                    Thread.sleep(5000); // sleep for a while until it's time to poll again
                } while (copyExecuting);
                progress = getProgress();
                message = "Finished!";
                portableRenderer.render("fullFormGroup"); // push a render one last time
            } catch (InterruptedException e) {
                System.out.println("Child interrupted.");
            }
        });
        statusThread.start();
    
        // create a thread which initiates script and triggers the termination of statusThread
        Thread copyThread = new Thread(new Runnable() {           
            public void run() {
            File someBigFile = new File("/tmp/foobar/large_file.tar.gz");
                scriptResult = copyFile(someBigFile); // this will take a long time, which is why we spawn a new thread
                copyExecuting = false; // this will caue the statusThread's do..while loop to terminate
    
    
            } 
        });
        copyThread.start();
    }
    

    【讨论】:

    • 非常普通的东西...非常感谢... Icefaces 示例很烂,但您提供的内容如此清晰:) 谢谢:)
    • 很高兴能帮上忙!如果有帮助,别忘了给答案点赞! PortableRenderer 的真正好处是您可以将其作为参数传递给另一个类中的方法,以从非 bean 上下文触发渲染。
    • 很遗憾他们没有以正确的代码提供教程。我非常感谢您提供示例...
    【解决方案2】:

    我建议查看我们的展示演示:

    http://icefaces-showcase.icesoft.org/showcase.jsf?grp=aceMenu&exp=progressBarBean

    在进度条示例列表下是一个名为 Push 的示例。它使用 Ajax Push(ICEfaces 提供的一项功能)来做我认为你想要的。

    此页面上还有一个名为 Easy Ajax Push 的教程,它将引导您完成使用 Ajax Push 的简单示例。

    http://www.icesoft.org/community/tutorials-samples.jsf

    【讨论】:

    • 感谢您的发帖,但我能够弄清楚。我对 HTTP 请求的基本工作原理感到困惑。 JavaRanch 的一位同事向我解释了这一点:coderanch.com/t/583103/JSF/java/… 你认为 ICEfaces 将这个多线程解决方案(见下文)抽象为一个可以由开发人员调用的简单单线是一个有效的建议吗?我最初的困惑是由所有关于让 ICEfaces 完成所有肮脏工作的营销炒作引起的,这似乎是这个口头禅的一个例外。
    猜你喜欢
    • 2015-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多