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