Статьи

Введение в использование Vaadin в Spring Boot

Вступление

В основе действий Vaadin лежит рендеринг на стороне сервера, поэтому его можно естественным образом интегрировать в такие среды, как Spring. Интеграция Vaadin в Spring уже давно лежит и предоставляет инструменты для настройки и управления Vaadin в контейнере Spring, и если вы хотите использовать Vaadin с Spring Boot, то вам повезло, потому что ребята из Vaadin уже сделали работа по созданию стартеров, которые автоматически настраивают практически все, чтобы вы могли за несколько секунд запустить и запустить простой пользовательский интерфейс. В этом посте мы кратко рассмотрим, как работать с Vaadin в Spring boot.

Настроить

Лучший способ создать загрузочное приложение Spring — использовать Spring Initializr . Мы собираемся проверить Vaadin вместе с другими стандартными версиями Spring, такими как Web и Security, и щелкнуть «Создать проект».

Чтобы создать представление в корне пути контекста, достаточно создать класс, расширяющий UI и аннотировать его с помощью @SpringUI .

1
2
3
4
5
6
7
8
@SpringUI
public class Main extends UI {
 
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        setContent(new Label("Hello"));
    }
}

Если используемый путь отличается от корневого, можно использовать @SpringUI(path="/app") : @SpringUI(path="/app") .

Интерфейсы и представления

Концепция пользовательских интерфейсов Vaadin аналогична концепции SPA (одностраничных приложений). Класс UI рассматривается как корневой контейнер нескольких представлений. Представление можно рассматривать как определенное состояние пользовательского интерфейса. Приложение может иметь несколько классов UI , но рекомендуется иметь один UI с несколькими представлениями, потому что это более эффективно. С помощью Navigator можно настроить маршрутизацию от просмотра к другому, не покидая страницы или UI . Чтобы создать представление, нам просто нужно реализовать интерфейс представления и аннотировать его с помощью @SpringView или, если область (о которой мы будем говорить в будущем) не очень важна, подойдет любая аннотация Spring инъекций:

1
2
3
4
5
6
7
8
@SpringView
public class Add extends Composite implements View {
 
    @PostConstruct
    public void init() {
        setCompositionRoot(new Label("I am a view"));
    }
}

Здесь мы использовали метод init() с @PostConstruct чтобы убедиться, что Spring завершил внедрение любых полей (если они есть). Также возможно использовать конструктор, если нет введенных полей.

пример

Vaadin — это полноценный фреймворк, имеющий широкий спектр компонентов , из которых может выбирать разработчик (макеты, диаграммы, сетки …). Также предлагается возможность создания пользовательских компонентов. Например, мы хотим создать приложение для сбора автомобилей, которое позволяет вводить и перечислять модели автомобилей:

Добавить вид:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@SpringView
public class Add extends Composite implements View {
 
    @Autowired
    CarRepository repository;
 
    @Autowired
    DataProvider dataProvider;
 
    @PostConstruct
    public void init() {
        FormLayout formLayout = new FormLayout();
        Label title = new Label("Add new Car");
        TextField brandInput = new TextField("Brand: ");
        TextField modelInput = new TextField("Model: ");
        TextField pictureLinkInput = new TextField("Picture Link: ");
        Button button = new Button("Add", clickEvent -> {
            repository.save(new Car(brandInput.getValue(), modelInput.getValue(), pictureLinkInput.getValue()));
            Notification.show("saved");
        });
        formLayout.addComponent(title);
        formLayout.addComponent(brandInput);
        formLayout.addComponent(modelInput);
        formLayout.addComponent(pictureLinkInput);
        formLayout.addComponent(button);
        setCompositionRoot(formLayout);
    }
}

Представление списка:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@SpringView
public class List extends Composite implements View {
 
    @Autowired
    CarRepository repository;
 
    @Autowired
    DataProvider dataProvider;
 
    @PostConstruct
    public void init() {
        Grid<Car> carGrid = new Grid<>();
        carGrid.setWidth("100%");
        carGrid.setHeight("100%");
        carGrid.setDataProvider(dataProvider);
        carGrid.addColumn(Car::getId).setCaption("Id");
        carGrid.addColumn(Car::getBrand).setCaption("Brand");
        carGrid.addColumn(Car::getModel).setCaption("Model");
        carGrid.addColumn((ValueProvider<Car, Object>) car ->
        new ExternalResource(car.getPictureLink())).setCaption("Picture")
        .setRenderer(new ImageRenderer()).setResizable(true);
        setCompositionRoot(carGrid);
        setSizeFull();
    }
}

Основной интерфейс:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@SpringUI(path="app")
public class Main extends UI {
 
    @Autowired
    Add addView;
 
    @Autowired
    List listView;
 
 
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        HorizontalLayout rootLayout = new HorizontalLayout();
        rootLayout.setSizeFull();
        HorizontalLayout mainarea = new HorizontalLayout();
        mainarea.setWidth("80%");
        Navigator navigator = new Navigator(this, mainarea);
        navigator.addView("", addView);
        navigator.addView("add", addView);
        navigator.addView("list", listView);
 
 
        CssLayout sideNav = new CssLayout();
        sideNav.setSizeFull();
        sideNav.addStyleName("sidenav");
        sideNav.setId("sideNav");
        sideNav.setWidth("20%");
 
        Button link1 = new Button("Add", e -> navigator.navigateTo("add"));
        link1.addStyleNames(BUTTON_LINK, MENU_ITEM);
        Button link2 = new Button("List", e -> navigator.navigateTo("list"));
        link2.addStyleNames(BUTTON_LINK, MENU_ITEM);
        sideNav.addComponent(link1);
        sideNav.addComponent(link2);
        rootLayout.addComponent(sideNav);
        rootLayout.addComponent(mainarea);
        setContent(rootLayout);
    }
}

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

1
2
3
4
Navigator navigator = new Navigator(this, mainarea);
        navigator.addView("", addView);
        navigator.addView("add", addView);
        navigator.addView("list", listView);

важно иметь "" пустой маршрут по умолчанию, потому что обычно маршрут не устанавливается при запуске. Поскольку Vaadin использует свои собственные темы и таблицы стилей, аннотация @StyleSheet в случае введения пользовательских стилей. Наши представления и пользовательские интерфейсы подключены к контейнеру Spring, поэтому можно внедрить любой bean-компонент Spring. Например, мы CarRepository который является JpaRepository для выполнения операций базы данных на объектах Car .

Безопасность

Vaadin использует свои собственные токены CSRF, поэтому механизм Spring CSRF должен быть отключен, чтобы приложение работало должным образом, если используется Spring Security. Минимальная конфигурация безопасности может выглядеть так:

1
2
3
4
5
6
7
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/app**").authenticated().and().formLogin().and().csrf().disable();
    }
}

Заворачивать

Vaadin можно рассматривать как альтернативу для быстрого создания пользовательских интерфейсов с бэкэндом Spring Boot. Поначалу Vaadin может быть легко настроен, но кажется, что кривая обучения не так гладка, когда сложность возрастает. Другим недостатком, который может быть замечен при работе с Vaadin (не только с Spring), является необходимость перезапускать все приложение (Spring Container обычно запускается некоторое время) каждый раз, когда вносятся изменения, что приводит к необходимости настройки HotSwap или аналогичные инструменты для горячей перезагрузки кода без перезапуска приложения.

Опубликовано на Java Code Geeks с разрешения Закарии Амине, партнера по нашей программе JCG . Смотрите оригинальную статью здесь: Введение в использование Vaadin в Spring Boot

Мнения, высказанные участниками Java Code Geeks, являются их собственными.