This tutorial will walk you through the steps of creating a Spring Boot FreeMarker Form Validation and Data Binding Example

FreeMarker is a Java-based template engine to generate text outputs such as HTML web pages and emails

Data model validation in Spring Boot can be achieved by using Jakarta Validation API which is included in the Spring Boot Validation Starter dependency

For handling form validation and data binding, Spring Boot provides form macros available when importing /spring.ftl into a FreeMarker template file

What you will build

An HTML form to receive user input data, and show error messages if the data is invalid when user hits submit button

Show the submitted data if all of it is valid

What you will need

  • JDK 1.8+

  • Maven 3+

  • Your favorite IDE

Project structure

Following is the final project structure with all the files we would create

├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── hellokoding
│       │           └── springboot
│       │               ├── FormController.java
│       │               ├── User.java
│       │               └── WebApplication.java
│       └── resources
│           ├── static
│           │   ├── css
│           │   │   └── main.css
│           │   └── js
│           │       └── main.js
│           ├── templates
│           │   └── form.ftlh
│           └── application.properties
└── pom.xml

pom.xml is the configuration file used by Maven to manage project dependencies and build process, it is usually placed at the project root directory

FormController.java is a web controller used for mapping user requests to FreeMarker view template files, and handling form validation and submission, would be created inside src/main/java

User.java is a custom data model used for defining user input form data and validation constraints, would be created inside src/main/java

FreeMarker view template files would be created inside src/main/resources/templates. We use the .ftlh file extension instead of ftl to enable the HTML auto-escaping since Spring Boot 2.2

CSS and JavaScript files would be created inside src/main/resources/static

application.properties is a configuration file used by Spring Boot, would be created inside src/main/resources

WebApplication.java is a launch file for Spring Boot to start the application, would be created inside src/main/java

Initialize a new Spring Boot application

Besides using IDE, we can create and init a new Spring Boot project by using Spring Initializr via web UI or command-line tools such as cURL, HTTPie, or Spring Boot CLI

The below is a cURL example with dependencies are web, freemarker, and validation

curl https://start.spring.io/starter.zip \  
    -d dependencies=web,freemarker,validation \
    -d javaVersion=1.8 \
    -d packageName=com.hellokoding.springboot \
    -d groupId=com.hellokoding.springboot \
    -d artifactId=hk-springboot-freemarker \
    -o hk-springboot-freemarker.zip

Unzip the hk-springboot-freemarker.zip file and import the sample project into your IDE

Project dependencies

For a Spring Boot FreeMarker web application, we will need the following dependencies on the pom.xml file

  • spring-boot-starter-web provides all the dependencies and auto-configuration we need to develop a web application in Spring Boot, including the Tomcat embedded servlet container

  • spring-boot-starter-freemarker provides the support for compiling FreeMarker template files

The library versions can be omitted as it is resolved by the parent pom provided by Spring Boot

<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>  
<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

We also need spring-boot-starter-validation for validating the custom data model

<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Define data model for the input form

Create User.java as a model class with 3 properties including firstName, lastName, and email corresponding to the text inputs on the form

[User.java]

package com.hellokoding.springboot;

import javax.validation.constraints.Email;  
import javax.validation.constraints.NotEmpty;

public class User {  
    @NotEmpty
    private String firstName;

    @NotEmpty
    private String lastName;

    @NotEmpty
    @Email
    private String email;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

@NotEmpty and @Email are validation annotations of the Jakarta Validation API which is included by default in the spring-boot-starter-validation dependency

Create Form Controller

Create FormController.java as a Spring Boot web controller

  • Define a POST API to handle form validation and submission

  • Define a GET API to serve the form input UI

  • Both APIs are available at /form URI

[FormController.java]

package com.hellokoding.springboot;

import org.springframework.stereotype.Controller;  
import org.springframework.ui.Model;  
import org.springframework.validation.BindingResult;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.PostMapping;

import javax.validation.Valid;

@Controller
public class FormController {  
    @GetMapping("/")
    public String index() {
        return "redirect:/form";
    }

    @GetMapping("/form")
    public String formGet(Model model) {
        model.addAttribute("user", new User());
        return "form";
    }

    @PostMapping("/form")
    public String formPost(@Valid User user, BindingResult bindingResult, Model model) {
        if (!bindingResult.hasErrors()) {
            model.addAttribute("noErrors", true);
        }
        model.addAttribute("user", user);
        return "form";
    }
}

@Valid is an annotation of Jakarta Validation API to trigger the data model validation

BindingResult is a Spring validation API to provide the validation results

Model is a Spring UI API to share the data to view template files

Create FreeMarker form view template file

Create a FreeMarker form view template file to show HTML input controls, receive user-submitted data, show validation errors, and submitted result to user

[form.ftlh]

<#import "/spring.ftl" as spring />

<!DOCTYPE html>  
<html lang="en">  
    <head>
        <meta charset="UTF-8">
        <title>Form Data Binding and Validation</title>
        <link href="/css/main.css" rel="stylesheet">
    </head>
    <body>
        <h2>Form Data Binding and Validation</h2>

        <#if user?? && noErrors??>
            Your submitted data<br>
            First name: ${user.firstName}<br>
            Last name: ${user.lastName}<br>
            Email: ${user.email}<br>
        <#else>
            <form action="/form" method="post">
                First name:<br>
                <@spring.formInput "user.firstName"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                Last name:<br>
                <@spring.formInput "user.lastName"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                Email:<br>
                <@spring.formInput "user.email"/>
                <@spring.showErrors "<br>"/>
                <br><br>
                <input type="submit" value="Submit">
            </form>
        </#if>

        <script src="/js/main.js"></script>
    </body>
</html>

In the above template file, we imported Spring Form Macros to provide form validation and data binding to the FreeMarker view template

<#import "/spring.ftl" as spring />
  • @spring.formInput will generate a 2 ways data binding HTML input text: pull value from and push value to the data model

  • @spring.showErrors will show validation error messages of the immediately preceding data binding property

We used FreeMarker interpolations ${...} to show data model value to user, and FreeMarker ifelse directives <#if>...<#else>...</#if> to dynamic generate conditional HTML ouput

Static files

Create 2 simple CSS and JavaScript files inside /src/main/resources/static

The main.css file is linked into FreeMarker view via <link href="/css/main.css" rel="stylesheet">

[main.css]

body * {  
  font-weight: 400;
}

form b {  
  color: red;
}

The main.js file is included into FreeMarker view via <script src="/js/main.js"></script>

[main.js]

(function(){
  console.log("Hello FreeMarker Form!");
})();

Application Configurations

Create application.properties file inside src/main/resources to configure Spring MVC view resolver via the spring.freemarker properties

[application.properties]

spring.freemarker.template-loader-path: classpath:/templates  
spring.freemarker.suffix: .ftlh

The spring.freemarker.template-loader-path property defines the path to FreeMarker template files, the spring.freemarker.suffix property defines the file extension we would like to use

Run and test

Create an Application class and use @SpringBootApplication annotation to launch the application

[WebApplication.java]

package com.hellokoding.springboot;

import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebApplication {  
    public static void main(String[] args) throws Exception {
        SpringApplication.run(WebApplication.class, args);
    }
}

Run the application by typing the following command on the terminal console at the project root directory

./mvnw clean spring-boot:run

You would see this text in the console

o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''

Access to http://localhost:8080/form on your web browser and start to explore the application

Conclusion

In this tutorial, we learned to build a Spring Boot FreeMarker form validation and data binding example. The source code is available on Github