Building Your First Vaadin Application

Building Your First Vaadin Application

Vaadin is a powerful server-side Java framework for creating web user interfaces. In this tutorial, we'll explore how to use Vaadin to build a simple web application. We'll be using Spring Boot as our backend and Vaadin for the frontend.

Setting Up the Project

To start creating your first application in Vaadin, you need to set up a new project. You can use the Spring Initializr to create a new Spring Boot application with the desired dependencies. Here are the steps:

  1. Open https://start.spring.io/.

  2. Choose "Maven" for the project and "3.0.6" for Spring Boot.

  3. Click on "Add Dependencies" and search for "Vaadin".

  4. Add any other dependencies you might want for your project, like "Spring Data JPA", "Spring Security", or "JOOQ Access Layer".

  5. Enter the Artifact and Group you want for your project.

  6. Write a brief description for your project.

  7. Click "Generate" to download the configured project.

  8. Unzip the package and import the folder into your Integrated Development Environment (IDE) as a Maven project.

Now you have created an empty project and are ready to start developing the User Interface (UI) and functionality.

Creating a Simple HelloWorld Application

Let's start with a simple HelloWorld application to make sure everything is working fine. Here's a small HelloWorld.java you can use to test:

Java

package org.vaadin.example.springapp;

import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.router.Route;

@Route("/")
public class HelloWorld extends Div {

    public HelloWorld() {
        add(new Button("Click to say hello", this::sayHello));
    }

    public void sayHello(ClickEvent<Button> e) {
        Notification.show("Hello stranger");
    }
}

To start the server, just open the context menu on the SpringAppApplication.java file and click “Run Java”. This will start the embedded web server and Vaadin in development mode. Now that your server is running, head to [http://localhost:8080/](http://localhost:8080/) to access your newly created Vaadin application.

Building a CRUD Application

Now that we have a basic Vaadin application up and running, let's build a more complex application that performs CRUD (Create, Read, Update, Delete) operations on an Employee entity.

Java

First, let's create the `Employee` entity:
@Entity
public class Employee {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;
    private String lastName;
}

Next, let's create a Spring Data repository to manage the CRUD operations:

Java

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

We can also pre-populate the database with a few sample Employees:

Java

@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"));
    };
}

Now, let's create the Vaadin UI for our CRUD application. We'll start by creating a MainView class, which is the entry point for Vaadin’s UI logic:

Java

@Route
public class MainView extends VerticalLayout {
    private EmployeeRepository employee

Repository;
    private EmployeeEditor editor;
    Grid<Employee> grid;
    TextField filter;
    private Button addNewBtn;

    public MainView(EmployeeRepository repository, EmployeeEditor editor) {
        this.employeeRepository = repository;
        this.editor = editor;
        this.grid = new Grid<>(Employee.class);
        this.filter = new TextField();
        this.addNewBtn = new Button("New employee", VaadinIcon.PLUS.create());

        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");

        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(null);
    }

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

In this class, we've created a grid to display the list of Employees, a text field to filter the list by last name, and a button to add a new Employee. We've also added listeners to handle user interactions, such as filtering the list, selecting an Employee to edit, and adding a new Employee.

Finally, let's create the EmployeeEditor class, which is a form for editing an Employee:

Java

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

    private final 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;

    public EmployeeEditor(EmployeeRepository repository) {
        this.repository = repository;

        add(firstName, lastName, actions);

        binder.bindInstanceFields(this);

        setSpacing(true);

        save.getElement().getThemeList().add("primary");
        delete.getElement().getThemeList().add("error");

        addKeyPressListener(Key.ENTER, e -> save());

        save.addClickListener(e -> save());
        delete.addClickListener(e -> delete());
        cancel.addClickListener(e -> editEmployee(employee));
        setVisible(false);
    }

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

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

    public interface ChangeHandler {
        void onChange();
    }

    public final void editEmployee(Employee e) {
        if (e == null) {
            setVisible(false);
            return;
        }
        final boolean persisted = e.getId() != null;
        if (persisted) {
            employee = repository.findById(e.getId()).get();
        } else {
            employee = e;
        }
        cancel.setVisible(persisted);
        binder.setBean(employee);
        setVisible(true);
        firstName.focus();
    }

    public void setChangeHandler(ChangeHandler h) {
        changeHandler = h;
    }
}

In this class, we've created text fields for editing the first name and last name of an Employee, and buttons for saving, cancelling, and deleting. We've also added listeners to handle user interactions, such as saving changes, cancelling edits, and deleting an Employee.

The editEmployee method is used to switch the form between creating a new Employee and editing an existing one. If the given Employee is null, the form is hidden. If the Employee has an ID (i.e., it's persisted), we retrieve the persisted Employee from the repository and make the cancel button visible. If the Employee doesn't have an ID (i.e., it's new), we use the given Employee as is and hide the cancel button.

The setChangeHandler method is used to register a callback to be called when an Employee is saved or deleted. This callback is used to update the list of Employees in the MainView.

With these classes, you have a basic Vaadin application that can create, read, update, and delete Employees. You can run the application by running the main method in the Spring Boot application class. The application will be accessible at [http://localhost:8080/](http://localhost:8080/).

Conclusion

In this tutorial, we've shown you how to create a simple Vaadin application with Spring Boot. We've covered setting up a new project, creating a simple HelloWorld application, and building a CRUD application. We hope this tutorial helps you get started with Vaadin and Spring Boot. Happy coding!

Did you find this article valuable?

Support Anay Sinhal by becoming a sponsor. Any amount is appreciated!