How we built Spring PetClinic 100% in Java
Tags: java, spring, webdev
Published: 2021-12-17 17:28:34

---
title: How we built Spring PetClinic 100% in Java
published: true
description: Vaadin Flow lets you build modern web applications without writing HTML or JavaScript. See how we implemented PetClinic fully in Java.
tags: java, spring, webdev
//cover_image: https://direct_url_to_image.jpg
---

If you've been part of the Spring community for a while, you may have run into the [PetClinic sample application](https://spring-petclinic.github.io/). PetClinic aims to give you a realistic example application showcasing everyday development tasks with Spring technologies. 

![The original Spring and Thymeleaf implementation of PetClinic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zio87udw83ziahyrne1a.jpg)
<figcaption>The original Spring and Thymeleaf implementation of PetClinic.</figcaption>



In addition to being the official Spring demo app, there is a [thriving community of alternate implementations](https://github.com/spring-petclinic) on GitHub. Having the same example implemented with different frontend and backend technologies can be helpful for learning about new technologies and understanding how they differ from each other. 

In the past month, we spent some time implementing both Vaadin [Flow](https://vaadin.com/flow) and [Fusion](https://vaadin.com/fusion) versions of PetClinic. I'll walk through some highlights in the Flow version in this post. 

![Vaadin Flow version of PetClinic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x6mkvz9sja0nrj071ln.png)
<figcaption>Vaadin Flow version of PetClinic</figcaption>

## Building a web app frontend without HTML
As you look through the code of the [Vaadin Flow PetClinic application](https://github.com/spring-petclinic/spring-petclinic-vaadin-flow),  one thing will hit you: there are no HTML templates. This is because the views are implemented in Java. 

As a concrete example, compare how pet owners are listed with Thymeleaf templates with how they are listed in Flow. 

```html
<table id="owners" class="table table-striped">
  <thead>
  <tr>
    <th style="width: 150px;">Name</th>
    <th style="width: 200px;">Address</th>
    <th>City</th>
    <th style="width: 120px">Telephone</th>
    <th>Pets</th>
  </tr>
  </thead>
  <tbody>
  <tr th:each="owner : ${listOwners}">
    <td>
      <a th:href="@{/owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
    </td>
    <td th:text="${owner.address}"/>
    <td th:text="${owner.city}"/>
    <td th:text="${owner.telephone}"/>
    <td><span th:text="${#strings.listJoin(owner.pets, ', ')}"/></td>
  </tr>
  </tbody>
</table>
<div th:if="${totalPages > 1}">
  <span>Pages:</span>
  <span>[</span>
  <span th:each="i: ${#numbers.sequence(1, totalPages)}">
      <a th:if="${currentPage != i}" th:href="@{'/owners/?page=' + ${i}}">[[${i}]]</a>
      <span th:unless="${currentPage != i}">[[${i}]]</span>
    </span>
  <span>]&nbsp;</span>
  <span>
      <a th:if="${currentPage > 1}" th:href="@{'/owners/?page=1'}" title="First"
         class="fa fa-fast-backward"></a>
      <span th:unless="${currentPage > 1}" title="First" class="fa fa-fast-backward"></span>
    </span>
  <span>
      <a th:if="${currentPage > 1}" th:href="@{'/owners/?page=' + ${currentPage - 1}}" title="Previous"
         class="fa fa-step-backward"></a>
      <span th:unless="${currentPage > 1}" title="Previous" class="fa fa-step-backward"></span>
    </span>
  <span>
      <a th:if="${currentPage < totalPages}" th:href="@{'/owners/?page=' + ${currentPage + 1}}" title="Next"
         class="fa fa-step-forward"></a>
      <span th:unless="${currentPage < totalPages}" title="Next" class="fa fa-step-forward"></span>
    </span>
  <span>
      <a th:if="${currentPage < totalPages}" th:href="@{'/owners/?page=' + ${totalPages}}" title="Last"
         class="fa fa-fast-forward"></a>
      <span th:unless="${currentPage < totalPages}" title="Last" class="fa fa-step-forward"></span>
    </span>
</div>
```
<figcaption>Listing owners in a paged table with Thymeleaf</figcation>

In Vaadin Flow, you define and configure the data grid in Java. The Grid component is automatically paged. 

```java
ownersGrid = new Grid<>();
ownersGrid.addColumn(new ComponentRenderer<>(owner -> 
	new RouterLink(
				owner.getFirstName() + " " + owner.getLastName(), // Link caption
				OwnerDetailsView.class, // Destination page
				new RouteParameters("ownerId", // Parameters
						owner.getId().toString()))))
		.setHeader(getTranslation("name"));
ownersGrid.addColumn(Owner::getAddress).setHeader(getTranslation("address"));
ownersGrid.addColumn(Owner::getCity).setHeader(getTranslation("city"));
ownersGrid.addColumn(Owner::getTelephone).setHeader(getTranslation(("telephone")));
ownersGrid.addColumn(owner -> owner.getPets().stream().map(Pet::toString)
		.collect(Collectors.joining(", ")))
		.setHeader(getTranslation("pets"));
```

The resulting Vaadin app is a single-page web application that runs in all modern browsers and does not require any plugins. 

## Run Vaadin Flow PetClinic locally

Try out the Vaadin Fusion on your own computer with the following commands (make sure you have Java 8+ and Maven installed):

```
git clone https://github.com/spring-petclinic/spring-petclinic-vaadin-flow
cd spring-petclinic-vaadin-flow
mvn spring-boot:run
```
You can now access the app on localhost:8080. The frontend code is in the `org.springframework.samples.petclinic.ui` package.