首页 > 解决方案 > 将新记录添加到数据库时更新 vaadin 网格

问题描述

我想将元素添加到数据库中的表中并使用新数据更新网格(可能我应该直接在 UI 上将记录添加到表中,但无论如何)。

我的grid组件看起来像这样

@SpringComponent
public class PlayersGrid extends Grid<Player> {

    @PostConstruct
    public void afterInit() {
        addColumn(Player::getId).setHeader("ID");
        addColumn(Player::getName).setHeader("Name");
        addColumn(Player::getCharacterClass).setHeader("Class");
        addColumn(Player::getLevel).setHeader("Level");
    }

    public class GridContentObserver implements ContentObserver {

        @Override
        public void refreshContent() {
            PlayersGrid.this.getDataProvider().refreshAll();
        }
    }
}

players通过看起来像这样的表单添加

@SpringComponent
public class CharacterCreationForm extends FormLayout {
    private static final Logger LOGGER = LoggerFactory.getLogger(CharacterCreationForm.class);

    private List<ContentObserver> boundObservers = new ArrayList<>();

    private TextField name;
    private TextField characterClass;
    private TextField level;

    @Autowired
    private PlayerRepository repository;

    @PostConstruct
    public void create() {
        name = new TextField();
        characterClass = new TextField();
        level = new TextField();

        addFormItem(name, "Name");
        addFormItem(characterClass, "Class");
        addFormItem(level, "Level");

        Binder<Player> binder = new Binder<>(Player.class);

        binder
            .forField(level)
            .withConverter(new StringToIntegerConverter(0, ""))
            .bind(Player::getLevel, Player::setLevel);

        binder.bindInstanceFields(this);

        Button button = new Button("Save");
        button.addClickListener(buttonClickEvent -> {
            try {
                Player newPlayer = new Player();
                binder.writeBean(newPlayer);
                LOGGER.info("Attempt to write object: {}", newPlayer);

                repository.save(newPlayer);
                // notify observers
                boundObservers.forEach(ContentObserver::refreshContent);
            } catch (ValidationException e) {
                e.printStackTrace();
            }
        });

        add(button);
    }

    public void addObserver(ContentObserver observer) {
        boundObservers.add(observer);
    }

}

我在应用程序中的主视图如下所示

public MainView(PlayerRepository repository, PlayersGrid grid, CharacterCreationForm form) {
    form.addObserver(grid.new GridContentObserver());
    form.setWidth("30%");

    // find the way to set items in the component
    grid.setItems(repository.findAll());

    HorizontalLayout horizontalLayout = new HorizontalLayout();
    horizontalLayout.add(form);

    VerticalLayout verticalLayout = new VerticalLayout();
    verticalLayout.add(grid, form);
    verticalLayout.setHeight("100%");
    add(verticalLayout);

    setClassName("main-layout");
}

启动时,我将所有存储的玩家都放在网格中。但是当我使用表单保存新记录时,它会在数据库中添加新记录,但不会更新网格。

怎么了?

标签: spring-bootvaadinvaadin-flow

解决方案


尝试以下更改,我认为这些更改会使代码更清晰并解决 ContentObserver 的问题

(没有运行代码,所以我不确定编译问题!)

更改 1:PlayersGrid 实现 ContentObserver 而不是内部类

@SpringComponent
public class PlayersGrid extends Grid<Player> implements ContentObserver {

    @PostConstruct
    public void afterInit() {
        addColumn(Player::getId).setHeader("ID");
        addColumn(Player::getName).setHeader("Name");
        addColumn(Player::getCharacterClass).setHeader("Class");
        addColumn(Player::getLevel).setHeader("Level");
    }

    @Override
    public void refreshContent() {
        this.getDataProvider().refreshAll();
    }
}

更改 2:boundObservers.forEach

@SpringComponent
public class CharacterCreationForm extends FormLayout {
    private static final Logger LOGGER = 
            LoggerFactory.getLogger(CharacterCreationForm.class);

    private List<ContentObserver> boundObservers = new ArrayList<>();

    private TextField name;
    private TextField characterClass;
    private TextField level;

    @Autowired
    private PlayerRepository repository;

    @PostConstruct
    public void create() {
        name = new TextField();
        characterClass = new TextField();
        level = new TextField();

        addFormItem(name, "Name");
        addFormItem(characterClass, "Class");
        addFormItem(level, "Level");

        Binder<Player> binder = new Binder<>(Player.class);

        binder
            .forField(level)
            .withConverter(new StringToIntegerConverter(0, ""))
            .bind(Player::getLevel, Player::setLevel);

        binder.bindInstanceFields(this);

        Button button = new Button("Save");
        button.addClickListener(buttonClickEvent -> {
            try {
                Player newPlayer = new Player();
                binder.writeBean(newPlayer);
                LOGGER.info("Attempt to write object: {}", newPlayer);

                repository.save(newPlayer);
                // notify observers

                // updated
                boundObservers.forEach( observer -> observer.refreshContent() );

            } catch (ValidationException e) {
                e.printStackTrace();
            }
        });

        add(button);
    }

    public void addObserver(ContentObserver observer) {
        boundObservers.add(observer);
    }

}

变化3:grid现在也是ContentObserver,所以更容易管理和理解。

public MainView(PlayerRepository repository, PlayersGrid grid, CharacterCreationForm form) {
    // updated
    form.addObserver(grid);
    form.setWidth("30%");

    // find the way to set items in the component
    grid.setItems(repository.findAll());

    HorizontalLayout horizontalLayout = new HorizontalLayout();
    horizontalLayout.add(form);

    VerticalLayout verticalLayout = new VerticalLayout();
    verticalLayout.add(grid, form);
    verticalLayout.setHeight("100%");
    add(verticalLayout);

    setClassName("main-layout");
}

推荐阅读