In this tutorial, we will learn Spring Boot Thymeleaf example with login screens.
About Thymeleaf:
Thymeleaf is a server-side Java template engine for web and standalone applications. It provides a natural templating language for HTML,XHTML and XML, and other types of documents. Thymeleaf’s main goal is to provide a better way to create web applications by combining the power of Java with the simplicity of HTML.
Thymeleaf is designed to be a modern, flexible, and highly extensible template engine that works seamlessly with Spring Framework and other Java-based technologies. It offers features such as:
- A natural and easy-to-learn syntax that can be used directly in HTML and XML documents.
- A powerful expression language that can be used to access data and execute operations in Java code.
- Integration with Spring Framework and other Java-based technologies, including support for Spring Security and Spring WebFlux.
- Support for internationalization and localization.
- Easy customization and extension through the use of custom dialects and processors.
Overall, Thymeleaf is a powerful and versatile template engine that can be used to build modern and dynamic web applications with Java.
JSP vs Thymeleaf:
- JSP is not a template engine, It’s compiled to the servlet and then that servlet will be served as web content
- Thymeleaf is a template engine which takes the HTML file, parses it and then produces web content which is being served.
- JSP supports Expression Language,Thymeleaf supports Standard Dialect (The expression language) is much more powerful than JSP Expression Language
- JSP pages required to compile and run where as Thymeleaf is a natural templating engine and We can live-preview the changes without having to compile, build and run
Spring Thymeleaf Tutorial:
- Create Spring Thymeleat Project In STS: File -> New -> Spring Starer Project
- Spring Starter Project configuration
- Spring Starter Project Dependencies :
- Thymeleaf
- Spring web
- lombok for entities and pojos to avoid getters/setters
- Spring Data JPA to authenticate with database
Required Spring dependencies:
Please check below end of tutorial for complete pom.xml file
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Note: I am using bootstrap for look and feel, spring data jpa to authenticate user with DB. In the later part of the tutorial,we will see login with spring security Authentication manager, which is recommended approach.
Project Folder Structure:
ProductUiApplication.java
package com.javasavvy.tutorial; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ProductUiApplication { public static void main(String[] args) { SpringApplication.run(ProductUiApplication.class, args); } }
LoginController.java
package com.javasavvy.tutorial.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; 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.servlet.ModelAndView; import com.javasavvy.tutorial.dto.LoginRequest; import com.javasavvy.tutorial.service.UserService; @Controller public class LoginController { @Autowired private UserService userService; @GetMapping("/") public String index(Model model, HttpServletRequest request) { request.getParameterMap().forEach((k, v) -> { model.addAttribute(k, v.length > 0 ? v[0] : ""); }); return "index"; } @GetMapping("/dashboard") public String dashboard(Model model, HttpServletRequest request) { request.getParameterMap().forEach((k, v) -> { model.addAttribute(k, v.length > 0 ? v[0] : ""); }); return "dashboard"; } @PostMapping("/login") public ModelAndView login(LoginRequest request) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("dashboard"); modelAndView.addObject("name", "[email protected]"); return modelAndView; } }
LoginRequest.java
if you are facing issues with lombok then install lombok plugin into STS/eclipse:
package com.javasavvy.tutorial.dto; import lombok.Data; @Data public class LoginRequest { private String email; private String password; }
User.java
package com.javasavvy.tutorial.entity; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.Data; import lombok.NoArgsConstructor; @Table(name="user") @Entity @Data @NoArgsConstructor public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="user_id") private long userId; @Column(name="email") private String email; @Column(name="password") private String password; @Column(name="created_date") private Date createdDate; }
UserRepository.java
package com.javasavvy.tutorial.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import com.javasavvy.tutorial.entity.User; @Repository public interface UserRepository extends JpaRepository<User, Long> { }
UserService.java
package com.javasavvy.tutorial.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.javasavvy.tutorial.repository.UserRepository; @Service public class UserService { @Autowired public UserRepository userRepository; }
application.yaml
spring: datasource: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/productdb username: postgres password: root hikari: connection-timeout: 30000 maximum-pool-size: 100 minimum-idle: 20 jpa: properties: hibernate: dialect: org.hibernate.dialect.PostgreSQLDialect thymeleaf: prefix: classpath:/templates/ suffix: .html
index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <link rel="shortcut icon" type="image/x-icon" class="favicon" href="/assets/images/favicon.ico"> <title>Login</title> <link th:href="@{/assets/bootstrap/bootstrap.min.css}" rel="stylesheet" /> <link th:href="@{/assets/styles.css}" rel="stylesheet" /> <script type="text/javascript" th:src="@{/assets/bootstrap/bootstrap.min.js}"></script> <script type="text/javascript" th:src="@{/assets/script.js}"></script> </head> <body> <div id="app-root"> <div class="content-wrapper"> <main class="pb-5"> <div class="center-form-wrapper"> <div class="logo"> <span>Login</span> </div> <div class="center-form-card"> <p class="mt-4 form-info">Please enter your credentials.</p> <form action="/login" method="POST"> <div class="form-floating mb-3"> <input type="email" class="form-control" id="email" placeholder="Email" required> <label for="email">Email</label> </div> <div class="form-floating mb-3"> <input type="password" class="form-control" id="password" placeholder="Password" required> <label for="password">Password</label> </div> <div class="form-group mb-3"> <button type="submit" class="btn btn-primary btn-block">Login</button> </div> <a href="#" th:href="@{/forgotPassword}">Forgot your password?</a> </form> </div> </div> </main> <footer class="">© 2023 Javasavvy, Inc. All rights reserved.</footer> </div> </div> </body> </html>
Dashboard.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <link rel="shortcut icon" type="image/x-icon" class="favicon" href="/assets/images/favicon.ico"> <title>Dashboard</title> <link th:href="@{/assets/bootstrap/bootstrap.min.css}" rel="stylesheet" /> <link th:href="@{/assets/styles.css}" rel="stylesheet" /> <script type="text/javascript" th:src="@{/assets/bootstrap/bootstrap.min.js}"></script> <script type="text/javascript" th:src="@{/assets/script.js}"></script> </head> <body> <div id="app-root"> <div class="content-wrapper"> <main class="pb-5"> <span th:text="${name}"></span> </main> <footer class="">© 2023 Javasavvy, Inc. All rights reserved.</footer> </div> </div> </body> </html>
POM.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.10</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.javasavvy.tutorial</groupId> <artifactId>product-ui</artifactId> <version>1.0.0</version> <name>product-ui</name> <description>Spring Boot Thymeleaf tutorial</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> --> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>