Spring Boot + Bootstrap + Thymeleaf Input Email

May 18, 2020 No comments Spring Boot Bootstrap Thymeleaf Input Email

Spring Boot + Bootstrap + Thymeleaf Input Email

1. Introduction

In this article, we are going to present the Thymeleaf Input Email component that checks the correctness of the provided email address on the browser level. The component comes with many built-in features. We can use the pattern attribute to set a regular expression the input's contents must match in order to be valid, or multiple parameter to allow many comma-separated e-mail addresses to be entered.

Follow below links to find more useful informations about Thymeleaf and Thymeleaf Forms:
Thymeleaf Posts
Building forms in Thymeleaf

2. Dependencies

2.1. Maven dependencies

To present how the Input Email component works with Thymeleaf we used a simple Spring Boot application created as a Maven project with the following dependencies:

2.2. Front-End libraries
  • bootstrap - a frontend framework for creating responsive websites.

Project Maven pom.xml file has the following structure:

<?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-input-email</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>
        <font-awesome.version>5.11.2</font-awesome.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.webjars</groupId>
            <artifactId>font-awesome</artifactId>
            <version>${font-awesome.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 Main Application class

The model layer contains one class Form with the following structure:

package com.frontbackend.thymeleaf.bootstrap.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
public class Form {

    private String email;
}

GET and POST requests on the root context are handled by a simple Spring Web Controller IndexController with the following structure:

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.Form;

@Controller
@RequestMapping({ "/", "/index" })
public class IndexController {

    @GetMapping
    public String main(Model model) {
        model.addAttribute("form", new Form());
        return "index";
    }

    @PostMapping
    public String save(Form form, Model model) {
        model.addAttribute("form", form);
        return "saved";
    }
}

The Application is the Java class with the main method that starts the Spring Boot application server:

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

The presentation layer contains two Thymeleaf templates:

  • index.html - a view that presents the input email component,
  • saved.html - the result view that presents provided email address.

The index.html template has the following structure:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Bootstrap Input Email</title>

    <link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
    <link th:rel="stylesheet" th:href="@{webjars/font-awesome/5.11.2/css/all.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 Input Email</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">
    <form method="post" th:object="${form}">
        <div class="form-group row">
            <div class="col-md-4 mt-5">
                <label for="birthdate">Email address</label>
                <div class="input-group">
                    <input type="email" class="form-control" id="birthdate" autocomplete="off" th:field="*{email}"/>
                    <div class="input-group-append">
                        <span class="input-group-text"><i class="fas fa-at"></i></span>
                    </div>
                </div>
            </div>
        </div>

        <button class="btn btn-primary" type="submit">Submit form</button>
    </form>

</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>

</body>
</html>

To present the submitted values we used the saved.html template with the following structure:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Bootstrap Input Email</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 Input Email</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">
    <h2 class="mt-5">Email address: <strong th:text="${form.email}"></strong></h2>

    <a th:href="@{/}" class="btn btn-primary">Go back</a>
</div>

</body>
</html>

5. The output

The running application is available under http://locahost:8080 URL and presents the following functionality:

Thymeleaf bootstrap input email

6. Conclusion

In this article, we presented the Thymeleaf Input Email component in a simple Spring Boot application. Using the built-in component to enter an email address has many advantages. With this approach we are dependency-free. Input email components are supported by all browsers and come with many additional features.

As usual, the code used in this article is available under our GitHub repository.

{{ message }}

{{ 'Comments are closed.' | trans }}