Vaadin で CRUD UI を作成
initial プロジェクトをチェックアウトしたか、initializr を使用してプロジェクトを作成した場合は、必要な依存関係がすべてすでにセットアップされています。ただし、このセクションの残りの部分では、Vaadin サポートを新しい Spring プロジェクトに追加する方法について説明します。Spring の Vaadin 統合には Spring Boot スターター依存関係コレクションが含まれているため、追加する必要があるのは次の Maven スニペット (または対応する Gradle 構成) だけです。
com.vaadin vaadin-spring-boot-starterこの例では、スターターモジュールによって導入されたデフォルトのバージョンよりも新しいバージョンの Vaadin を使用しています。新しいバージョンを使用するには、Vaadin 部品表(BOM)を次のように定義します。
com.vaadin vaadin-bom $ pom import デフォルトでは、Gradle は BOM をサポートしていませんが、そのための便利なプラグイン (英語) があります。同じことを実行する方法の例については、 build.gradle ビルドファイル [GitHub] (英語) をチェックしてください。メインビュークラスを定義する
メインビュークラス (このガイドでは MainView と呼ばれます) は、Vaadin の UI ロジックのエントリポイントです。Spring Boot アプリケーションでは、 @Route のアノテーションを付けると、自動的に取得され、Web アプリケーションのルートに表示されます。 @Route アノテーションにパラメーターを指定することで、ビューが表示される URL をカスタマイズできます。次のリスト ( src/main/java/com/example/crudwithvaadin/MainView.java の initial プロジェクトから) は、単純な "Hello, World" ビューを示しています。
Unresolved directive in - include::initial/src/main/java/com/example/crudwithvaadin/MainView.java[]データグリッド内のエンティティの一覧表示
レイアウトを良くするには、 Grid コンポーネントを使用できます。 setItems メソッドを使用して、コンストラクターによって注入された CustomerRepository から Grid にエンティティのリストを渡すことができます。 MainView の本体は次のようになります。
@Route public class MainView extends VerticalLayout < private final CustomerRepository repo; final Gridgrid; public MainView(CustomerRepository repo) < this.repo = repo; this.grid = new Grid(Customer.class); add(grid); listCustomers(); > private void listCustomers() < grid.setItems(repo.findAll()); >> 大規模なテーブルがある場合、または多数の同時ユーザーがある場合は、データセット全体を UI コンポーネントにバインドしたくない可能性が高くなります。 Vaadin Grid はサーバーからブラウザーにデータを遅延ロードしますが、前述のアプローチではデータのリスト全体がサーバーメモリに保持されます。メモリを節約するには、ページングを使用するか、遅延読み込み ( grid.setItems(VaadinSpringDataHelpers.fromPagingRepository(repo)) メソッドなど) を使用して、最上位の結果のみを表示できます。データのフィルタリング
大きなデータセットがサーバーで問題になる前に、ユーザーが編集する関連行を見つけようとすると、ユーザーにとって頭痛の種になる可能性があります。 TextField コンポーネントを使用して、フィルターエントリを作成できます。これを行うには、最初に listCustomer() メソッドを変更してフィルタリングをサポートします。次の例( src/main/java/com/example/crudwithvaadin/MainView.java の complete プロジェクトから)は、その方法を示しています。
void listCustomers(String filterText) < if (StringUtils.hasText(filterText)) < grid.setItems(repo.findByLastNameStartsWithIgnoreCase(filterText)); >else < grid.setItems(repo.findAll()); >> これは、Spring Data の宣言型クエリが役に立ちます。 findByLastNameStartsWithIgnoringCase の記述は、 CustomerRepository インターフェースでの単一行の定義です。リスナーを TextField コンポーネントにフックし、その値をそのフィルターメソッドにプラグインできます。 ValueChangeListener は、フィルターテキストフィールドで ValueChangeMode.LAZY を定義するため、ユーザー型として自動的に呼び出されます。次の例は、そのようなリスナーを設定する方法を示しています。
TextField filter = new TextField(); filter.setPlaceholder("Filter by last name"); filter.setValueChangeMode(ValueChangeMode.LAZY); filter.addValueChangeListener(e -> listCustomers(e.getValue())); add(filter, grid);エディターコンポーネントの定義
Vaadin UI はプレーン Java コードなので、最初から再利用可能なコードを作成できます。これを行うには、 Customer エンティティのエディターコンポーネントを定義します。これを Spring 管理の Bean にして、 CustomerRepository をエディターに直接挿入し、Create、Update、Delete パーツまたは CRUD 機能に取り組むことができます。次の例( src/main/java/com/example/crudwithvaadin/CustomerEditor.java から)は、その方法を示しています。
package com.example.crudwithvaadin; import com.vaadin.flow.component.Key; import com.vaadin.flow.component.KeyNotifier; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.data.binder.Binder; import com.vaadin.flow.spring.annotation.SpringComponent; import com.vaadin.flow.spring.annotation.UIScope; import org.springframework.beans.factory.annotation.Autowired; /** * A simple example to introduce building forms. As your real application is probably much * more complicated than this example, you could re-use this form in multiple places. This * example component is only used in MainView. ** In a real world application you'll most likely using a common super class for all your * forms - less code, better UX. */ @SpringComponent @UIScope public class CustomerEditor extends VerticalLayout implements KeyNotifier < private final CustomerRepository repository; /** * The currently edited customer */ private Customer customer; /* Fields to edit properties in Customer entity */ TextField firstName = new TextField("First name"); TextField lastName = new TextField("Last name"); /* Action buttons */ Button save = new Button("Save", VaadinIcon.CHECK.create()); Button cancel = new Button("Cancel"); Button delete = new Button("Delete", VaadinIcon.TRASH.create()); HorizontalLayout actions = new HorizontalLayout(save, cancel, delete); Binderbinder = new Binder(Customer.class); private ChangeHandler changeHandler; @Autowired public CustomerEditor(CustomerRepository repository) < this.repository = repository; add(firstName, lastName, actions); // bind using naming convention binder.bindInstanceFields(this); // Configure and style components setSpacing(true); save.addThemeVariants(ButtonVariant.LUMO_PRIMARY); delete.addThemeVariants(ButtonVariant.LUMO_ERROR); addKeyPressListener(Key.ENTER, e ->save()); // wire action buttons to save, delete and reset save.addClickListener(e -> save()); delete.addClickListener(e -> delete()); cancel.addClickListener(e -> editCustomer(customer)); setVisible(false); > void delete() < repository.delete(customer); changeHandler.onChange(); >void save() < repository.save(customer); changeHandler.onChange(); >public interface ChangeHandler < void onChange(); >public final void editCustomer(Customer c) < if (c == null) < setVisible(false); return; >final boolean persisted = c.getId() != null; if (persisted) < // Find fresh entity for editing // In a more complex app, you might want to load // the entity/DTO with lazy loaded relations for editing customer = repository.findById(c.getId()).get(); >else < customer = c; >cancel.setVisible(persisted); // Bind customer properties to similarly named fields // Could also use annotation or "manual binding" or programmatically // moving values from fields to entities before saving binder.setBean(customer); setVisible(true); // Focus first name initially firstName.focus(); > public void setChangeHandler(ChangeHandler h) < // ChangeHandler is notified when either save or delete // is clicked changeHandler = h; >>
大規模なアプリケーションでは、このエディターコンポーネントを複数の場所で使用できます。また、大規模なアプリケーションでは、いくつかの一般的なパターン(MVP など)を適用して、UI コードを構造化することもできます。
エディターを接続する
前のステップでは、コンポーネントベースのプログラミングのいくつかの基本を見てきました。 Button を使用し、選択リスナーを Grid に追加することにより、エディターをメインビューに完全に統合できます。次のリスト( src/main/java/com/example/crudwithvaadin/MainView.java からの)は、 MainView クラスの最終バージョンを示しています。
package com.example.crudwithvaadin; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.grid.Grid; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.data.value.ValueChangeMode; import com.vaadin.flow.router.Route; import org.springframework.util.StringUtils; @Route public class MainView extends VerticalLayout < private final CustomerRepository repo; private final CustomerEditor editor; final Gridgrid; final TextField filter; private final Button addNewBtn; public MainView(CustomerRepository repo, CustomerEditor editor) < this.repo = repo; this.editor = editor; this.grid = new Grid(Customer.class); this.filter = new TextField(); this.addNewBtn = new Button("New customer", VaadinIcon.PLUS.create()); // build layout HorizontalLayout actions = new HorizontalLayout(filter, addNewBtn); add(actions, grid, editor); grid.setHeight("300px"); grid.setColumns("id", "firstName", "lastName"); grid.getColumnByKey("id").setWidth("50px").setFlexGrow(0); filter.setPlaceholder("Filter by last name"); // Hook logic to components // Replace listing with filtered content when user changes filter filter.setValueChangeMode(ValueChangeMode.LAZY); filter.addValueChangeListener(e -> listCustomers(e.getValue())); // Connect selected Customer to editor or hide if none is selected grid.asSingleSelect().addValueChangeListener(e -> < editor.editCustomer(e.getValue()); >); // Instantiate and edit new Customer the new button is clicked addNewBtn.addClickListener(e -> editor.editCustomer(new Customer("", ""))); // Listen changes made by the editor, refresh data from backend editor.setChangeHandler(() -> < editor.setVisible(false); listCustomers(filter.getValue()); >); // Initialize listing listCustomers(null); > // tag::listCustomers[] void listCustomers(String filterText) < if (StringUtils.hasText(filterText)) < grid.setItems(repo.findByLastNameStartsWithIgnoreCase(filterText)); >else < grid.setItems(repo.findAll()); >> // end::listCustomers[] > 実行可能 JAR を構築するコマンドラインから Gradle または Maven を使用してアプリケーションを実行できます。必要なすべての依存関係、クラス、リソースを含む単一の実行可能 JAR ファイルを構築して実行することもできます。実行可能な jar を構築すると、開発ライフサイクル全体、さまざまな環境などで、アプリケーションとしてサービスを簡単に提供、バージョン管理、デプロイできます。
Gradle を使用する場合、 ./gradlew bootRun を使用してアプリケーションを実行できます。または、次のように、 ./gradlew build を使用して JAR ファイルをビルドしてから、JAR ファイルを実行できます。
java -jar build/libs/gs-crud-with-vaadin-0.0.1-SNAPSHOT.jarMaven を使用する場合、 ./mvnw spring-boot:run を使用してアプリケーションを実行できます。または、次のように、 ./mvnw clean package で JAR ファイルをビルドしてから、JAR ファイルを実行できます。
java -jar target/gs-crud-with-vaadin-0.0.1-SNAPSHOT.jarVaadin アプリケーションが http://localhost:8080 で実行されていることがわかります
要約
おめでとう! 永続化のために Spring Data JPA を使用して、フル機能の CRUD UI アプリケーションを作成しました。そして、REST サービスを公開したり、JavaScript や HTML の 1 行を記述したりすることなく、それを実行しました。
関連事項
- Spring Boot アプリケーションの構築
- JPA でインメモリ H2 データアクセス
- MongoDB でデータアクセス
- Neo4j でデータアクセス
- JPA で MySQL データアクセス
コードを入手する
Get the Spring newsletter
Stay connected with the Spring newsletter
Copyright © 2005 - 2026 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. Terms of Use (英語) • Privacy (英語) • Trademark Guidelines
Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra™, and Apache Geode™ are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java™, Java™ SE, Java™ EE, and OpenJDK™ are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.