Spring Boot和Vaadin的示例应用程序

Sample Application with Spring Boot and Vaadin

1.概述

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

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

2.设定

首先,将Maven依赖项添加到标准Spring Boot应用程序中:

1
2
3
4
<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>

Vaadin也是Spring Initializer公认的依赖项。

本教程使用的Vaadin版本比启动程序模块带来的默认版本要高。 要使用更新的版本,只需定义Vaadin物料清单(BOM),如下所示:

1
2
3
4
5
6
7
8
9
10
11
<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.后端服务

我们将使用具有firstName和lastName属性的Employee实体对其执行CRUD操作:

1
2
3
4
5
6
7
8
9
10
@Entity
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;
    private String lastName;
}

这是简单,对应的Spring Data存储库–用于管理CRUD操作:

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

我们在EmployeeRepository接口上声明查询方法findByLastNameStartsWithIgnoreCase。 它将返回与姓氏匹配的雇员列表。

让我们还用一些示例雇员来预填充数据库:

1
2
3
4
5
6
7
8
9
@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.我叫UI

4.1。 MainView类别

MainView类是Vaadin的UI逻辑的入口点。 注释@Route告诉Spring Boot自动选择它并显示在Web应用程序的根目录:

1
2
3
4
5
6
7
8
@Route
public class MainView extends VerticalLayout {
    private EmployeeRepository employeeRepository;
    private EmployeeEditor editor;
    Grid<Employee> grid;
    TextField filter;
    private Button addNewBtn;
}

我们可以通过为@Route批注提供参数来自定义显示视图的URL:

1
@Route(value="myhome")

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

EmployeeEditor编辑器–显示用于提供员工信息以创建和编辑的Employee表单。

Grid 网格–显示雇员列表的网格

TextField过滤器–用于输入将过滤网格的姓氏的文本字段

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

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

4.2。 将组件连接在一起

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

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

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

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

我们使用HorizontalLayout来水平排列过滤器文本字段和按钮。 然后将此布局,围栏和编辑器添加到父垂直布局中:

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

提供网格高度和列名称。 我们还将在文本字段中添加帮助文本:

1
2
3
4
5
grid.setHeight("200px");
grid.setColumns("id","firstName","lastName");
grid.getColumnByKey("id").setWidth("50px").setFlexGrow(0);

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

在应用程序启动时,UI将如下所示:

 width=

4.3。 向组件添加逻辑

我们将ValueChangeMode.EAGER设置为过滤器文本字段。 每次在客户端上更改值时,它将值同步到服务器。

我们还为值更改事件设置了一个侦听器,该侦听器根据过滤器中提供的文本返回经过过滤的员工列表:

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

在网格中选择一行时,我们将显示Employee表单,允许用户编辑名字和姓氏:

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

单击添加新员工按钮后,我们将显示空白的员工表单:

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

最后,我们听听编辑器所做的更改,并使用来自后端的数据刷新网格:

1
2
3
4
editor.setChangeHandler(() -> {
    editor.setVisible(false);
    listEmployees(filter.getValue());
});

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

1
2
3
4
5
6
7
void listEmployees(String filterText) {
    if (StringUtils.isEmpty(filterText)) {
        grid.setItems(employeeRepository.findAll());
    } else {
        grid.setItems(employeeRepository.findByLastNameStartsWithIgnoreCase(filterText));
    }
}

4.4。 建立表格

我们将为用户使用一个简单的表单来添加/编辑员工:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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;
}

@SpringComponent只是Springs @Component批注的别名,以避免与Vaadins Component类发生冲突。

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

当前,已编辑的Employee存储在employee成员变量中。 我们通过firstName和lastName文本字段捕获Employee属性。

表单具有三个按钮-保存,取消和删除。

将所有组件连接在一起后,表格将如下所示进行行选择:

 width=

我们使用了一个活页夹,该活页夹使用命名约定将表单字段与Employee属性绑定在一起:

1
binder.bindInstanceFields(this);

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

1
2
3
4
5
6
7
8
9
void delete() {
    repository.delete(employee);
    changeHandler.onChange();
}

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

5.结论

在本文中,我们使用Spring Boot和Spring Data JPA编写了功能全面的CRUD UI应用程序,以实现持久性。

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