Vaadin:任务完成后无法获得 receive/react 的进度对话框
Vaadin: Cannot get progress dialog to receive/react when the task completes
我写了一个小的 Spring Boot/Vaadin 应用程序,它显示一个简单的 UI 来接受用户输入并调用另一个需要一些时间的服务 运行.提交任务后,我将显示一个进度对话框,其中显示一个进度条、一条消息通知用户正在发生什么以及一个关闭按钮以允许他们在作业完成时关闭对话框。我正在使用 ListenableFuture
在任务完成时收到通知。
我可以让对话框以“正在执行”的状态出现,并且进度条正在做它的事情,但是当任务完成时(我有调试语句去控制台让我知道),它不会触发更新状态消息和启用关闭按钮的逻辑。我不知道我做错了什么。
代码如下:
MainView1.java
@Route("rescheduleWorkOrders1")
@CssImport("./styles/shared-styles.css")
public class MainView1 extends VerticalLayout {
...
private final BackendService service;
public MainView1(BackendService service) {
this.service = service;
configureView();
addSubmitButton();
bindFields();
}
private void addSubmitButton() {
Button submit = new Button("Submit", this::submit);
add(submit);
}
private void submit(ClickEvent<?> event) {
UserData data = binder.getBean();
ListenableFuture<ResponseEntity<String>> future = service.executeTask(data);
ProgressDialog dialog = new ProgressDialog(future);
dialog.open();
}
private void configureView() {
...
}
private void bindFields() {
...
}
}
ProgressDialog.java
public class ProgressDialog extends Dialog {
private final ListenableFuture<ResponseEntity<String>> future;
private ProgressBar bar;
private Paragraph message;
private Button close;
public ProgressDialog(ListenableFuture<ResponseEntity<String>> future) {
super();
this.future = future;
configureView();
this.future.addCallback(new ListenableFutureCallback<>() {
@Override
public void onSuccess(ResponseEntity<String> result) {
message.setText("Task complete. Status: " + result.getStatusCode());
bar.setVisible(false);
close.setEnabled(true);
}
@Override
public void onFailure(Throwable ex) {
message.setText(ex.getMessage());
bar.setVisible(false);
close.setEnabled(true);
}
});
}
private void configureView() {
bar = new ProgressBar();
bar.setIndeterminate(true);
bar.setVisible(true);
message = new Paragraph("Executing task ...");
close = new Button("Close", this::close);
close.setEnabled(false);
add(bar, message, close);
}
private void close(ClickEvent<?> event) {
this.close();
}
}
BackendService.java
@Service
public class BackendService {
@Async
public ListenableFuture<ResponseEntity<String>> executeTask(UserData data) {
...
RestTemplate template = new RestTemplate();
ResponseEntity<String> response = template.postForEntity(uri, entity, String.class);
System.out.println(response);
return AsyncResult.forValue(response);
}
}
注意:我确实在 @Configuration
中指定了 @EnableAsync
注释 class。
在 Vaadin 中处理异步代码时,您需要:
- 在活动请求之外更新 UI 时使用
UI#access
。这会获取 UI 上的锁,以防止它被两个线程同时更新。
- 通过将
@Push
注释添加到您的主布局或视图来启用服务器推送。这允许服务器将更新推送到客户端,即使没有请求处于活动状态。
没有前者,在最好的情况下你会得到 ConcurrentModificationException
s,在最坏的情况下会得到非常微妙的错误。
如果没有后者,更改将被应用(即对话框关闭),但更改只会在客户端下次发送请求时发送给客户端。我相信这是您的主要问题。
可以在 documentation 中找到更多信息。
我写了一个小的 Spring Boot/Vaadin 应用程序,它显示一个简单的 UI 来接受用户输入并调用另一个需要一些时间的服务 运行.提交任务后,我将显示一个进度对话框,其中显示一个进度条、一条消息通知用户正在发生什么以及一个关闭按钮以允许他们在作业完成时关闭对话框。我正在使用 ListenableFuture
在任务完成时收到通知。
我可以让对话框以“正在执行”的状态出现,并且进度条正在做它的事情,但是当任务完成时(我有调试语句去控制台让我知道),它不会触发更新状态消息和启用关闭按钮的逻辑。我不知道我做错了什么。
代码如下:
MainView1.java
@Route("rescheduleWorkOrders1")
@CssImport("./styles/shared-styles.css")
public class MainView1 extends VerticalLayout {
...
private final BackendService service;
public MainView1(BackendService service) {
this.service = service;
configureView();
addSubmitButton();
bindFields();
}
private void addSubmitButton() {
Button submit = new Button("Submit", this::submit);
add(submit);
}
private void submit(ClickEvent<?> event) {
UserData data = binder.getBean();
ListenableFuture<ResponseEntity<String>> future = service.executeTask(data);
ProgressDialog dialog = new ProgressDialog(future);
dialog.open();
}
private void configureView() {
...
}
private void bindFields() {
...
}
}
ProgressDialog.java
public class ProgressDialog extends Dialog {
private final ListenableFuture<ResponseEntity<String>> future;
private ProgressBar bar;
private Paragraph message;
private Button close;
public ProgressDialog(ListenableFuture<ResponseEntity<String>> future) {
super();
this.future = future;
configureView();
this.future.addCallback(new ListenableFutureCallback<>() {
@Override
public void onSuccess(ResponseEntity<String> result) {
message.setText("Task complete. Status: " + result.getStatusCode());
bar.setVisible(false);
close.setEnabled(true);
}
@Override
public void onFailure(Throwable ex) {
message.setText(ex.getMessage());
bar.setVisible(false);
close.setEnabled(true);
}
});
}
private void configureView() {
bar = new ProgressBar();
bar.setIndeterminate(true);
bar.setVisible(true);
message = new Paragraph("Executing task ...");
close = new Button("Close", this::close);
close.setEnabled(false);
add(bar, message, close);
}
private void close(ClickEvent<?> event) {
this.close();
}
}
BackendService.java
@Service
public class BackendService {
@Async
public ListenableFuture<ResponseEntity<String>> executeTask(UserData data) {
...
RestTemplate template = new RestTemplate();
ResponseEntity<String> response = template.postForEntity(uri, entity, String.class);
System.out.println(response);
return AsyncResult.forValue(response);
}
}
注意:我确实在 @Configuration
中指定了 @EnableAsync
注释 class。
在 Vaadin 中处理异步代码时,您需要:
- 在活动请求之外更新 UI 时使用
UI#access
。这会获取 UI 上的锁,以防止它被两个线程同时更新。 - 通过将
@Push
注释添加到您的主布局或视图来启用服务器推送。这允许服务器将更新推送到客户端,即使没有请求处于活动状态。
没有前者,在最好的情况下你会得到 ConcurrentModificationException
s,在最坏的情况下会得到非常微妙的错误。
如果没有后者,更改将被应用(即对话框关闭),但更改只会在客户端下次发送请求时发送给客户端。我相信这是您的主要问题。
可以在 documentation 中找到更多信息。