«1. Обзор

Vaadin — это серверная среда Java для создания пользовательских веб-интерфейсов.

В этом руководстве мы рассмотрим, как использовать пользовательский интерфейс на основе Vaadin в серверной части на основе Spring Boot. Для ознакомления с Vaadin обратитесь к этому руководству.

2. Настройка

Давайте начнем с добавления зависимостей Maven в стандартное приложение Spring Boot:

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

Vaadin также является зависимостью, распознаваемой Spring Initializer.

В этом туториале используется более новая версия Vaadin, чем та, что используется по умолчанию в начальном модуле. Чтобы использовать более новую версию, просто определите спецификацию Vaadin следующим образом:

<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. Серверная служба

Мы будем использовать сущность Employee со свойствами firstName и lastName для выполнения над ней операций CRUD. :

@Entity
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;
    private String lastName;
}

Вот простой соответствующий репозиторий Spring Data — для управления операциями CRUD:

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

Мы объявляем метод запроса findByLastNameStartsWithIgnoreCase в интерфейсе EmployeeRepository. Он вернет список сотрудников, соответствующих фамилии.

Давайте также предварительно заполним БД несколькими образцами сотрудников:

@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

4.1. Класс MainView

Класс MainView является точкой входа для логики пользовательского интерфейса Vaadin. Аннотация @Route указывает Spring Boot автоматически подобрать его и показать в корневом каталоге веб-приложения:

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

Мы можем настроить URL-адрес, по которому отображается представление, указав параметр для аннотации @Route:

@Route(value="myhome")

Класс использует следующие компоненты пользовательского интерфейса для отображения на странице:

Редактор EmployeeEditor — показывает форму Employee, используемую для предоставления информации о сотрудниках для создания и редактирования.

Grid\u003cEmployee\u003e grid — gird для отображения списка сотрудников

TextField filter — текстовое поле для ввода фамилии, по которой будет фильтроваться gird

Button addNewBtn — Button чтобы добавить нового сотрудника. Отображает редактор EmployeeEditor.

Он внутренне использует employeeRepository для выполнения операций CRUD.

4.2. Соединение компонентов вместе

MainView расширяет VerticalLayout. VerticalLayout — это контейнер компонентов, который показывает подкомпоненты в порядке их добавления (по вертикали).

Далее мы инициализируем и добавляем компоненты.

Мы даем метку кнопке со значком +.

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

Мы используем HorizontalLayout для горизонтального размещения текстового поля фильтра и кнопки. Затем добавьте этот макет, сетку и редактор в родительский вертикальный макет:

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

Укажите высоту связки и имена столбцов. Мы также добавляем текст справки в текстовое поле:

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

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

При запуске приложения пользовательский интерфейс будет выглядеть так:

4.3. Добавление логики к компонентам

Мы установим ValueChangeMode.EAGER в текстовое поле фильтра. Это синхронизирует значение с сервером каждый раз, когда оно изменяется на клиенте.

Мы также установили прослушиватель для события изменения значения, которое возвращает отфильтрованный список сотрудников на основе текста, предоставленного в фильтре:

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

При выборе строки в гирде мы показываем форму Сотрудник , позволяя пользователю редактировать имя и фамилию:

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

При нажатии кнопки добавления нового сотрудника мы показываем пустую форму сотрудника:

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

Наконец, мы слушаем изменения, внесенные редактора и обновить сетку данными из бэкенда:

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

Функция listEmployees получает отфильтрованный список сотрудников и обновляет сетку:

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

4.4. Построение формы

Мы будем использовать простую форму для пользователя, чтобы добавлять/редактировать сотрудника:

@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.

@UIScope связывает компонент с текущим пользовательским интерфейсом Vaadin.

В настоящее время отредактированный сотрудник хранится в переменной-члене сотрудника. Мы фиксируем свойства Employee через текстовые поля firstName и lastName.

Форма имеет три кнопки – сохранить, отменить и удалить.

Когда все компоненты соединены вместе, форма для выбора строки будет выглядеть, как показано ниже:

Мы используем Binder, который связывает поля формы со свойствами сотрудника, используя соглашение об именах:

binder.bindInstanceFields(this);

«

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

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

«Мы вызываем соответствующий метод EmployeeRepositor на основе пользовательских операций:

5. Заключение

В этой статье мы написали полнофункциональное приложение CRUD с пользовательским интерфейсом, используя Spring Boot и Spring Data JPA для сохраняемости.