Vaadin 7 应用程序中 Push 的最简示例 ("@Push")

15

我想要看到Vaadin 7中使用新的推送技术的最简单示例,比如新的@Push注释。

我的应用程序无法正常运行服务器推送。在修复自己的应用程序之前,我想先尝试一个简单的示例应用程序。


亲爱的投反对票者:请在您的投票中留下批评意见。 - Basil Bourque
学习完这个页面后,您可能会发现这个页面很有用:在Vaadin 7应用程序中使用Push显示多个客户端上的相同数据 - Basil Bourque
要在Vaadin 8中使用Push异步更新UI小部件的完整工作示例,请参见我的答案,链接为[https://stackoverflow.com/a/50885540/642706],该问题是[*Vaadin:在返回数据后更新UI*](https://stackoverflow.com/q/50880506/642706)。 - Basil Bourque
2个回答

24

《Vaadin之书》中示例的简化

Vaadin之书包含了一个关于推送的章节,其中包括使用Vaadin Charts的示例。

以下是我的代码。基于上述提到的Vaadin Charts示例,我通过将Chart对象替换为简单的Label对象来进行简化。该标签每秒更新一次,以告诉您当前时间。

screen shot of example Vaadin app telling current time in UTC as text

仅供参考 - 在真实项目中使用 Executor

注意:我下面的示例是为了简单起见而构建的,不适用于生产代码。睡眠线程是管理计划线程工作的一种粗糙和笨拙的方式。Java 提供了 Executor 设施来处理这种工作。在真实项目中,我会使用 ScheduledExecutorService 来安排我们任务(告诉时间),而不是使用单个睡眠的 Thread 对象。相关提示:永远不要在 Servlet 环境中使用 Timer。有关更完整和更真实的示例,请参见 my Answer 中关于 Vaadin 推送的类似问题。

我在这个示例中采取了其他捷径,例如:将 Label 小部件直接放置在 UI 上,而真实的工作会使用 Layout 来包含 Label

我的配置

我的代码使用Vaadin 7.3.7和Java 8 Update 25在NetBeans 8.0.2和Tomcat 8.0.15上运行,操作系统为Mac OS X 10.8.5(Mountain Lion)。

推送技术相对较新,特别是WebSocket类型。请确保使用最新版本的Web服务器,例如Tomcat 7或8的最新更新。

如何使用此示例

此代码是一个单一文件,即MyUI.java文件。要使用此代码:

  1. 在您选择的IDE中创建一个新的默认Vaadin应用程序。
  2. 在修改之前,请确保成功运行该示例。
  3. MyUI类的内容替换为以下代码。

@Push注解

除了中间的代码外,请注意我们如何将@Push注解添加到MyUI类定义中。

示例代码

package com.example.pushvaadinapp;

import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.Widgetset;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import javax.servlet.annotation.WebServlet;

/**
 * © 2014 Basil Bourque. This source code may be used freely forever by anyone absolving me of any and all responsibility.
 *
 *  +----------------------------+
 *  |  NOT FOR PRODUCTION USE!   |
 *  +----------------------------+
 *     Sleeping threads is an awkward way to manage scheduled background work.
 *     By the way, never use a 'Timer' in a Servlet environment. 
 *     Use an Executor instead, probably a ScheduledExecutorService.
 */
@Push
@Theme ( "mytheme" )
@Widgetset ( "com.example.pushvaadinapp.MyAppWidgetset" )
public class MyUI extends UI
{

    Label label = new Label( "Now : " );

    @Override
    protected void init ( VaadinRequest vaadinRequest )
    {
        // Put a widget on this UI. In real work we would use a Layout.
        setContent( this.label );

        // Start the data feed thread
        new FeederThread().start();
    }

    @WebServlet ( urlPatterns = "/*" , name = "MyUIServlet" , asyncSupported = true )
    @VaadinServletConfiguration ( ui = MyUI.class , productionMode = false )
    public static class MyUIServlet extends VaadinServlet
    {
    }

    public void tellTime ()
    {
        label.setValue( "Now : " + new java.util.Date() ); // If Java 8, use: Instant.now(). Or, in Joda-Time: DateTime.now().
    }

    class FeederThread extends Thread
    {

        int count = 0;

        @Override
        public void run ()
        {
            try {
                // Update the data for a while
                while ( count < 100 ) {
                    Thread.sleep( 1000 );

                    // Calling special 'access' method on UI object, for inter-thread communication.
                    access( new Runnable()
                    {
                        @Override
                        public void run ()
                        {
                            count ++;
                            tellTime();
                        }
                    } );
                }

                // Inform that we have stopped running
                // Calling special 'access' method on UI object, for inter-thread communication.
                access( new Runnable()
                {
                    @Override
                    public void run ()
                    {
                        label.setValue( "Done." );
                    }
                } );
            } catch ( InterruptedException e ) {
                e.printStackTrace();
            }
        }
    }
}

2
需要widgetset吗?我猜不需要。而且为什么要费心解释一整段关于java.time的内容,当目标是拥有一个最小化的工作示例时呢?只需使用一个计数器或new Date().toString()即可。而且在你的问题中,你提到你想要一个简单的测试应用程序,在这个应用程序中可以测试这些东西。那么为什么不将你的整个项目(包括pom/gradle/等等)放在GitHub上供找到你问题的Stack Overflow用户使用呢? - cfrick
@cfrick 所有观点都很好;谢谢您。[A] 我已经按照您的建议停用了 java.time 的使用和讨论。[B] 至于 widgetset,该注解是由新的Maven原型创建的新多模块项目的默认设置,并由 Vaadin Plugin For NetBeans 的 1.1.3 更新交付。此外,这份模糊的文档暗示production模块的编译现在自动优化了widgetset(和主题)。所以我会保持原样。 - Basil Bourque
为什么不能在Servlet环境中使用计时器? - Alex78191

1

这里是一个简单但完整的Vaadin 8示例,演示了如何使用服务器推送和Java EE消息API在不同的UI之间发送消息,使用Broadcaster模式,该模式在Vaadin文档中有描述。如果您对消息传递或向其他用户广播不感兴趣,则仅查看ReceiveMessageUI

原则上,所有问题都可以归结为以下内容:

  1. Annotate the Vaadin UI with @Push to enable server push (by default over a WebSocket connection)
  2. Wrap UI updates with access() when accessing it from other threads, sending updates happens automatically by default:

    getUI().access(() -> layout.addComponent(new Label("Hello!")));
    
  3. Use the Broadcaster pattern to publish messages to other users and to subscribe to their messages.


“广播者模式”是指观察者模式还是其他什么? - Basil Bourque
1
还有一种模式,我指的是Vaadin文档中记录的广播器模式 - mrts
最好在文档中查找示例 https://vaadin.com/docs/v8/framework/advanced/advanced-push.html - Alex78191

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