1. Introduction
In this article, we are going to present Thymeleaf Single/Multi-Select components embedded in a Spring Boot application. For the base layout framework, we choose Bootstrap that allows creating responsive websites easily.
More information about how to configure Thymeleaf for Spring Boot and how to start working with forms, check below links:
Spring Boot with Thymeleaf
Thymeleaf Forms
2. Maven dependencies
The example application use several libraries:
The Maven pom.xml
file with all required dependencies looks like the following:
Copy
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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>
<artifactId>thymeleaf-bootstrap-select-option</artifactId>
<properties>
<bootstrap.version>4.0.0-2</bootstrap.version>
<webjars-locator.version>0.30</webjars-locator.version>
<lombok.version>1.18.2</lombok.version>
</properties>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>${webjars-locator.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Model, Controller and Application class
Spring web controller was defined to handle all GET and POST requests to the main application path. The base model object Order
contains an enum field Pizza
and an array of Dip
objects. The Order
object will be used as the main form of the command object.
The Order
class used in this example application have the following structure:
Copy
package com.frontbackend.thymeleaf.bootstrap.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@NoArgsConstructor
public class Order {
private Pizza pizza;
private Dip[] dips;
}
Pizza enum object looks like the following:
Copy
package com.frontbackend.thymeleaf.bootstrap.model;
public enum Pizza {
MARGHERITA,
PEPPERONI,
CAPRICCIOSA,
MUSHROOM,
MARINARA,
SEAFOOD,
HAWAIIAN,
VEGETARIANA,
MEXICAN
}
Dip enum object looks like the following:
Copy
package com.frontbackend.thymeleaf.bootstrap.model;
public enum Dip {
KETCHUP,
MAYONNAISE,
GARLIC
}
Web controller class have the following structure:
Copy
package com.frontbackend.thymeleaf.bootstrap.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.frontbackend.thymeleaf.bootstrap.model.Order;
@Controller
@RequestMapping({ "/", "/index" })
public class IndexController {
@GetMapping
public String main(Model model) {
model.addAttribute("order", new Order());
return "index";
}
@PostMapping
public String save(Order order, Model model) {
model.addAttribute("order", order);
return "saved";
}
}
The main method in Application
class starts the Spring Boot application server:
Copy
package com.frontbackend.thymeleaf.bootstrap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. Templates
We defined two Thymeleaf templates in the /resources/templates
directory:
index.html
- to present the main form with single and multi-select components,
saved.html
- where we are going to present selected from the previous page options.
The index.html
file will have the following structure:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Select Option</title>
<link th:rel="stylesheet" th:href="@{assets/bootstrap-select-1.13.9/dist/css/bootstrap-select.css}"/>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">Thymeleaf - Bootstrap Select Option</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-4 mt-5">
<form method="post" th:object="${order}">
<div class="form-group">
<label for="pizza">Choose pizza</label>
<select class="form-control selectpicker" th:field="*{pizza}" id="pizza">
<option value="">Nothing selected</option>
<option th:each="pizza : ${T(com.frontbackend.thymeleaf.bootstrap.model.Pizza).values()}"
th:value="${pizza}"
th:text="${pizza}">pizza
</option>
</select>
</div>
<div class="form-group">
<label for="dips">Select dips</label>
<select class="form-control selectpicker" th:field="*{dips}" id="dips" multiple>
<option th:each="dip : ${T(com.frontbackend.thymeleaf.bootstrap.model.Dip).values()}"
th:value="${dip}"
th:text="${dip}">dip
</option>
</select>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
</div>
</div>
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/popper.js/umd/popper.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
<script th:src="@{assets/bootstrap-select-1.13.9/dist/js/bootstrap-select.js}"></script>
</body>
</html>
We used special T expression to retrieve all enum values:
${T(com.frontbackend.thymeleaf.bootstrap.model.Pizza).values()}"
,
${T(com.frontbackend.thymeleaf.bootstrap.model.Dip).values()}"
.
To brings select elements into the 21st century we used bootstrap-select library.
The save.html
file will have the following structure:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Select Option</title>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">Thymeleaf - Bootstrap Select Option</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="mt-5">Pizza: <strong th:text="${order.pizza}"></strong></div>
<div>Dips: <strong th:text="${#strings.listJoin(order.dips, ',')}"></strong></div>
<a th:href="@{/}" class="btn btn-primary mt-5">Go back</a>
</div>
</body>
</html>
5. The output
Started application is available under http://locahost:8080
URL address, and presents the following functionality:
6. Conclusion
In this article, we presented how to use Thymeleaf Single and Multi-Select components in a Spring Boot application using the Thymeleaf template engine.
The code used in this article is available under our GitHub repository .
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}