This Spring Boot Thymeleaf Ajax Example will shows you how to create a simple web application based on Spring Boot and Thymeleaf template + jQuery.ajax. Here, we are using jQuery.ajax function to send a request to Spring REST API and return a JSON response.
Other interesting posts you may like
Let’s begin:
Spring Boot Thymeleaf Ajax Example
Project Structure
In the Spring Boot Thymeleaf Ajax Example, our project is with this structure below
Maven Dependency
In the Spring Boot Thymeleaf Ajax Example, we are using A normal Spring Boot Thymeleaf starter dependency and some webjars resources.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javabycode</groupId> <artifactId>spring-boot-thymeleaf-ajax-example</artifactId> <packaging>jar</packaging> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath></relativePath> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- hot swapping, enable live reload --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>2.2.4</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.3.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
Create Spring Controller
We create a simple controller to display login page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.javabycode.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class MyController { private final Logger logger = LoggerFactory.getLogger(MyController.class); @GetMapping("/") public String index() { return "login"; } } |
Create Spring REST API
We create a REST API which accepts a submit request on the login form and return the result using ResponseEntity format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
package com.javabycode.controller; import com.javabycode.model.AjaxResponseBody; import com.javabycode.model.LoginForm; import com.javabycode.model.User; import com.javabycode.services.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @RestController public class MyRestController { UserService userService; @Autowired public void setUserService(UserService userService) { this.userService = userService; } @PostMapping("/api/login") public ResponseEntity<?> getSearchResultViaAjax(@Valid @RequestBody LoginForm loginForm, Errors errors) { AjaxResponseBody result = new AjaxResponseBody(); //If error, just return a 400 bad request, along with the error message if (errors.hasErrors()) { result.setMsg(errors.getAllErrors() .stream().map(x -> x.getDefaultMessage()) .collect(Collectors.joining(","))); return ResponseEntity.badRequest().body(result); } List<User> users = userService.login(loginForm); if (users.isEmpty()) { result.setMsg("no user found!"); } else { result.setMsg("success"); } result.setResult(users); return ResponseEntity.ok(result); } } |
Create some POJO
AjaxResponseBody POJO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
package com.javabycode.model; import java.util.List; public class AjaxResponseBody { String msg; List<User> result; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public List<User> getResult() { return result; } public void setResult(List<User> result) { this.result = result; } } |
User POJO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
package com.javabycode.model; public class User { String username; String password; String email; public User(String username, String password, String email) { this.username = username; this.password = password; this.email = email; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + '}'; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } } |
Form Validation
The form data will be validated by using JSR 303 validation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.javabycode.model; import org.hibernate.validator.constraints.NotBlank; public class LoginForm { @NotBlank(message = "username can't empty!") String username; @NotBlank(message = "password can't empty!") String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } } |
A service to validate a valid user
Our service will find user information from database or other resources
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package com.javabycode.services; import com.javabycode.model.User; import com.javabycode.model.LoginForm; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @Service public class UserService { private List<User> users; public List<User> login(LoginForm loginForm) { //do stuffs //dump user data User user = new User(loginForm.getUsername(), loginForm.getPassword(), "email@javabycode.com"); return new ArrayList<User>(Arrays.asList(user)); } } |
Spring Boot Web Application
Don’t forget to create the Spring Boot Web Application and sometimes it is call to be Spring Boot Starter
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.javabycode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootWebApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SpringBootWebApplication.class, args); } } |
HTML form using Thymeleaf template
In our Spring Boot Thymeleaf Ajax Example, we create a simple HTML form uing the Thymeleaf template and bootstrap css.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Spring Boot Thymeleaf AJAX example</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css"/> </head> <body> <div class="container" style="min-height: 500px"> <div class="starter-template"> <h1>Spring Boot Thymeleaf AJAX Example</h1> <form class="form-horizontal" id="login-form"> <div class="form-group form-group-lg"> <label class="col-sm-2 control-label">Username</label> <div class="col-sm-6"> <input type="text" class="form-control" id="username"/> </div> </div> <div class="form-group form-group-lg"> <label class="col-sm-2 control-label">Password</label> <div class="col-sm-6"> <input type="password" class="form-control" id="password"/> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-6"> <button type="submit" id="bth-login" class="btn btn-primary btn-lg">Login </button> </div> </div> </form> <div id="feedback"></div> </div> </div> <script type="text/javascript" src="webjars/jquery/2.2.4/jquery.min.js"></script> <script type="text/javascript" src="js/ajax_functions.js"></script> </body> </html> |
Ajax submit function
Gets HTML form then convert form data into JSON format via JSON.stringify, and send POST request using the jQuery.ajax function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
$(document).ready(function () { $("#login-form").submit(function (event) { //stop submit the form event. Do this manually using ajax post function event.preventDefault(); var loginForm = {} loginForm["username"] = $("#username").val(); loginForm["password"] = $("#password").val(); $("#btn-login").prop("disabled", true); $.ajax({ type: "POST", contentType: "application/json", url: "/api/login", data: JSON.stringify(loginForm), dataType: 'json', cache: false, timeout: 600000, success: function (data) { var json = "<h4>Ajax Response</h4><pre>" + JSON.stringify(data, null, 4) + "</pre>"; $('#feedback').html(json); console.log("SUCCESS : ", data); $("#btn-login").prop("disabled", false); }, error: function (e) { var json = "<h4>Ajax Response Error</h4><pre>" + e.responseText + "</pre>"; $('#feedback').html(json); console.log("ERROR : ", e); $("#btn-login").prop("disabled", false); } }); }); }); |
Demo Spring application
Go to the project directory and run the command line
1 |
mvn spring-boot:run |
Then the successful screen should be like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.5.2.RELEASE) 2017-04-07 23:06:32 INFO c.j.SpringBootWebApplication - Starting SpringBootWebA pplication 2017-04-07 23:06:32 DEBUG c.j.SpringBootWebApplication - Running with Spring Boo t v1.5.2.RELEASE, Spring v4.3.7.RELEASE 2017-04-07 23:06:32 INFO c.j.SpringBootWebApplication - No active profile set, falling back to default profiles: default 2017-04-07 23:06:58 INFO c.j.SpringBootWebApplication - Started SpringBootWebAp plication in 27.88 seconds (JVM running for 30.686) |
Now, let’s access the address http://localhost:8080/ and the login form looks like below
Submit the login form without data, the validation error should display
Enter username/password on the form
Then click submit button, the user information is displayed when the login is successful
That’s all on the Spring Boot Thymeleaf Ajax Example. You may be interested in Spring Boot Thymeleaf Hello World Example.
References
Spring IO – Building a RESTful Web Service
MDN – JSON.stringify()
Download complete source code, click link below
spring-boot-thymeleaf-ajax-example.zip (1039 downloads)