Introduction to using Vaadin in Spring Boot
Introduction
Vaadin’s way of doing things rely on server-side rendering, so it can be integrated naturally into frameworks like Spring. Vaadin’s Spring integration has been lying around for a while now, and provides tools for configuring and managing Vaadin within the Spring container, and if you are looking to use Vaadin with Spring Boot then you are in luck, because the Vaadin folks has already done the work of creating starters that autoconfigure pretty much everything so that you can get a simple UI up and running in matter of seconds. In this post, we will take a brief look on how to work with Vaadin in Spring boot.
Set up
The best way to create a Spring boot application is by using Spring Initializr. We are going to check Vaadin along with other standard Spring starters like Web and Security and click on “Generate Project”.
To create a view at the root of the context path, it is enough to create a class that extends UI
and to annotate it with @SpringUI
.
@SpringUI public class Main extends UI { @Override protected void init(VaadinRequest vaadinRequest) { setContent(new Label("Hello")); } }
If the path to be used is different than the root, the path property can be used: @SpringUI(path="/app")
.
UIs and Views
Vaadin’s concept of user interfaces is similar to the concept of SPAs (Single Page Applications). A UI
class is considered as the root container of several views. A view can be seen as a particular state of a UI. An application can have several UI
classes, but it is recommended to have one UI
with several views because it is more efficient. With the help of the Navigator
, the routing can be configured from a view to another without leaving the page or the UI
. To create a View
, we simply need to implement the view interface and annotate it with @SpringView
or if the scope (We will talk about view scopes in the future) is not really important, any Spring injection annotation would work:
@SpringView public class Add extends Composite implements View { @PostConstruct public void init() { setCompositionRoot(new Label("I am a view")); } }
We have used here the init()
method with the @PostConstruct
to make sure that Spring has finished injecting any fields (if there is any). It also possible to use the constructor in case there is no injected fields.
Example
Vaadin is a fully fledged framework, and has wide range of components that the developer can choose from (layouts, charts, grids..). It also offers the possibility to create custom components. As an example, we want to create a car collection app that allows entering and listing car models:
The Add view:
@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); } }
The list view:
@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(); } }
The Main UI:
@SpringUI(path="app") @StyleSheet({"http://localhost:8080/styles.css"}) 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); } }
We have created two views: one form for adding cars and a grid for displaying them. The UI class wires up the two views using the navigator
. The UI is composed of two parts: a side navigation bar with links to views and the main area which is the variable part. We have configured the navigator
to dispatch views only in the main area, and configured the routes to each view:
Navigator navigator = new Navigator(this, mainarea); navigator.addView("", addView); navigator.addView("add", addView); navigator.addView("list", listView);
it is important to have a default ""
empty route because usually the route is not set on start up. As Vaadin uses its own themes and stylesheets, the @StyleSheet
annotation comes handy in case custom styles are to be introduced. Our views and UIs are wired up to the Spring container, so it is possible to inject any Spring bean. For example, we injected the CarRepository
which is a JpaRepository
for performing database operations on Car
entities.
Security
Vaadin uses its own CSRF tokens, so the Spring CSRF mechanism should be disabled for the app to work properly, if Spring Security is used. A minimal security configuration can look like:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/app**").authenticated().and().formLogin().and().csrf().disable(); } }
Wrap up
Vaadin can be seen as an alternative for rapidly creating UIs with a Spring Boot backend. Vaadin may be easy to set up at first, but it appears that the learning curve is not that smooth when complexity increases. Another drawback that may be noticed when working with Vaadin (not only with Spring) is having to restart the whole app (Spring Container takes a while to start usually) every time a change is made, which leads to the necessity of setting up HotSwap
or similar tools for hot reloading the code without having the restart application.
- Source code: https://github.com/zak905/vaadin-spring-boot
Published on Java Code Geeks with permission by Zakaria Amine, partner at our JCG program. See the original article here: Introduction to using Vaadin in Spring Boot Opinions expressed by Java Code Geeks contributors are their own. |