Andy McKibbin
Andy McKibbin

Reputation: 814

Thymeleaf template not processed by Spring

I'm trying to use Thymeleaf with Spring, using spring-boot. When I access a URL mapped to a controller that I expect to result in a Thymeleaf template being used, I just get a blank page in the browser.

I'm using autoconfiguration, with the following results (snipped from http://localhost:8080/autoconfig):

{
    "positiveMatches":{
        "ThymeleafAutoConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"@ConditionalOnClass classes found: org.thymeleaf.spring4.SpringTemplateEngine"
            }
        ],
        "ThymeleafAutoConfiguration.DefaultTemplateResolverConfiguration":[
            {
                "condition":"OnBeanCondition",
                "message":"@ConditionalOnMissingBean (names: defaultTemplateResolver; SearchStrategy: all) found no beans"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafDefaultConfiguration":[
            {
                "condition":"OnBeanCondition",
                "message":"@ConditionalOnMissingBean (types: org.thymeleaf.spring4.SpringTemplateEngine; SearchStrategy: all) found no beans"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafViewResolverConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"@ConditionalOnClass classes found: javax.servlet.Servlet"
            },
            {
                "condition":"OnWebApplicationCondition",
                "message":"found web application StandardServletEnvironment"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafViewResolverConfiguration#thymeleafViewResolver":[
            {
                "condition":"OnBeanCondition",
                "message":"@ConditionalOnMissingBean (names: thymeleafViewResolver; SearchStrategy: all) found no beans"
            },
            {
                "condition":"OnPropertyCondition",
                "message":"matched"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafWebLayoutConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"@ConditionalOnClass classes found: nz.net.ultraq.thymeleaf.LayoutDialect"
            }
        ],
    },
    "negativeMatches":{
        "ThymeleafAutoConfiguration.DataAttributeDialectConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"required @ConditionalOnClass classes not found: com.github.mxab.thymeleaf.extras.dataattribute.dialect.DataAttributeDialect"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafConditionalCommentsDialectConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"required @ConditionalOnClass classes not found: org.thymeleaf.extras.conditionalcomments.dialect.ConditionalCommentsDialect"
            }
        ],
        "ThymeleafAutoConfiguration.ThymeleafSecurityDialectConfiguration":[
            {
                "condition":"OnClassCondition",
                "message":"required @ConditionalOnClass classes not found: org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect"
            }
        ],
    }
}

I have absolutely no application configuration - everything at this stages depends on autoconfig.

My controller (only one so far) looks like this:

@RestController
@RequestMapping("/")
public class MainController {

    @RequestMapping(value = "main.html", method = RequestMethod.GET)
    public void index( Model model ) {
        model.addAttribute( "name", "Gorgonzola" );
    }
}

I have the following project layout:

src/
    main/
        java/
            attendance/
                MainController.java
        resources/
            templates/
                main.html

and templates/main.html contains:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:th="http://www.thymeleaf.org">

    <head>
        <title>Attendance</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    </head>

    <body>

        <p th:text="'Hello, ' + ${name} + '!'" />

    </body>

</html>

http://localhost:8080/mappings includes this:

"{[/main.html],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}": {
    "bean": "requestMappingHandlerMapping",
    "method": "public void attendance.MainController.index(org.springframework.ui.Model)"
},

I'm using the Gradle spring-boot plugin and running the application with the Gradle bootRun task.

I tried adding --debug to the bootRun parameters, and when I point my browser at http://localhost:8080/main.html, I get this:

2015-02-19 17:36:14.754 DEBUG 9168 --- [tp1565713391-18] o.s.b.a.e.mvc.EndpointHandlerMapping     : Looking up handler method for path /main.html
2015-02-19 17:36:14.756 DEBUG 9168 --- [tp1565713391-18] o.s.b.a.e.mvc.EndpointHandlerMapping     : Did not find handler method for [/main.html]

... so I suspect I'm missing one simple parameter. But what is it?

Can anyone see why my template is not being processed? Or suggest further diagnostic steps I can take?

Upvotes: 0

Views: 2257

Answers (2)

Andy McKibbin
Andy McKibbin

Reputation: 814

I managed to make this work. There were a few things wrong with it:

  • the @RestController annotation, which I'd added accidentally, should of course read @Controller
  • the DOCTYPE specification in main.html appears to be incompatible with the Thymeleaf dialect that's autoconfigured - it needs to just read <!DOCTYPE html>
  • I took hrrgttnchml's suggestion about returning the bare name of the template to use

So now it works. Sorry for answering my own question, but after several hours of fiddling with this there's a certain amount of closure.

Upvotes: 1

daniel.eichten
daniel.eichten

Reputation: 2555

Your Controller doesn't define which view to render. Per default the ViewResolver doesn't do that based on your RequestMapping. Just make your main method to return a String and add a return statement like return "main"; and everything should work.

Upvotes: 0

Related Questions