Question

Using Spring Boot and Thymeleaf to build an application, everything works fine in IntelliJ, but when I build via gradle clean build then I get errors.

Here is my directory structure:

🗁 src
├─── 🗁 generated
├─── 🗁 main
│   ├─── 🗁 java
│   ├─── 🗁 resources
│   │   └─── 🗁 assets
│   │       ├─── 🗁 css
│   │       ├─── 🗁 js
│   │       └─── 🗁 templates
│   │           └─── *.html
│   └─── 🗁 webapp
└─── 🗁 test
    ├─── 🗁 groovy
    │   └─── unit & integration tests here
    ├─── 🗁 resources
    └─── 🗁 unit

Here is my gradle file:

apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'jacoco'
apply plugin: 'war'
apply plugin: 'maven'

def generatedResources = "$buildDir/generated-resources/main"

configurations {
    querydslapt
}

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.0.RC4")
    }
}


repositories {
    mavenCentral()
    maven {url "http://repo.spring.io/libs-snapshot"}
    maven {url 'http://repo.spring.io/milestone' }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:1.0.0.RELEASE")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:1.0.1.RELEASE")
    compile("org.springframework.boot:spring-boot:1.0.1.RELEASE")
    compile("org.springframework:spring-orm:4.0.0.RC1")
    compile("org.hibernate:hibernate-entitymanager:4.2.1.Final")
    compile("com.h2database:h2:1.3.172")
    compile("joda-time:joda-time:2.3")
    compile("org.thymeleaf:thymeleaf-spring4")
    compile("org.codehaus.groovy.modules.http-builder:http-builder:0.7.1")
    compile('org.codehaus.groovy:groovy-all:2.2.1')
    compile('org.jadira.usertype:usertype.jodatime:2.0.1')
    compile('com.mysema.maven:maven-apt-plugin:1.0.2')
    compile('com.mysema.querydsl:querydsl-apt:3.3.2')
    compile('com.mysema.querydsl:querydsl-jpa:3.3.2')

    querydslapt "com.mysema.querydsl:querydsl-apt:3.3.2"
    testCompile('org.spockframework:spock-core:0.7-groovy-2.0') {
        exclude group: 'org.codehaus.groovy', module: 'groovy-all'
    }
    testCompile('org.codehaus.groovy.modules.http-builder:http-builder:0.7+')
    testCompile("junit:junit")
}

jacocoTestReport {
    group = "Reporting"
    description = "Generate Jacoco coverage reports after running tests."
}

sourceSets {

    generated {
        java {
            srcDirs = ['src/main/generated']
        }
    }
    main {
        //let's register an output folder on the main SourceSet:
    output.dir(generated, builtBy: 'generateQueryDSL')
        java {
            srcDirs = []
        }
        groovy {
            srcDirs = ['src/main/groovy', 'src/main/java']
        }
        resources {
            srcDirs = ['src/main/resources']
        }

        output.resourcesDir = "build/classes/main"
    }

    test {
        java {
            srcDirs = []
        }
        groovy {
            srcDirs = ['src/test/groovy', 'src/test/java']
        }
        resources {
            srcDirs = ['src/test/resources']
        }

        output.resourcesDir = "build/classes/test"
    }
}


task generateQueryDSL(type: JavaCompile, group: 'build', description: 'Generates the QueryDSL query types') {
    source = sourceSets.main.java
    classpath = configurations.compile + configurations.querydslapt
    options.compilerArgs = [
            "-proc:only",
            "-processor", "com.mysema.query.apt.jpa.JPAAnnotationProcessor"
    ]
    destinationDir = sourceSets.generated.java.srcDirs.iterator().next()
}

compileJava {
    dependsOn generateQueryDSL
    source generateQueryDSL.destinationDir
}

compileGeneratedJava {
    dependsOn generateQueryDSL
    options.warnings = false
    classpath += sourceSets.main.runtimeClasspath
}

clean {
    delete sourceSets.generated.java.srcDirs
}

idea {
    module {
        sourceDirs += file('src/main/generated')
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}

I have my UI configured as below:

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
    ...

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController( "/home" ).setViewName( "index" );
        ...
    } 

    // removed to try and find the css/js/images
    // @Override
    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //     registry.addResourceHandler( "/resources/**" ).addResourceLocations( "/resources/" );
    // }      

    ...
}

Here is an example test:

@SpringApplicationConfiguration
class TreasuryStatusEvaluatorTest extends Specification {

    @Shared
    def ConfigurableApplicationContext context

    @Shared
    private StatusRepository statusRepository

    void setupSpec() {
        Future future = Executors.newSingleThreadExecutor().submit(
                new Callable() {
                    @Override
                    public ConfigurableApplicationContext call() throws Exception {
                        return (ConfigurableApplicationContext) SpringApplication.run(OFAC.class)
                    }
                })
        context = future.get(60, TimeUnit.SECONDS)
        treasuryStatusEvaluator = context.getBean(TreasuryStatusEvaluator.class)
        statusRepository = context.getBean(StatusRepository.class)
    }

    void cleanupSpec() {
        if (context != null) {
            context.close()
        }
    }
...
}

Here is a typical html page:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta name="description" content=""/>  

    <link href="/resources/static/css/bootstrap.css" rel="stylesheet"/>
    <link href="/resources/static/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="/resources/static/css/bootstrap-responsive.css" rel="stylesheet"/>
    <link href="/resources/static/css/bootstrap-responsive.min.css" rel="stylesheet"/>
    <link href="/resources/static/css/ofac.css" rel="stylesheet"/>
    <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"/>

    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
    <!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
</head>
<body>
<div id="wrap">
...

<script src="/resources/static/js/libs/jquery.min.js"></script>
<script src="/resources/static/js/libs/bootstrap/bootstrap.min.js"></script>
</body>
</html>

These tests run within IntelliJ or as an application all is well. But when I run the tests from the command line, I get errors such as:

Caused by: java.lang.IllegalStateException: Cannot find template location: class path resource [templates/] (please add some templates or check your Thymeleaf configuration)

I see that in spring-boot there is an issue with directory structure with thymeleaf: https://github.com/spring-projects/spring-boot/issues/424 and it would seem that a template directory is required. I am not using any templates, just html.

Update #1: I moved the html under src/main/resources/*

Update #2: I moved the css/js/libs to src/main/resources/static I tried having them under src/main/static but that didn't work either

Was it helpful?

Solution

There is a 1.0.1.RELEASE of Spring Boot now, so you should be using that (and it might just fix your problem). Normally, though, I wouldn't expect you would need Thymeleaf configuration as long as you put your templates in "classpath:/templates" (those html files are what Thymeleaf calls "templates"). You can specify the template location using spring.thymeleaf.prefix if you want them somewhere else (see docs here).

If you prefer to configure Thmyeleaf yourself completely then the you need to use the conventional bean name for the template resolver ("defaultTemplateResolver"), so that Boot knows what you are doing. Details are in the ThymeleafAutoConfiguration - some of the features there are explicitly called out in the docs, but this one appears not to be.

OTHER TIPS

If you are getting the same exception

Caused by: java.lang.IllegalStateException: Cannot find template location: class path resource [templates/] (please add some templates or check your Thymeleaf configuration)

but using SpringBoot 1.2.0-RELEASE, it could be simply that you need to create a directory src/main/resources/templates.

I upgraded from SpringBoot 1.1.9 to 1.2.0 and started getting this exception. Adding the directory fixed it.

Alternatively, if you get this exception and don't want to use thymeleaf, you can disable it by using...

config/application.yml

spring.groovy.template.check-template-location: false

More recent versions of spring, will actually tell you this in the stacktrace...

i.e.

Caused by: java.lang.IllegalStateException: Cannot find template location: classpath:/templates/ (please add some templates, check your Groovy configuration, or set spring.groovy.template.check-template-location=false)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top