Mastering Thymeleaf Layouts Without Extensions in Spring MVC

Snippet of programming code in IDE
Published on

Mastering Thymeleaf Layouts Without Extensions in Spring MVC

Thymeleaf is a powerful Java templating engine that's widely used in Spring MVC applications. One of its most appreciated features is its ability to create dynamic and reusable layouts. While many developers lean on layout dialects or extensions, it’s entirely possible to master Thymeleaf layouts without relying on any additional tools. This approach allows for greater control and understanding of your layouts. In this blog post, we will explore how to effectively manage Thymeleaf layouts in a Spring MVC environment.

Table of Contents

  1. Introduction to Thymeleaf
  2. Setting Up a Spring MVC Project
  3. Creating Base Layouts with Thymeleaf
  4. Implementing Content Blocks
  5. Styling Your Layouts
  6. Best Practices
  7. Conclusion

A Brief Overview to Thymeleaf

Thymeleaf serves as a modern server-side Java template engine that is designed to be used in web applications. It emphasizes ease of use and elegance, allowing developers to write HTML with embedded template logic. When paired with Spring MVC, it becomes an extremely potent tool for rendering web pages.

Unlike JSPs, Thymeleaf makes it easy to create reusable templates with neat and clean markup. If you're keen on making your code modular, leveraging Thymeleaf's layout capabilities is the way to go.

Setting Up a Spring MVC Project

Before delving into layouts, we need to set up a basic Spring MVC project. If you already have one, you can skip this section. Below is a basic Maven project structure you can use:

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>thymeleaf-layouts</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <properties>
        <java.version>1.8</java.version>
        <spring.version>5.3.9</spring.version>
        <thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>${thymeleaf.version}</version>
        </dependency>
        <!-- Add other dependencies as needed -->
    </dependencies>
</project>

This configuration sets the stage for our Thymeleaf project.

Application Configuration

Next, we need to configure Spring MVC and Thymeleaf in your WebMvcConfig class:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolversRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode("HTML");
        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        return templateEngine;
    }

    @Bean
    public ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }
}

This establishes the necessary beans for Thymeleaf to function properly within your Spring MVC application.

Creating Base Layouts with Thymeleaf

A solid layout strategy involves creating a base layout from which other views can inherit. Here's a simple example of a base layout:

<!-- base.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:text="${pageTitle} + ' | My Site'">My Site</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/styles.css}"/>
</head>
<body>
    <header>
        <h1>Welcome to My Site</h1>
    </header>
    <div th:replace="${content}"></div>
    <footer>
        <p>Copyright &copy; 2023 My Site</p>
    </footer>
</body>
</html>

Explanation:

  • In this layout, the <title> tag dynamically renders the page title using the pageTitle variable.
  • The header and footer remain consistent across pages, ensuring a unified look.

Inheriting the Base Layout

Now, you can create another HTML file that inherits from this base layout:

<!-- home.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <title th:with="pageTitle='Home'">My Site</title>
</head>
<body>
    <div layout:fragment="content">
        <h2>Home Page</h2>
        <p>This is a simple home page.</p>
    </div>
</body>
</html>

Explanation:

  • The content is defined with the layout:fragment attribute, allowing this section to be replaced in the base layout.
  • Notice how the title changes based on the page using the th:with directive.

Implementing Content Blocks

If you want to create flexible and dynamic layouts, implementing content blocks is essential. You can further optimize your layout mechanism by using fragments:

Define the Fragment

Update your base layout to include an additional fragment for body content:

<!-- base.html -->
<body>
    <header>
        <h1>Welcome to My Site</h1>
    </header>
    <div th:replace="${content}"></div>
    <div layout:fragment="bodyContent" th:insert="~{fragmentName :: content}"></div>
    <footer>
        <p>Copyright &copy; 2023 My Site</p>
    </footer>
</body>

Utilizing the Fragment

In your home.html, you can specify and insert this fragment:

<!-- home.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title th:with="pageTitle='Home'">My Site</title>
</head>
<body>
    <div layout:fragment="content">
        <h2>Home Page</h2>
        <p>This is a simple home page.</p>
    </div>
</body>
</html>

Styling Your Layouts

Don't forget that your layouts need proper styling. Create a simple CSS file:

/* styles.css */
body {
    font-family: Arial, sans-serif;
}

header, footer {
    background-color: #f8f8f8;
    padding: 10px;
    text-align: center;
}

Link this CSS file in your base layout to style all pages uniformly.

Best Practices

  1. Keep Your Layouts Consistent: Always use base layouts and fragments to avoid code duplication.
  2. Use Meaningful Variable Names: When passing variables to your views, ensure they are descriptive to improve readability and maintainability.
  3. Avoid Logic in Templates: Keep your HTML and Thymeleaf expressions clean. Move business logic to your controllers.

Lessons Learned

Mastering Thymeleaf layouts in Spring MVC does not necessitate external extensions. By utilizing the built-in capabilities of Thymeleaf, you can effectively create structured and dynamic page layouts. This ensures your code remains clean and maintains a high degree of reusability.

As you build more complex applications, you'll appreciate the control you gain by managing layouts directly in Thymeleaf. For further enhancements, consider exploring Thymeleaf documentation here.

With practice and these techniques, you're well on your way to getting the most out of Thymeleaf in your Spring MVC projects. Happy coding!