Skip to content
Advertisement

SpringMVC with Bootstrap and Thymeleaf pages decoration

I am working in: “SpringMVC 5”, with “Twitter Bootstrap 4” html pages, and “Thymeleaf 3” templating, in IntelliJ EAP (latest version) and Tomcat9, Maven

The structure of my project:

src/main/java (WebConfig.java/Controlers/Beans)
src/main/resources (*.properties)
src/main/webapp/WEB-INF/views/layout/template.html
src/main/webapp/WEB-INF/views/fragments/menubar.html
src/main/webapp/WEB-INF/views/home.html (my page)

I am using these tutorials: https://www.baeldung.com/spring-thymeleaf-fragments https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#template-layout

I have my page (home.html). I have my template (template.html). According to the 2nd tutorial:

  • I inserted the “menubar” into the “template” (this insert must work, because I inserted the menubar directly to the “home.html” and it was inserted successfuly)
  • Question that I cannot solve from what they say into the 2nd tutorial: How I “decorate” my “home.html” according the “template.html”. I mean, how I use the template to decorate according it all my pages? I used the following in the “home.html” but it is not working:
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
        layout:decorate="~{layout/template}"

My files are:

“home.html”

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<!-- These in the html-tag are not working
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/template}"
-->
<body>

<th:block th:fragment="page_content"> <!-- IntelliJ says I cannot recognise the th:block -->
    <h2>Home page</h2>
    <p>Hello home page</p>
</th:block>

</body></html>

“menubar.html”

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<body>

<nav class="navbar navbar-expand-lg navbar-light bg-light" th:fragment="menubar">
    <div class="container-fluid">
        <!-- bla-bla -->
    </div>
</nav>

</body></html>

“template.html”

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <!-- Stylesheets (Bootstrap and mine) here -->
    <title>Template Title</title>
</head>
<body>

<div th:replace="fragments/menubar.html :: menubar"></div>

<!-- Page Content -->
<section class="page_content">
    <div layout:fragment="page_content"></div>
</section>

<!-- Javascript scripts (Bootstrap and mine) here -->

</body></html>

“WebConfig.java”

@Configuration
@ComponentScan(basePackages = {"packages"})
@EnableWebMvc
public class WebConfig {
/*
I have a seperate controler that GETs my "home.html" successfuly
*/
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".html");
        viewResolver.setExposeContextBeansAsAttributes(true);
        return viewResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        //templateEngine.addDialect(new LayoutDialect()); // This is not working at all
        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
        return templateEngine;
    }

    @Bean
    public SpringResourceTemplateResolver thymeleafTemplateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setPrefix("/WEB-INF/views/layout/");
        templateResolver.setSuffix(".html");
        return templateResolver;
    }

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        return viewResolver;
    }
}

In my pom (some of it):

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>3.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-spring-environment-dialect</artifactId>
    <version>1.0.1</version>
</dependency>

Please some one help. Thanks in advance

Answer

Hey finally I found solution:

Step 1

I put the page and the layout in the same folder:

src/main/webapp/WEB-INF/views/fragments/menubar.html
src/main/webapp/WEB-INF/views/template.html
src/main/webapp/WEB-INF/views/home.html (my page)

Step 2

In “home.html” I added the “layout:decorate”

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
        xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
        layout:decorate="~{template}">
...

In “template.html” I changed the “layout:fragment”

<div th:replace="fragments/menubar.html :: menubar"></div>

<!-- Page Content -->
<section layout:fragment="page_content">
    <p>Template content</p>
</section>

In the “WebConfig.java” I deleted the “viewResolver() method” and I changed the others like following:

@Configuration
@ComponentScan(basePackages = {"packages"})
@EnableWebMvc
public class WebConfig {
    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.addDialect(new LayoutDialect()); // I added it again. Very important
        templateEngine.setTemplateResolver(thymeleafTemplateResolver());
        return templateEngine;
    }

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

    @Bean
    public ThymeleafViewResolver thymeleafViewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        return viewResolver;
    }
}

But… A problem remains. I cannot keep my pages and my layout in different folders. If I do it with the previous structure and put: layout:decorate=”~{layout/template}” the page is displayed as a blank page.

Any solution and idea from you it would be perfect for me. A part of the solution is found though.

=========== Update: ===========

Solution in the last part is found. I had a mistake in the “template.html”. I should put it as: “layout/fragments/menubar.html :: menubar” with the structure:

src/main/webapp/WEB-INF/views/layout/template.html
src/main/webapp/WEB-INF/views/fragments/menubar.html
src/main/webapp/WEB-INF/views/home.html (my page)

And the code will be:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <!-- Stylesheets (Bootstrap and mine) here -->
    <title>Template Title</title>
</head>
<body>
 
<div th:replace="layout/fragments/menubar.html :: menubar"></div>
 
<!-- Page Content -->
<section class="page_content">
    <div layout:fragment="page_content"></div>
</section>
 
<!-- Javascript scripts (Bootstrap and mine) here -->
 
</body></html>

I will put it as a solution, in some hours when the system will let me.

Advertisement