spring

Thymeleaf with Spring WebFlux

Spring WebFlux is a reactive programming framework for building web applications in the Spring ecosystem. It’s designed to handle asynchronous and non-blocking operations, making it suitable for building highly scalable and performant web applications. Thymeleaf, on the other hand, is a popular server-side templating engine for rendering HTML templates in Java applications.

1. Introduction

Spring WebFlux is a reactive programming framework within the broader Spring ecosystem for building asynchronous, non-blocking, and event-driven web applications. It was introduced in Spring Framework 5 to provide an alternative to the traditional Spring MVC framework for building web applications. Spring WebFlux is particularly well-suited for building highly scalable and responsive applications that can handle a large number of concurrent connections.

  • Reactive Programming Model: Spring WebFlux is built on the principles of reactive programming, which allows developers to handle asynchronous and event-driven operations using reactive streams. It uses Project Reactor, a reactive programming library, to provide the necessary building blocks for reactive applications.
  • Non-Blocking: Spring WebFlux is non-blocking, meaning it can handle a large number of concurrent requests without blocking threads. This is particularly useful for applications that require high concurrency and low-latency responses.
  • Annotation-Based Controllers: Spring WebFlux supports annotation-based controllers for defining endpoints and handling HTTP requests.
  • Functional Endpoints: In addition to annotation-based controllers, Spring WebFlux also allows you to define endpoints using a more practical and programmatic approach. This can be useful for building reactive APIs.
  • Router Functions: Router functions are a fundamental concept in Spring WebFlux for defining how incoming requests are routed to handlers. They provide a way to create custom routing logic, allowing for more flexibility in defining endpoints.
  • Support for Multiple Reactive Data Sources: Spring WebFlux is not limited to HTTP requests. It can also handle other types of data sources, such as WebSockets, server-sent events (SSE), and more. This makes it suitable for building real-time applications.
  • Reactive WebClient: Spring WebFlux includes a reactive WebClient that allows you to make asynchronous HTTP requests to external services. It integrates seamlessly with the reactive programming model.
  • Adaptive Threading: Spring WebFlux uses an adaptive threading model that automatically adjusts the number of threads based on the workload, making efficient use of system resources.
  • Backpressure Support: Reactive streams, used in Spring WebFlux, support backpressure, which allows consumers to signal producers about their ability to handle data. This helps prevent overwhelming the system with too much data.
  • Integration with Spring Ecosystem: Spring WebFlux can be integrated with other Spring projects and libraries, such as Spring Security, Spring Data, and Spring Cloud, making it suitable for building comprehensive microservices architectures.
  • Annotated Controllers for MVC: While Spring WebFlux is primarily designed for reactive applications, it also includes the option to use annotated controllers in a traditional Spring MVC style, allowing you to mix both programming models in a single application.
  • Functional Error Handling: Spring WebFlux provides functional error handling mechanisms that allow you to define how errors are handled at different levels of the application, including global error handling.
  • Reactive Security: Spring Security can be integrated with Spring WebFlux to provide security features for reactive applications, including authentication and authorization.

2. Significance of Thymeleaf

Thymeleaf is a popular server-side templating engine for web applications in the Java ecosystem. Thymeleaf is significant because it provides an efficient and developer-friendly way to create server-side rendered web applications in Java and it holds importance for several reasons:

  • Server-Side Rendering (SSR): Thymeleaf is primarily used for server-side rendering, which means that HTML templates are processed on the server before being sent to the client’s browser. This approach is valuable for search engine optimization (SEO) and initial page load performance because it ensures that the HTML content is readily available to search engines and doesn’t rely on client-side JavaScript for rendering.
  • Integration with Spring Framework: Thymeleaf integrates seamlessly with the Spring Framework, making it a preferred choice for building web applications with Spring. It supports both Spring MVC (Model-View-Controller) and Spring WebFlux, allowing developers to choose the appropriate programming model for their application’s needs.
  • Natural and Human-Readable Templates: Thymeleaf templates are designed to be easy to read and write. They resemble standard HTML, and the Thymeleaf-specific attributes and syntax are intuitive. This makes it accessible to developers, including those who are new to Thymeleaf.
  • Rich Templating Features: Thymeleaf provides a wide range of features for templating, including expressions, conditional rendering, iteration, attribute manipulation, and more. These features allow developers to create dynamic and data-driven web pages with ease.
  • Internationalization and Localization: Thymeleaf includes built-in support for internationalization (i18n) and localization (l10n). It allows you to create templates that can be easily adapted to different languages and regions, making it suitable for building global applications.
  • Wide Adoption and Active Community: Thymeleaf has gained widespread adoption in the Java community and has an active and supportive user base. This means that you can find ample documentation, tutorials, and community-contributed extensions and libraries to enhance your Thymeleaf projects.
  • Extensibility: Thymeleaf is extensible, allowing developers to create custom dialects or processors to meet specific project requirements. This extensibility ensures that you can adapt Thymeleaf to your application’s unique needs.
  • Cross-Platform Compatibility: Thymeleaf can be used in various Java-based web frameworks and environments, including Spring Boot, Java EE, and standalone applications. This flexibility makes it a versatile choice for web development in Java.
  • No Dependency on JavaScript: Unlike client-side rendering frameworks, Thymeleaf doesn’t rely on JavaScript to render content. This can simplify development and ensure that your application remains functional even when JavaScript is disabled in the user’s browser.

3. Developing a Spring Webflux application

Let’s delve into some practical exercises. To initiate Thymeleaf in Spring Webflux, you can proceed with the following steps. Please note that we have skipped database connectivity for the simplicity of this tutorial and focus on the main aspects i.e. Spring Webflux and Thymeleaf. You’re free to update the Entity and Repository layer as per your needs.

In case anyone is interested in understanding the project structure:

Fig. 1: Project Structure

3.1 Incorporating Dependencies into pom.xml

Establish a fresh Spring Boot project using Spring Initialzr or leverage an existing one. Include the necessary dependencies in your project’s pom.xml file.

pom.xml

<dependencies>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>io.projectreactor</groupId>
	<artifactId>reactor-test</artifactId>
	<scope>test</scope>
</dependency>
</dependencies>

3.2 Configure Application Properties

Let us understand the application.properties.

  • server.port=9030 – Specifies the port on which the server should listen for incoming requests.
  • spring.application.name=spring-webflux-thymeleaf – Sets the name of the Spring Boot application, which can be used for various purposes, including application identification.
  • spring.thymeleaf.reactive.max-chunk-size=8192 – Configures the maximum chunk size for reactive Thymeleaf processing. This property can affect how Thymeleaf processes templates in a reactive way.

application.properties

# spring properties
server.port=9030
spring.application.name=spring-webflux-thymeleaf

# thymeleaf property
spring.thymeleaf.reactive.max-chunk-size=8192

3.3 Create Model Class

The following is an explanation of the Task model class in Java.

  • Fields:
    • id (type: int) – Represents the unique identifier for a task.
    • name (type: String) – Stores the name or description of the task.
    • completed (type: boolean) – Indicates whether the task is completed (true) or not (false).
  • Methods:
    • getId() – A getter method that retrieves the id of the task.
    • setId(int id) – A setter method that sets the id of the task.
    • getName() – A getter method that retrieves the name of the task.
    • setName(String name) – A setter method that sets the name of the task.
    • isCompleted() – A getter method that checks if the task is completed and returns true if it is.
    • setCompleted(boolean completed) – A setter method that sets the completion status of the task.
    • toString() – An overridden method that provides a string representation of the Task object, including its id, name, and completed fields.

Task.java

package com.example.demo.entity;

public class Task {

    private int id;
    private String name;
    private boolean completed;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }

    @Override
    public String toString() {
        return "Task{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", completed=" + completed +
                '}';
    }
}

3.4 Create Repository Interface

The following is an explanation of the TaskRepository class in Java.

  • Fields:
    • tasks (type: List<Task>) – A static list that stores instances of the Task class.
  • Static Initialization Block:
    • This block is executed when the class is loaded and initializes the tasks list with 50 Task objects. Each Task object is assigned an id, name, and completed value based on a loop.
  • Methods:
    • findAll()Flux is another core reactive type, representing a stream of zero or more values. It is used for asynchronous and potentially non-blocking operations that produce multiple results over time. This method returns a Flux<Task> (reactive stream) containing all tasks in the tasks list. It introduces a 2-second delay between emitting each element in the Flux.

TaskRepository.java

package com.example.demo.repository;

import com.example.demo.entity.Task;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@Repository
public class TaskRepository {

    private static final List<Task> tasks = new ArrayList<>();

    static {
        for (int i = 1; i <= 50; i++) {
            Task t = new Task();
            t.setId(i);
            t.setName("Task " + i);
            t.setCompleted(i % 2 == 0);
            tasks.add(t);
        }
    }

    public Flux<Task> findAll() {
        return Flux.fromIterable(tasks).delayElements(Duration.ofSeconds(2));
    }
}

3.5 Create Controller Class

Create a controller to handle HTTP requests and render Thymeleaf templates. You can use annotations like @Controller and @GetMapping to define your controller methods.

TaskController.java

package com.example.demo.controller;

import com.example.demo.repository.TaskRepository;
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.RequestMapping;
import org.thymeleaf.spring6.context.webflux.IReactiveDataDriverContextVariable;
import org.thymeleaf.spring6.context.webflux.ReactiveDataDriverContextVariable;

@Controller
@RequestMapping("/api")
public class TaskController {

    @Autowired
    private TaskRepository repository;

    // Endpoint - http://localhost:9030/api/tasks
    @GetMapping("/tasks")
    public String index(final Model model) {

        IReactiveDataDriverContextVariable variable =
                new ReactiveDataDriverContextVariable(repository.findAll(), 1);

        model.addAttribute("tasks", variable);

        return "index";
    }
}

3.6 Create Implementation Class

The provided Java class DemoApplication is a fundamental component in a Spring Boot application. It is the entry point for the application and is responsible for bootstrapping and launching the Spring Boot application.

DemoApplication.java

package com.example.demo;

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

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

4. Thymeleaf Template

Create Thymeleaf templates in the src/main/resources/templates directory. The template will retrieve the tasks attribute to display the data returned by the controller class.

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Spring webflux pagination</title>
    <link data-th-href="@{/css/task.css}" rel="stylesheet">
</head>
<body>
<div id="container">
    <h2>Spring Webflux Pagination Example</h2>
    <hr/>
    <table id="alltasks">
        <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Completed</th>
        </tr>
        </thead>
        <tbody>
        <tr data-th-each="task: ${tasks}">
            <td>[[${task.id}]]</td>
            <td>[[${task.name}]]</td>
            <td>[[${task.completed}]]</td>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

5. Run the Application

You can now run your Spring Boot application. When you access http://localhost:9030/api/tasks, the index.html template will be rendered and the data will keep streaming and will be displayed on the html page every 2 seconds in a reactive way.

Fig. 2: Demo Image

6. Conclusion

In conclusion, the fusion of Spring Boot, Thymeleaf, and WebFlux embodies a dynamic and versatile stack for crafting contemporary Java web applications. Each component fulfills a pivotal role in simplifying development, amplifying user experiences, and optimizing performance. Spring Boot emerges as an empowering framework, streamlining the creation of production-ready Java applications by eliminating much of the boilerplate code. It focuses developers on business logic rather than infrastructure intricacies, making it particularly suited for microservices and cloud-native applications.

Thymeleaf, a robust templating engine, seamlessly integrates with Spring Boot, excelling in server-side rendering for SEO optimization, efficient initial page loads, and graceful degradation. Its intuitive templates and rich feature sets empower developers, whether novices or experts. Meanwhile, Spring WebFlux, a reactive programming framework, offers an alternative to traditional Spring MVC, excelling in responsiveness, scalability, and non-blocking operations. It caters to real-time applications, IoT, and data streaming scenarios. Integration among these components is well-documented, allowing developers to harmoniously combine server-side rendering with reactivity. This stack’s flexibility supports traditional and reactive paradigms or hybrids, accommodating diverse application requirements.

Further enriched by vibrant communities and extensive ecosystems, Spring Boot, Thymeleaf, and Spring WebFlux deliver performance and scalability, ideal for demanding use cases. In summary, this combination empowers Java web developers to create responsive, high-performance, and maintainable applications while benefiting from the robust support and resources of the Spring community, making it a potent choice for various web development scenarios.

7. Download the Project

This was a tutorial to play with Spring Webflux and Thymeleaf. You can download the source code from the below link.

Download
You can download the full source code of this example here: Thymeleaf with Spring WebFlux

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button