当前位置: 首页 > 知识库问答 >
问题:

带Vaadin UI的Spring boot应用程序不断刷新屏幕

姜华翰
2023-03-14

我有一个启动应用程序,我正在添加一些crud屏幕。我决定使用Vaadin,在我将其部署到多节点生产环境之前,它似乎工作得很好。一旦进入prod环境,屏幕就会无缘无故地不断刷新。例如,在一个屏幕中有一个网格,当单击一行时,会弹出一个显示项目详细信息的对话框。但一旦对话框弹出,页面就会刷新多次。

这个论坛的帖子在这里https://vaadin.com/forum/thread/17586129/routerlayout-causing-page-refresh是我正在使用的相同布局的一个示例,描述了一个非常类似的问题。

我有一个扩展VerticalLayout的基础抽象类,所有的具体类都扩展了这个基础抽象类。每个混凝土类定义自己的管线并使用公共布局类。

我已经联系了gitter,瓦丁论坛,并在github中打开了一个bug,但据我所知,瓦丁没有人想回应任何事情。

以下是我使用的所有版本:Vaadin Flow版本:14 Java版本:12.0.1 12 OS版本:Mac 10.14.5浏览器版本:Fire Fox 70.0.1,Chrome 78.0.3904.97

我的实现中的代码片段:主视图

@Slf4j
@RoutePrefix("v1/crud")
@Theme(value = Material.class, variant = Material.DARK)
public class MainView extends Div implements RouterLayout {
private H1 h1 = new H1("Vaadin Crud UI");
private HorizontalLayout header = new HorizontalLayout(h1);
private Div content = new Div();
private ApplicationContext context;

@Inject
public MainView(ApplicationContext context) {
    this.context = context;
    setSizeFull();
    h1.setWidthFull();
    content.setWidthFull();
    header.setWidthFull();
    header.setAlignItems(FlexComponent.Alignment.CENTER);
    VerticalLayout navigationBar = new VerticalLayout();
    navigationBar.setWidth("25%");

    navigationBar.add(createNavigationButton("Home", VaadinIcon.HOME, ReportTab.class));
    navigationBar.add(createNavigationButton("Batch Search", VaadinIcon.SEARCH, BatchSearchTab.class));
    ... a bunch more buttons
    HorizontalLayout layout = new HorizontalLayout(navigationBar, content);
    layout.setWidthFull();
    VerticalLayout page = new VerticalLayout(header, layout);
    page.setWidthFull();
    add(page);
}

@Override
public void showRouterLayoutContent(HasElement hasElement) {
    if (hasElement != null) {
        Element newElement = hasElement.getElement();
        if (newElement != null) {
            content.removeAll();
            content.getElement().appendChild(newElement);
        }
    }
}

private Button createNavigationButton(String caption, VaadinIcon icon, Class<? extends BaseEditor> editor) {
    Button button = new Button(caption, icon.create());
    button.addClickListener(event -> UI.getCurrent().navigate(editor));
    button.addThemeVariants(ButtonVariant.MATERIAL_CONTAINED);
    button.getStyle().set("background-color", "#00819D");
    button.setWidthFull();
    return button;
}

}

基础组件:

@Slf4j
@Data
@SpringComponent
@UIScope
public abstract class BaseEditor<P, B> extends VerticalLayout {

private final RememberMeService rememberMe;
private final P businessProcess;
protected Binder<B> binder;
protected Dialog editDialog = new Dialog();
protected Button save = new Button("Save", VaadinIcon.CHECK.create());
protected Button close = new Button("Close", VaadinIcon.EXIT.create());
protected Button delete = new Button("Delete", VaadinIcon.TRASH.create());
protected B bean;

private ChangeHandler changeHandler;
private boolean proceed = true;

public BaseEditor(P businessProcess, RememberMeService rememberMe) {
    this.rememberMe = rememberMe;
    this.businessProcess = businessProcess;
    save.addClickListener(e -> save());
    delete.addClickListener(e -> delete());
}

public abstract void delete();

public abstract void save();

protected abstract Component getContent();

protected void edit(B e) {
    bean = e;
    editDialog.open();
    getBinder().setBean(e);
}

protected void initEditorPanel(Component... components) {
    HorizontalLayout actions = new HorizontalLayout(save, close, delete);
    VerticalLayout data = new VerticalLayout(components);
    data.add(actions);
    editDialog.removeAll();
    editDialog.add(data);
    getBinder().bindInstanceFields(this);
    close.addClickListener(e -> editDialog.close());
}

public interface ChangeHandler {
    void onChange();
}

void setChangeHandler(ChangeHandler h) {
    changeHandler = h;
}

void errorDialog(String message) {
    final Button close = new Button("Close", VaadinIcon.CLOSE.create());
    H3 h3 = new H3(message);
    final Dialog errorDialog = new Dialog(h3, close);
    errorDialog.open();
    close.addClickListener(e -> errorDialog.close());
}

BaseEditor filter(Predicate<B> predicate) {
    Objects.requireNonNull(predicate);
    proceed = predicate.test(bean);
    return this;
}

void buttonConsumer(Consumer<B> consumer) {
    if (!proceed) {
        proceed = true;
        return;
    }
    try {
        consumer.accept(bean);
    } catch (Exception e) {
        errorDialog(e.getMessage());
    } finally {
        editDialog.close();
        getChangeHandler().onChange();
    }
}

void either(Consumer<B> whenTrue, Consumer<B> whenFalse) {
    try {
        if (proceed) {
            whenTrue.accept(bean);
        } else {
            whenFalse.accept(bean);
        }
    } catch (Exception e) {
        errorDialog(e.getMessage());
    } finally {
        proceed = true;
        editDialog.close();
        getChangeHandler().onChange();
    }
}
}

混凝土构件:

@Slf4j
@Route(value = "search/batch", layout = MainView.class)
public class BatchSearchTab extends BaseEditor<BatchService, Batch> {
private TextField searchField1;
private TextField searchField2;

public BatchSearchTab(BatchService businessProcess, RememberMeService rememberMe) {
    super(businessProcess, rememberMe);
    binder = new Binder<>(Batch.class);
    save.setIcon(VaadinIcon.REPLY.create());
    save.setText("Replay");
    delete.setIcon(VaadinIcon.CLOSE.create());
    delete.setText("Cancel");
    getContent();
}

@Override
public void delete() {
    buttonConsumer(b -> getBusinessProcess().cancelBatch(b.getBatchId(), b.getUserAgent()));
}

@Override
public void save() {
    filter(b -> b.isReplayable()).buttonConsumer(b -> getBusinessProcess().buildAndSendFile((getBean())));
}

@Override
public void edit(Batch batch) {
    HorizontalLayout actions = new HorizontalLayout();
    H2 h2 = new H2();
    if (batch.isReplayable()) {
        h2.setText("Would you like to replay the following.");
        actions.add(save, delete, close);
    } else {
        h2.setText("This record is not eligible for replay.");
        actions.add(close);
    }

    Label batchId = new Label("Correlation Id: " + batch.getBatchId());
    Label txnCount = new Label("Transaction Count: " + batch.getTotalTxns());
    Label txnAmount = new Label("Total: " + batch.getTotalBatchAmount());
    VerticalLayout data = new VerticalLayout(h2, batchId, txnCount, txnAmount, actions);
    data.add(actions);
    editDialog.removeAll();
    editDialog.add(data);
    close.addClickListener(e -> editDialog.close());
    editDialog.open();
    getBinder().setBean(batch);
}

@Override
protected Component getContent() {
    final H2 h2 = new H2("Locate Batches");
    searchField1 = new TextField("Batch Code");
    searchField2 = new TextField("User Agent");
    searchField2.addKeyPressListener(Key.ENTER, e -> keyPressListener());
    Button searchBtn = new Button("Search", VaadinIcon.SEARCH.create());
    HorizontalLayout search = new HorizontalLayout(searchField1, searchField2);
    searchBtn.addClickListener(e -> {
        search(searchField1.getValue(), searchField2.getValue());
    });
    add(h2, search, searchBtn);
    return this;
}

private void search(String code, String userAgent) {
    log.info("Searching {} and {}", code, userAgent);
    List<Batch> batches =
        getBusinessProcess().getBatchesForUserAgent(code, userAgent, 60);
    log.info("Found {} batches", batches.size());
    if (batches.size() > 0) {
        buildGrid(batches, "BatchId", "totalTxns", "totalBatchAmount", "status");
    } else {
        errorDialog("No Records found for criteria");
    }
}

private void keyPressListener() {
    String code = StringUtils.isNotBlank(searchField1.getValue()) ? searchField1.getValue() : null;
    if (StringUtils.isNotBlank(searchField2.getValue())) {
        search(code, searchField2.getValue());
    }
}

private void buildGrid(Collection<Batch> records, String... columns) {
    Component result;
    if (records.size() == 0) {
        result = new Label("NO REPORT DATA AVAILABLE.");
    } else {
        final Grid<Batch> grid = new Grid<>(Batch.class);
        grid.setHeightByRows(records.size() < 10);
        grid.setColumns(columns);
        grid.setItems(records);
        grid.setWidthFull();
        grid.asSingleSelect().addValueChangeListener(l -> Optional.ofNullable(l.getValue()).ifPresent(this::edit));
        result = grid;
    }
    if (getComponentCount() < 3) {
        add(result);
    } else {
        replace(getComponentAt(2), result);
    }
}

private void loadData(String code, String userAgent) {
    if (StringUtils.isNotBlank(code)) {
        search(null, userAgent);
    } else {
        search(code, userAgent);
    }
}
}

共有1个答案

令狐宏浚
2023-03-14

免责声明:一些进一步的事实调查通过IRC进行

这个问题的答案与OP在循环加载ballancer之后运行应用程序的多个实例有关。客户端随机访问服务器,因此没有会话在那里运行。

解决方案是有一个共享会话存储,理想情况下在现有会话上有load ballancer dispatch,这样“热”后端服务器就会受到影响。

 类似资料:
  • Fancybox破坏Swiper。在没有可见CSS和DOM更改的情况下添加偏移量。要在jsbin(https://output.jsbin.com/jiqucacete)上复制此问题,您需要: 1)按下swiper幻灯片图像2)转到fancybox图库弹出的下一个图像3)关闭图库,在swiper中将有幻灯片变化 它是如何工作的?为什么没有可见的CSS、DOM更改?如何修复?

  • 我使用的是Appium版本1.4.0(draco)和Xcode版本6.4。我无法让刷卡功能在我的自动测试中工作。iOS的模拟器设备是iPad air。任何有用的帖子将不胜感激。

  • 【参数】 子链刷新的参数在subchainbase.sol中定义。参数列表如下: 1.刷新周期Round数值:定义子链经过多少区块后刷新。假如子链有100个节点,每个节点依次产生block,定义Round数为5,则每过500block 刷新一次。 2.当前刷新id 索引:指定下次刷新的id 在Nodelist中 的索引值 3.刷新过期数值expiration:指定的id在block [0, 2*e

  • 使用android软键盘输入文本并使用键盘下方可用的键手动关闭后,应用程序页面不会刷新。键盘所在的位置显示一个黑色空间。 我尝试了windowSoftInputMode的各种可用选项,但没有解决这个问题。遗憾的是,adjustPan没有表现出预期的行为。当windowSoftInputMode设置为adjustPan时,键盘隐藏文本字段。 隐藏软键盘后如何使页面刷新以消除此问题?

  • } 用于显示股票的HTML页面:

  • 这是我使用SpringBoot的第一天,我试图理解体系结构,因此我开始构建一个hello world应用程序: 在我的pom.xml中,在maven-shade-plugin下,我将mainClass声明如下: 文件目标是src/main/java/com/demo/helloworld.java,该文件中的代码是: 我错过了什么?