Minimal example of Push in Vaadin 7 app (“@Push”)

2019-01-07 18:49发布

问题:

I want to see the most minimal example of using the new Push technology in Vaadin 7, such as the new @Push annotation.

I am having problems getting server-push to work in my app. I would like to try a simple example app before trying to fix my own app.

回答1:

Simplification Of Example In The Book Of Vaadin

The Book Of Vaadin includes a chapter on Push, including an example using Vaadin Charts.

Below is my code. While based on that Vaadin Charts example mentioned above, I simplified it by replacing the use of a Chart object with a simple Label object. The Label updates every second or so to tell you the current time.

For Example Use Only – Use an Executor in real-world project

Caveat: My example below is built for simplicity, not intended as production code. Sleeping a thread is a crude and awkward way to manage scheduled threaded work. Java provides the Executor facility for this kind of work. In a real-world project I would use a ScheduledExecutorService rather than a single sleeping Thread object to schedule our task (of telling time). Related tip: Never use a Timer in a Servlet environment. For a fuller and more real-world example, see my Answer to a similar Question about Push with Vaadin.

I took other shortcuts in this example, such as: I place the Label widget directly on the UI whereas real-world work would use a Layout to contain the Label.

My Configuration

My code is using Vaadin 7.3.7 with Java 8 Update 25 in NetBeans 8.0.2 and Tomcat 8.0.15 on Mac OS X 10.8.5 (Mountain Lion).

Push technology is relatively new, especially the WebSocket variety. Be sure to use recent versions of your web server, such as recent updates to Tomcat 7 or 8.

How To Use This Example

This code is a single file, the MyUI.java file. To use this code:

  1. Create a new default Vaadin app in your IDE of choice.
  2. Get that example running successfully, before modifying.
  3. Replace the contents of MyUI class with the code below.

@Push Annotation

Beside the code in the middle, note how we added the @Push annotation to the MyUI class definition.

Example Code

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:

Here is a simple but full Vaadin 8 example that demonstrates how to use server push and Java EE messaging APIs to send messages between different UIs using the Broadcaster pattern described in Vaadin docs. If you are not interested in messaging or broadcasting to other users, then look at ReceiveMessageUI only.

In principle it all boils down to the following:

  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.