JavaData & JavaGetting Started with Spring and Vaadin

Getting Started with Spring and Vaadin

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Vaadin, down the years, has matured; so has Spring. They can be a killer combination when it comes to developing Web-based applications. Vaadin can be used do the presentation work whereas Spring does all the heavy lifting of delivering business services. This article provides an overview of integrating these two frameworks and shows a simple example of how they can be used in developing Web-based applications.

Overview

There are numerous presentation layer frameworks available for developing Java-based Web applications. Each of them has its way in delivering the developer’s specific needs. Vaadin distinctively is one among them. An interesting aspect of Vaadin as a presentation layer framework is that we can use plain Java code to design a functional Web interface, much like the Swing framework is used to design a desktop application interface. Although not limited to Java code-based approach only, Vaadin also provides an alternate option for HTML-based design. These clearly distinguish Vaadin from other JavaScript-based frameworks.

Spring

Spring is an open source framework to develop Java enterprise applications. In fact, it provides almost everything needed to create any Java-based applications, including support for Groovy and Kotlin as alternative languages on the JVM. The Spring framework is divided into modules; as a result, they can be nitpicked and used according to your need. The heart of the modules is the core container with a configuration model and dependency injection mechanism. Apart from this, there id foundational support for different application architectures, such as Web, messaging, transaction, and persistence. It also has the support of the Servlet-based Spring MVC Web framework and Spring Web Flux reactive Web framework.

Historically, Spring began its journey in 2003 as a simpler alternative to the J2EE specification, and today has emerged as a fine complement to Java EE technology by selectively integrating distinct specifications from the Java EE spectrum, such as Concurrency utilities (JSR 236), Bean Validation (JSR 303), Servlet API (JSR 340), WebSocket API (JSR 356), JSON Binding API (JSR 367), JMS (JSR 914), JPA (JSR 338), and so forth, to name a few.

The evolution with Spring 5 went further into much more than just a framework and shifted the paradigm of Java programming once and for all with innovative projects such as Spring Boot, Spring Batch, Spring Integration, Spring Data, Spring Cloud, and so on.

In our following example, we’ll use Spring Boot to transitively import all the dependencies required for the application. In association with Vaadin, Spring shall do the heavy lifting of providing background business services using JPA technology and Vaadin shall provide the view for data presentation in the browser.

Vaadin

Vaadin is an open source Web application development platform that provides a set of tools and starters, apart from its flagship product called Vaadin Flow (previously called Vaadin framework). In short, it started as a framework that enabled implementation of an HTML Web user interface using Java programming. This is what is called Vaadin Flow now. Later on, it started proving high-level component APIs that do more than just presentation work. According to official documentation, Vaadin provides:

  • Automatic support for client-server communication using WebSocket
  • Support for building Web views using pure Java code or HTML
  • Data binding support
  • Route with nested route and parameter support
  • Other JVM language support such as Kotlin and Scala
  • Built-in Spring support

Integrating Vaadin and Spring

Spring, as a framework, is an open design for integrating various other technologies. As a result, it is no surprise that Vaadin would find its niche in Spring, almost effortlessly. It would be an exaggeration to say that Vaadin is an exceptional web UI design framework, but it serves its purpose. It is distinct because it allows a Java code-based design approach. A Java developer who mainly focuses on the business service development rarely finds interest in UI design. Vaadin is a good choice for them. Vaadin can be used to develop a highly responsive Web interface, yet, perhaps the glorious part of it is that it allows a Java developer a little idea of how JavaScript is able to develop a functional, decent Web interface using Java code only. That singularly deserves kudos for the Vaadin developers.

As stated, that Spring is an open-ended architecture, integrating them is like walking in the park, thanks to Spring Boot. Here, we’ll try a very simple example; nothing fancy, of course, with Spring JPA functionality. The code is kept simple and elaborate to make it as lucid as possible.

A Quick Example

<?xml version="1.0" encoding="UTF-8"?>
<project 
      xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.mano</groupId>
   <artifactId>spring-vaadin-app1</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>spring-vaadin-app1</name>
   <description>
      Demo project for Spring Boot
   </description>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>
         spring-boot-starter-parent
      </artifactId>
      <version>2.0.6.RELEASE</version>
      <relativePath/>
         <!-- look up parent from repository -->
   </parent>
   <properties>
      <project.build.sourceEncoding>
         UTF-8
      </project.build.sourceEncoding>
      <project.reporting.outputEncoding>
         UTF-8
      </project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <vaadin.version>10.0.5</vaadin.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>
            spring-boot-starter-data-jpa
         </artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>
            spring-boot-starter-web
         </artifactId>
      </dependency>
      <dependency>
         <groupId>com.vaadin</groupId>
         <artifactId>
            vaadin-spring-boot-starter
         </artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-devtools</artifactId>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <scope>runtime</scope>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>
            spring-boot-starter-test
         </artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-bom</artifactId>
            <version>${vaadin.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>
   <build>
      <plugins>
         <plugin>
            <groupId>
               org.springframework.boot
            </groupId>
            <artifactId>
               spring-boot-maven-plugin
            </artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Listing 1: pom.xml

server.port = 8080
# ===============================
# = DATA SOURCE - MYSQL
# ===============================
spring.datasource.url = jdbc:mysql://localhost:3306/testdb
spring.datasource.username = root
spring.datasource.password = secret
pring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
# ===============================
# = JPA / HIBERNATE
# ===============================
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create-drop
#spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.naming-strategy =
   org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect =
   org.hibernate.dialect.MySQL5Dialect

Listing 2: application.properties

package com.mano.springvaadinapp1.model;
import javax.persistence.*;
@Entity
public class Employee {
   @Id
   @GeneratedValue
   privateLong id;
   private String name;
   // Contact
   private String phone;
   private String email;
   public Employee() {
   }
   public Employee(String name, String phone, String email) {
      this.name = name;
      this.phone = phone;
      this.email = email;
   }
   public Long getId() {
      return id;
   }
   public void setId(Long id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getPhone() {
      return phone;
   }
   public void setPhone(String phone) {
      this.phone = phone;
   }
   public String getEmail() {
      return email;
   }
   public void setEmail(String email) {
      this.email = email;
   }
   @Override
   public String toString() {
      return "Employee{" +
         "id=" + id +
         ", name='" + name + ''' +
         ", phone='" + phone + ''' +
         ", email='" + email + ''' +
         '}';
   }
}

Listing 3: Employee.java

package com.mano.springvaadinapp1.repository;
import com.mano.springvaadinapp1.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends
      JpaRepository<Employee, Long> {
   Employee findByName(String name);
}

Listing 4: EmployeeRepository.java

package com.mano.springvaadinapp1.ui;
import com.mano.springvaadinapp1.model.Employee;
import com.mano.springvaadinapp1.repository.EmployeeRepository;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.html.NativeButton;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.listbox.ListBox;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;
@Route("test")
public class TestUI extends HorizontalLayout{
   private TextField txtname, txtphone,
      txtemail;
   private Button btnAddNew;
   private ListBox<Employee> listBox =
      new ListBox<>();
   private EmployeeRepository repo;
   @Autowired
   public TestUI(EmployeeRepository repo){
      this.repo = repo;
      listBox.setItems(repo.findAll());
      listBox.setRenderer(new ComponentRenderer<>(emp -> {
         Label name = new Label("Name: " + emp.getName());
         Label phone = new Label("Phone: " + emp.getPhone());
         Label email = new Label("Email: " + emp.getEmail());
         NativeButton button = new NativeButton("Delete",
               event -> {
            repo.delete(emp);
            clearFormData();
            listBox.getDataProvider().refreshItem(emp);
         });
         Div labels = new Div(name, phone,email);
         Div layout = new Div(labels, button);
         labels.getStyle().set("display", "flex")
            .set("flexDirection", "column")
            .set("marginRight", "10px");
         layout.getStyle().set("display", "flex")
            .set("alignItems", "center");
         return layout;
      }));
      listBox.setItemEnabledProvider(employee -> {
         employee = repo.findByName(employee.getName());
         if (employee!=null)
            return true;
         else
            return false;
      });
      listBox.addValueChangeListener(event ->
         populateForm(listBox.getValue()));
      add(listBox, createForm());
   }
   private FormLayout createForm(){
      FormLayout f = new FormLayout();
      txtname = new TextField("Name");
      txtphone = new TextField("Phone");
      txtemail = new TextField("Email");
      btnAddNew = new Button("Add New",
         VaadinIcon.PLUS.create());
      btnAddNew.addClickListener(event->save());
      f.add(txtname,txtemail,txtphone,btnAddNew);
      return f;
   }
   private void save(){
      if (txtname.isEmpty() || txtphone.isEmpty()
            || txtemail.isEmpty()) {
         Notification.show("Input data cannot be empty");
         return;
      }
      Employee emp = repo.findByName(txtname
         .getValue().trim());
      if (emp==null) {
         repo.save(new Employee(txtname.getValue(),
            txtphone.getValue(), txtemail.getValue()));
         listBox.setItems(repo.findAll());
      }else{
         Notification.show("Cannot save. Same name
            exists. Try different name.");
      }
      clearFormData();
   }
   public void clearFormData(){
      txtname.setValue("");
      txtphone.setValue("");
      txtemail.setValue("");
   }
   public void populateForm(Employee emp){
      txtname.setValue(emp.getName());
      txtemail.setValue(emp.getEmail());
      xtphone.setValue(emp.getPhone());
   }
}

Listing 5: TestUI.java

package com.mano.springvaadinapp1;
import com.mano.springvaadinapp1.model.Employee;
import com.mano.springvaadinapp1.repository
   .EmployeeRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure
   .SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
   private static final Logger log =
      LoggerFactory.getLogger(Application.class);
   public static void main(String[] args) {
      SpringApplication.run(Application.class);
   }

   @Bean
   publicCommandLineRunner loadData(EmployeeRepository
         repository) {
      return (args) -> {
         repository.save(new Employee("Sachin Tendulkar",
            "987654321","sachin@gmail.com"));
         repository.save(new Employee("Kapil Dev",
            "34543543","kaipi@gmail.com"));
         repository.save(new Employee("Sunil Gavaskar",
            "565534321","sunil@fastmail.com"));
         repository.save(new Employee("Ravi Sastri",
            "3445543521","ravi@yahoo.com"));
         repository.save(new Employee("Navjit Sidhu",
            "234555","nav@outlook.com"));
         // Fetch all employees
         log.info("Employees found with findAll():");
         log.info("-------------------------------");
         for (Employee e : repository.findAll()) {
            log.info(e.toString());
         }
         log.info("");
         Employee employee= repository.findById(1L).get();
         log.info("Employee found with findOne(1L):");
         log.info("--------------------------------");
         log.info(employee.toString());
         log.info("");
      };
   }
}

Listing 6: Application.java

Output

Output of the running program
Figure 1: Output of the running program

Conclusion

It is fun to integrate Spring and Vaadin; they work together seamlessly. The example given above is to give an idea how to integrate both into the framework. Note that the application above is not thoroughly tested; hence, it may have some runtime issues, my bad! I did it in a hurry. Feel free to take it from there and enhance it. Happy coding 🙂

References

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories