Sample Application with Spring Boot and Vaadin – 使用Spring Boot和Vaadin的示例应用程序

最后修改: 2018年 8月 4日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Vaadin is a server-side Java framework for creating web user interfaces.

Vaadin是一个用于创建Web用户界面的服务器端Java框架

In this tutorial, we’ll explore how to use a Vaadin based UI on a Spring Boot based backend. For an introduction to Vaadin refer to this tutorial.

在本教程中,我们将探讨如何在基于Spring Boot的后端使用基于Vaadin的UI。有关Vaadin的介绍,请参考教程。

2. Setup

2.设置

Let’s start by adding Maven dependencies to a standard Spring Boot application:

让我们先在一个标准的Spring Boot应用程序中添加Maven依赖项。

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>

Vaadin is also a recognized dependency by the Spring Initializer.

Vaadin也是一个被Spring Initializer认可的依赖关系。

This tutorial uses a newer version of Vaadin than the default one brought in by the starter module. To use the newer version, simply define the Vaadin Bill of Materials (BOM) like this:

本教程使用的是一个较新的Vaadin版本,而不是启动模块带来的默认版本。要使用较新的版本,只需像这样定义Vaadin的物料清单(BOM)。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-bom</artifactId>
            <version>10.0.11</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3. Backend Service

3.后端服务

We’ll use an Employee entity with firstName and lastName properties to perform CRUD operations on it:

我们将使用一个带有firstNamelastName属性的Employee实体来对其进行CRUD操作。

@Entity
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;
    private String lastName;
}

Here’s the simple, corresponding Spring Data repository – to manage the CRUD operations:

这里有一个简单的、对应的Spring Data仓库–管理CRUD操作。

public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    List<Employee> findByLastNameStartsWithIgnoreCase(String lastName);
}

We declare query method findByLastNameStartsWithIgnoreCase on the EmployeeRepository interface. It will return the list of Employees matching the lastName.

我们在EmployeeRepository接口上声明查询方法findByLastNameStartsWithIgnoreCase。它将返回符合lastNameEmployee列表。

Let’s also pre-populate the DB with a few sample Employees:

让我们也用几个样本雇员来预先填充DB。

@Bean
public CommandLineRunner loadData(EmployeeRepository repository) {
    return (args) -> {
        repository.save(new Employee("Bill", "Gates"));
        repository.save(new Employee("Mark", "Zuckerberg"));
        repository.save(new Employee("Sundar", "Pichai"));
        repository.save(new Employee("Jeff", "Bezos"));
    };
}

4. Vaadin UI

4.我需要用户界面

4.1. MainView Class

4.1.MainView

The MainView class is the entry point for Vaadin’s UI logic. Annotation @Route tells Spring Boot to automatically pick it up and show at the root of the web app:

MainView类是Vaadin的UI逻辑的入口。注解@Route告诉Spring Boot自动拾取它并显示在Web应用程序的根部:

@Route
public class MainView extends VerticalLayout {
    private EmployeeRepository employeeRepository;
    private EmployeeEditor editor;
    Grid<Employee> grid;
    TextField filter;
    private Button addNewBtn;
}

We can customize the URL where the view is shown by giving a parameter to the @Route annotation:

我们可以通过给@Route注释一个参数来定制显示视图的URL。

@Route(value="myhome")

The class uses following UI components to be displayed on the page:

该类使用以下UI组件在页面上显示。

EmployeeEditor editor – shows the Employee form used to provide employee information to create and edit.

EmployeeEditor编辑器 – 显示Employee表格,用于提供雇员信息的创建和编辑。

Grid<Employee> grid – gird to display the list of Employees

Grid<Employee> grid – 显示Employees的列表。

TextField filter – text field to enter the last name based on which the gird will be filtered

TextField filter – 输入姓氏的文本字段,将根据该字段进行过滤。

Button addNewBtn – Button to add a new Employee. Displays the EmployeeEditor editor.

Button addNewBtn – 添加新雇员的按钮。显示EmployeeEditor编辑器。

It internally uses the employeeRepository to perform the CRUD operations.

它内部使用employeeRepository来执行CRUD操作。

4.2. Wiring the Components Together

4.2.将部件连在一起的接线

MainView extends VerticalLayout. VerticalLayout is a component container, which shows the subcomponents in the order of their addition (vertically).

MainView扩展了VerticalLayoutVerticalLayout是一个组件容器,它按添加顺序显示子组件(垂直)。

Next, we initialize and add the components.

接下来,我们初始化并添加组件。

We provide a label to the button with a + icon.

我们为该按钮提供一个带有 “+”图标的标签。

this.grid = new Grid<>(Employee.class);
this.filter = new TextField();
this.addNewBtn = new Button("New employee", VaadinIcon.PLUS.create());

We use HorizontalLayout to horizontally arrange filter text field and the button. Then add this layout, gird, and editor into the parent vertical layout:

我们使用HorizontalLayout来水平排列过滤文本字段和按钮。然后将这个布局、腰带和编辑器添加到父级垂直布局中。

HorizontalLayout actions = new HorizontalLayout(filter, addNewBtn);
add(actions, grid, editor);

Provide the gird height and column names. We also add help text in the text field:

提供腰围高度和列名。我们还在文本字段中添加帮助文本。

grid.setHeight("200px");
grid.setColumns("id", "firstName", "lastName");
grid.getColumnByKey("id").setWidth("50px").setFlexGrow(0);

filter.setPlaceholder("Filter by last name");

On the application startup, UI would look this:

在应用程序启动时,用户界面会是这样的。

vaadin1

4.3. Adding Logic to Components

4.3.为组件添加逻辑

We’ll set ValueChangeMode.EAGER to the filter text field. This syncs the value to the server each time it’s changed on the client.

我们将把ValueChangeMode.EAGER设为filter文本字段。这样,每次在客户端上改变数值时,都会同步到服务器上。

We also set a listener for the value change event, which returns the filtered list of employees based on the text provided in the filter:

我们还为价值变化事件设置了一个监听器,它根据过滤器中提供的文本返回过滤后的雇员名单:

filter.setValueChangeMode(ValueChangeMode.EAGER);
filter.addValueChangeListener(e -> listEmployees(e.getValue()));

On selecting a row within the gird, we would show the Employee form, allowing the user to edit the first name and last name:

在选择腰带内的一行时,我们将显示雇员表格,允许用户编辑名字和姓氏。

grid.asSingleSelect().addValueChangeListener(e -> {
    editor.editEmployee(e.getValue());
});

On clicking the add new employee button, we would show the blank Employee form:

在点击添加新员工按钮时,我们将显示空白的员工表格。

addNewBtn.addClickListener(e -> editor.editEmployee(new Employee("", "")));

Finally, we listen to the changes made by the editor and refresh the grid with data from the backend:

最后,我们听从编辑器的变化,用后台的数据刷新网格。

editor.setChangeHandler(() -> {
    editor.setVisible(false);
    listEmployees(filter.getValue());
});

The listEmployees function gets the filtered list of Employees and updates the grid:

listEmployees函数获取过滤后的Employees列表并更新网格。

void listEmployees(String filterText) {
    if (StringUtils.isEmpty(filterText)) {
        grid.setItems(employeeRepository.findAll());
    } else {
        grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText));
    }
}

4.4. Building the Form

4.4.构建表格

We’ll use a simple form for the user to add/edit an employee:

我们将使用一个简单的表单让用户添加/编辑一个雇员。

@SpringComponent
@UIScope
public class EmployeeEditor extends VerticalLayout implements KeyNotifier {

    private EmployeeRepository repository;
    private Employee employee;

    TextField firstName = new TextField("First name");
    TextField lastName = new TextField("Last name");

    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);
    Binder<Employee> binder = new Binder<>(Employee.class);
    private ChangeHandler changeHandler;
}

The @SpringComponent is just an alias to Springs @Component annotation to avoid conflicts with Vaadins Component class.

@SpringComponent只是Spring @Component注解的一个别名,以避免与Vaadins Component类的冲突。

The @UIScope binds the bean to the current Vaadin UI.

@UIScope将Bean绑定到当前的Vaadin UI。

Currently, edited Employee is stored in the employee member variable. We capture the Employee properties through firstName and lastName text fields.

目前,编辑过的Employee被存储在employee成员变量中。我们通过firstNamelastName文本字段捕获Employee属性。

The form has three button – save, cancel and delete.

该表格有三个按钮 – 保存取消删除

Once all the components are wired together, the form would look as below for a row selection:

一旦所有的组件被连接在一起,表格看起来就像下面的行选择。

vaadin2

We use a Binder which binds the form fields with the Employee properties using the naming convention:

我们使用一个Binder,它使用命名惯例将表单字段与Employee属性绑定起来

binder.bindInstanceFields(this);

We call the appropriate EmployeeRepositor method based on the user operations:

我们根据用户的操作,调用适当的EmployeeRepositor方法。

void delete() {
    repository.delete(employee);
    changeHandler.onChange();
}

void save() {
    repository.save(employee);
    changeHandler.onChange();
}

5. Conclusion

5.结论

In this article, we wrote a full-featured CRUD UI application using Spring Boot and Spring Data JPA for persistence.

在这篇文章中,我们使用Spring Boot和Spring Data JPA编写了一个全功能的CRUD UI应用程序,用于持久性。

As usual, the code is available over on GitHub.

像往常一样,代码可在GitHub上获得。