Vaadin 8:每1分钟用服务器中的数据重新加载网格 [英] Vaadin 8 : reload grid with data from server every 1min

查看:128
本文介绍了Vaadin 8:每1分钟用服务器中的数据重新加载网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为网格提供自动刷新功能,该功能基本上是每隔n秒钟用服务器中的最新数据更新网格.

I am trying to have a auto refresh feature for the grid which basically, updates the grid with latest data from the server every 'n' seconds.

每当用户启用自动刷新时,我便能够实现PollListner.

I was able to implement the PollListner whenever the user enables Auto-Refresh.

                UI ui= TestUI.getCurrent();
                Boolean value = isRefreshChkBox.getValue();
                PollListener listener = e -> {
                    explorer.reloadUI();
                };
                if (value) {

                    String refreshRateValue = refreshRateTxtField.getValue();
                    int refreshRate = Integer.valueOf(refreshRateValue);
                    int millis = (int) TimeUnit.SECONDS.toMillis(refreshRate);

                    absUI.setPollInterval(millis);

                    absUI.addPollListener(listener);
                } else {
                    absUI.setPollInterval(-1);
                    absUI.removePollListener(listener);
                }

使用上面的代码,每次启用自动刷新时我都会添加PollListener,并在禁用时将其删除.

With the above code, I add PollListener everytime autorefresh is enabled and I remove it on disable.

我在这里找到了类似的问题

I found similar question here VAADIN 7: What is the simplest way to refresh a Vaadin View in 5 minute intervals?

但是我想了解的是,有没有更好的方法来实现简单的用例AutoRefresh UI? PollListener应该在哪里实现?我想为视图创建一次PollListener,并且每次用户更改刷新率时才更新PollInterval.

But what I want to understand, is there a better approach to achieve a simple usecase AutoRefresh UI?? where should PollListener be implemented?? I thought of creating PollListener once for the view and just update the PollInterval everytime user changes the refresh rate.

关于哪种方法更好的任何指示,或者Vaadin中是否有全新的概念来实现这一目标?

Any pointers on which approach is better or is there completely new concept in Vaadin to achieve this?

TIA

推荐答案

请参阅LeifÅstrand的正确答案.我将添加一些讨论,并使用轮询和推送功能提供完整的示例应用程序.

See the correct Answer by Leif Åstrand. I will add a bit of discussion, and a complete example app using both Polling and Push.

Vaadin 8有两种自动更新信息显示而无需用户做出手势的方式:轮询和推.

Vaadin 8 has two ways to automatically update the display of information without the user making a gesture: Polling & Push.

在Vaadin 8的投票功能中,您 UI 子类.默认值-1禁用轮询.

In Vaadin 8’s Polling feature, you set a polling interval of milliseconds on your UI subclass. The default value of -1 disables Polling.

myUI.setPollInterval( ( int ) TimeUnit.MINUTES.toMillis( 1 ) );  // Specify milliseconds for polling interval.

启用后,安装在用户网络浏览器中的Vaadin JavaScript库将通过Vaadin服务器签入.作为 PollNotifier , UI签入会导致在服务器端触发事件.

When enabled, the Vaadin JavaScript library installed in the user’s web browser checks in with the Vaadin server. Being a PollNotifier, the UI checking-in causes an event to be fired on the server-side.

如果您定义一个实现 PollListener 接口,您的实例将具有其

If you define a class that implements the PollListener interface, your instance will have its poll method invoked.

注册PollListener后.返回Registration对象.该对象提供了remove方法来注销您的侦听器(如果需要).

Upon registering your PollListener. get back a Registration object. That object provides a remove method to unregister your listener, if need be.

您可以选择使用lambda语法,匿名内部类或单独定义的类来定义PollListener.

You have your choice of defining your PollListener using lambda syntax, an anonymous inner class, or a separately-defined class.

Registration registration = this.addPollListener( new UIEvents.PollListener() {
    @Override
    public void poll ( UIEvents.PollEvent pollEvent ) {
        System.out.println( "TRACE - PollListener::poll running. " + Instant.now() );
        …
    }
} );

或者,lambda语法:

Or, lambda syntax:

Registration registration = this.addPollListener( ( UIEvents.PollListener ) pollEvent -> {
    System.out.println( "TRACE - PollListener::poll running. " + Instant.now() );
    …
} );

在此调用期间,您的代码可以注册Runnable以便在方便的时候使用UI子类进行调用.

During this invocation, your code can register a Runnable to be invoked at a convenient time with your UI subclass.

Runnable负责更新UI子类中包含的小部件的工作.请记住 从不从后台线程访问或修改窗口小部件.您可能会摆脱它,或者可能导致可怕的事情发生.安全:请始终调用UI::access以传递访问小部件的Runnable. Runnable将在Web应用程序的主用户界面线程(UI子类实例的负责线程)上运行.

That Runnable does the work of updating widgets contained in your UI subclass. Remember to never access or modify widgets from a background thread. You may get away with it, or you may cause terrible things to happen. Be safe: Always call UI::access to pass a Runnable that accesses the widgets. That Runnable will be run on the main user-interface thread of your web app, the thread in charge of your UI subclass instance.

getUI().access( new Runnable() {
                    @Override
                    public void run ( ) {
                        subscriber.refresh( new ArrayList <>( statusList ) ); // Copy the list in case the `Grid` modifies it, such as sorting.
                    }
                } );

专业人士

使用轮询功能的好处在于,您必须进行的编程比使用Push更为简单(下面讨论).了解非用户自动生成的更新时,轮询可能是更好的选择.

Pros

The upside of using the Polling feature is that the programming you must do is simpler than with Push (discussed below). Polling is likely a better route to take when learning about automated non-user-generated updates.

一个简单的方面是,UI子类的每个实例都负责自己的轮询,选择是否以及何时进行轮询以及控制轮询的频率.每个UI子类实例都调用其自己的 setPollInterval 方法.对用户来说,更多轮询可能是不错的选择,但是聊天会增加网络流量,从而使您的网络管理员变得胡思乱想.因此,您可以通过UI子类实例来调整频率.请记住,不仅每个用户都有自己的UI子类实例,而且Vaadin 8还能够使用多窗口/选项卡应用程序.每个Web浏览器中的一个Web应用程序可以打开多个窗口/选项卡,每个窗口/选项卡运行各自的相同或不同的UI子类实例.

One simple aspect is that each instance of your UI subclass is in charge of its own polling, choosing if and when to do polling and controlling how often to poll. Each UI subclass instance calls its own setPollInterval method. More polling may be nice for the user, but the chattiness increases network traffic, thereby making your network admin cranky. So you can tune the frequency by UI subclass instance. Remember that not only does each user have their own UI subclass instance, but also, Vaadin 8 is capable of multi-window/tab apps. One web app in each web browser can have multiple windows/tabs open, each running their own instance of the same or different UI subclasses.

从美学上讲,一个缺点是轮询破坏了HTTP设计的请求响应优雅性.尽管这是我的宠儿,但那艘船已经航行很久了,因此在这里我不会浪费太多时间来夸大使用文档传送系统作为交互式客户端-服务器应用程序体系结构的能力.

One downside aesthetically is that polling breaks the request-response elegance of the HTTP design. While this is a pet-peeve of mine, that ship has sailed long ago, so I'll not waste bytes here ranting about using a document-delivery system as an interactive client-server app architecture.

更实际的缺点是网络上不必要的流量.如果您能够通过 Webpush ,然后在客户端和服务器之间保持很少的流量的开放连接,直到服务器生成要传达给客户端的事件为止.但是请注意,WebSocket很容易被防火墙和防火墙所击败.代理和Webpush可能无法实现/不支持,在这种情况下,可以在Vaadin中使用Push实现( Atmosphere Framework 库,由 async-io.org )提供技术.

A more practical downside is unnecessary traffic on the network. If you are able to use Push via WebSocket or Webpush, then an open connection is maintained between client and server with very little traffic all the while until the server generates an event to be communicated to the client. But be aware that WebSocket is easily defeated by firewalls & proxies, and Webpush may not be implemented/supported, in which case the Push implementation in Vaadin (the Atmosphere Framework library by async-io.org) may fall back to polling techniques.

另一个缺点是每个客户端执行自己的重复轮询的效率低下,并且每个客户端都会在服务器端触发单独的执行,例如在数据库中搜索新数据.如果您有许多客户端都使用同一组不可变对象,则Push可以更有效地执行一次搜索新数据并将相同的数据对象交付给所有客户端的操作.

Another downside is inefficiency of each client doing its own repeated polling and each triggering a separate execution on the server-side such as the search for fresh data in the database. If you have many clients all consuming the same set of immutable objects, then Push can be more efficient doing a single search for fresh data and delivering the same bunch of data objects to all the clients.

Vaadin与Atmosphere的组合(如上链接)大大简化了在Web应用程序中使用Push技术的过程.但是,与使用轮询"功能所看到的相比,具有更多运动部件的情况要复杂一些.

The combination of Vaadin with Atmosphere (linked above) vastly simplifies using Push technology in your web app. Nevertheless, it is a bit more complicated with more moving parts than seen with the Polling feature.

首先,使用 @Push UI子类上的注释.

Firstly, enable Push with the @Push annotation on your UI subclass.

然后使用ScheduledExecutorService安排每分钟触发一次事件.用ServletContextListener设置该执行程序.参见下面的示例代码.

Then schedule the firing of an event every minute using a ScheduledExecutorService. Set up that executor with a ServletContextListener. See example code below for all this.

就网络流量而言,使用 WebSocket 技术或 Webpush .

Push can be quite efficient in terms of network traffic able to use WebSocket technology or Webpush, as mentioned above.

不幸的是,WebSocket可能会被防火墙击败.代理. Webpush是新的,可能不会得到广泛支持.在这种情况下,Vaadin/Atmosphere可能会退回到使用轮询方法.

Unfortunately WebSocket can be defeated by firewalls & proxies. And Webpush is new and may not be widely supported. In this case, Vaadin/Atmosphere may fall-back to using a polling approach.

另一个缺点是编码更加复杂.刚接触这项工作的程序员可能需要一段时间才能掌握各种动静的部分.

Another downside is that the coding is a bit more complex. A programmer new to this work may take a while to grasp the various moving pieces.

  • 您需要在服务器端使用后台线程来跟踪时间,在本例中,它是每分钟触发一次.现代的方法是使用ScheduledExecutorService来处理线程和触发计划.
  • 要设置该执行程序服务,您将需要实现一个ServletContextListener,如下所述.
  • You need a background thread on the server-side to track the time, in our case firing every minute. The modern approach to that is using a ScheduledExecutorService to handle the threading and firing schedule.
  • To setup that executor service, you will need to implement a ServletContextListener as discussed below.

请注意,某些推送方法(尤其是WebSocket)涉及维护开放的网络连接.因此,这会占用服务器计算机上的资源,例如端口号.

Be aware that some of the push approaches, especially WebSocket, involve maintaining an open network connection. So this consumes resources such as port numbers on your server machine.

我使用Vaadin 8.6beta1构建了一个完整的工作示例应用程序.此应用程序同时支持 轮询和推送.不知道您是否会在真正的Web应用程序中同时使用这两者,但也许可以.

I built a complete working example app using Vaadin 8.6beta1. This app supports both Polling and Push. Not sure if you would ever mix both in a real web app, but perhaps.

访问我的Google云端硬盘上的主文件 .添加到通过Vaadin Ltd.提供的Maven原型vaadin-archetype-application创建的项目中.

Access the main files on my Google Drive. Add to a project created via the Maven archetype vaadin-archetype-application provided by Vaadin Ltd.

注意事项:此示例经过几天的兼职整理.因此,它可能是也可能不是生产就绪代码,并且可能会或可能不会显示适当的技术.但是希望它将有助于指导新手.

Caveat: This example was cobbled together part-time over days. So it may or may not be production-ready code, and may or may not show proper technique. But hopefully it will help to guide a newbie.

注意:我不是这个领域的专家.因此,请使用盐粒进行上面的所有讨论和示例代码.做你自己的研究和学习.

Caveat: I am not an expert in this arena. So take all my discussion above and my example code here with a grain-of-salt. Do your own research and study.

此应用程序允许您通过单选按钮启用和禁用每种方法.您还可以通过单击立即手动刷新按钮来强制立即刷新.

This app allows you to enable and disable each approach via radio buttons. You can also force an immediate refresh by clicking the Refresh manually now button.

绿色阴影表示自上次刷新以来已更改的值.

The green-shading indicates changed values since the last refresh.

您可以运行多个窗口.观看它们一起更新还是单独更新,或者不是全部更新,取决于您的单选按钮设置.

You can run multiple windows. Watch them update together or separately or not all, depending on your radio button settings.

该示例应用程序的主要思想是模拟一个数据库,该数据库保持大约十种设备/过程/人/物的当前状态.每种状态均以数字1-10标识.每个状态的状态都包含10个值(1-9).每个状态都会记录上一次更新的时间.

The main idea of this example app is to simulate a database maintaining a current status of some ten pieces of equipment/processes/people/whatever. Each status in identified by a number 1-10. Each has a status with a domain of ten values, 1-9. And each status records the moment it was last updated.

这十个状态记录在Vaadin Grid 小部件中显示为行.

These ten status records are displayed as rows in a Vaadin Grid widget.

所有这些数据都记录在一个关系数据库中,即 H2数据库引擎 .作为演示,我们不需要持久性,因此数据库是内存中的.后台线程随机更新数据库中的状态行.

All this data is recorded in a relational database, the H2 Database Engine. As a demo, we’ve no need for persistence, so the database is in-memory. A background thread randomly updates the status rows in the database.

此数据库服务代码建立我们的内存H2数据库,为我们的Status定义表,并填充十行.该类还可以随机更新某些行的值.并且您可以要求检索表示当前存储值的ListStatus对象.

This database-service code establishes our in-memory H2 database, defining the table for our Status, and populating ten rows. This class also can randomly update the value of some of the rows. And you can ask to retrieve a List of Status objects representing the currently stored values.

每个状态记录都用Status类(一个简单的POJO)用Java表示.

Each status record is represented in Java by the Status class, a simple POJO.

Vaadin基于 Java Servlet 技术. Vaadin应用程序是Servlet的一个重要实现.作为Servlet,它可以响应用户网络浏览器的传入请求.

Vaadin is based on Java Servlet technology. Your Vaadin app is one big Servlet implementation. As a servlet, it responds to incoming requests by the users’ web browsers.

在第一个传入请求之前,我们需要进行一些设置工作.一方面,我们需要使用十个状态记录来建立并填充该数据库.

Before that first incoming request, we need to do some set-up work. For one thing, we need to establish and populate that database with our ten status records.

Servlet规范要求所有网络容器支持ServletContextListener接口.如果编写实现该接口的类并将其声明到Web容器,则将在第一个请求之前和最后一个请求之后调用它.

The Servlet specification requires all web containers to support the ServletContextListener interface. If you write a class implementing that interface, and declare it to the web container, then it will be invoked before the first request and after the last request.

在我们的示例中,我们使用该挂钩建立数据库.我们还设置了一个后台线程,该线程随机更改我们的存储状态记录,以模拟用户的更新或Feed中的最新数据.

In our example, we use that hook to establish the database. We also set up a background thread that randomly changes our stored status records to simulate either users’ updates or fresh data from a feed.

这是我们的示例ServletContextListener.

The easiest way to declare its presence to our web container is by the @WebListener annotation but you can choose other routes as needed in your deployment scenario.

@WebListener
public class MyServletContextListener implements ServletContextListener {
…

MyUI.java

此Vaadin Web应用程序的入口点是我们的UIMyUI.java子类.它有两个工作:(a)在屏幕上获取我们的用户界面内容,以及(b)将自己注册为PollListener以对轮询更新做出反应.

MyUI.java

The entry point into this Vaadin web app is our subclass of UI, MyUI.java. It has two jobs: (a) Get our user-interface content on-screen, and (b) Register itself as a PollListener to react to polling updates.

这是我们的用户界面内容.这是此示例应用程序的核心.它显示Vaadin网格,其显示将用新数据更新.

Here is our user-interface content. This is the centerpiece of this example app. It displays the Vaadin Grid whose display is to be updated with fresh data.

此经理负责监督要通过Push更新我们的DataDisplayLayout实例的pub-sub(Publish-Subscribe)模型.

This manager oversees the pub-sub (Publish-Subscribe) model of signing up instances of our DataDisplayLayout that want to be updated via Push.

此处使用弱引用的集合来跟踪订户.因此,订阅的DataDisplayLayout实例可以优雅地通知其不再更新的愿望,或者实例可以简单地超出范围,最终成为订阅者.

A collection of weak references are used here to track the subscribers. So the subscribing DataDisplayLayout instance can gracefully notify of their desire to no longer be updated, or the instance can simply go out-of-scope to eventually be dropped as a subscriber.

轮询方法不需要此管理器,因为UI子类(MyUI)的每个实例都在分别轮询服务器.

The Polling approach does not need this manager, as each instance of our UI subclass (MyUI) is individually polling the server.

Vaadin网格中表示新值的单元格的绿色是通过 CSS 设置的.在Vaadin 8中,我们通过编辑在项目的webapp文件夹中埋藏的mytheme.scss文件来执行此操作.

The green coloring of the cell in the Vaadin Grid denoting a fresh value is set via CSS. In Vaadin 8, we do this by editing the mytheme.scss file found buried in your project’s webapp folder.

在这里我们定义样式名称fresh_row.

Here we define the style name fresh_row.

@import "../valo/valo.scss";

@mixin mytheme {
  @include valo;

  // Insert your own theme rules here
  .v-grid-row.fresh_row > td:nth-child(2) {
    background-color: honeydew;
  }
}

我们必须通过实现样式生成器将该样式名称分配给Vaadin Grid行.

We must assign that style name to our Vaadin Grid rows by implementing a style generator.

this.grid.setStyleGenerator( ( StyleGenerator ) o -> {
    Status s = ( Status ) o;
    if ( s.getUpdated().isAfter( this.whenRowLastUpdated ) ) {
        return "fresh_row";
    } else {
        return null;
    }
} );

这篇关于Vaadin 8:每1分钟用服务器中的数据重新加载网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆