首页 > 解决方案 > Spring Boot Gradle 多模块项目找不到模板位置

问题描述

我正在使用 Gradle 管理我的项目,并且根项目中有 3 个模块(Spring Boot)。

每个模块在自定义模板位置都有自己的模板,/WEB-INF/templates/我在每个模块上设置了这些属性application.yml

但是,当应用程序启动时出现警告日志

2021-09-16 22:53:39.153  WARN 17043 --- [  restartedMain] o.s.b.a.m.MustacheAutoConfiguration      : Cannot find template location: /WEB-INF/templates/ (please add some templates, check your Mustache configuration, or set spring.mustache.check-template-location=false)

这很奇怪,因为我独立运行应用程序,它不是作为多模块项目打开的项目,只是将项目作为单个项目打开,它运行良好。

这是我的 build.gradle

// root project
plugins {
    id 'org.springframework.boot' version '2.5.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}

subprojects {

    group = 'yes.youcan'
    version = '0.0.1-SNAPSHOT'

    apply plugin: 'java'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'org.springframework.boot'

    repositories {
        mavenCentral()
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    compileJava {
        sourceCompatibility = 1.8
    }

    test {
        useJUnitPlatform()
    }

    project(':child2') {
        apply plugin: 'war'
    }

    project(':child3') {
        apply plugin: 'war'
    }

    dependencyManagement {
        imports {
            mavenBom("org.springframework.boot:spring-boot-dependencies:2.5.4")
        }
    }
}

// child project 1
ext {
    keycloakVersion = '15.0.2'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation "org.springframework.boot:spring-boot-starter-log4j2"
    modules {
        module("org.springframework.boot:spring-boot-starter-logging") {
            replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
        }
    }
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-mustache'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.keycloak:keycloak-spring-boot-starter'

    compileOnly 'org.projectlombok:lombok'

    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'

    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.rest-assured:rest-assured'
}

dependencyManagement {
    imports {
        mavenBom "org.keycloak.bom:keycloak-adapter-bom:${keycloakVersion}"
    }
}

// child project 2
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation "org.springframework.boot:spring-boot-starter-log4j2"
    modules {
        module("org.springframework.boot:spring-boot-starter-logging") {
            replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
        }
    }
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-mustache'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    compileOnly 'org.projectlombok:lombok'
    compileOnly 'com.querydsl:querydsl-jpa'
    compileOnly 'com.querydsl:querydsl-core'

    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'

    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'javax.persistence:javax.persistence-api'
    annotationProcessor 'javax.annotation:javax.annotation-api'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"

    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

    testImplementation 'com.querydsl:querydsl-jpa'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.rest-assured:rest-assured'
}

def generated = 'src/main/generated'

sourceSets {
    main.java.srcDirs += [ generated ]
}

tasks.withType(JavaCompile) {
    options.annotationProcessorGeneratedSourcesDirectory(file(generated))
}

clean.doLast {
    file(generated).deleteDir()
}

// child project 3
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation "org.springframework.boot:spring-boot-starter-log4j2"
    modules {
        module("org.springframework.boot:spring-boot-starter-logging") {
            replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
        }
    }
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-mustache'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    compileOnly 'com.querydsl:querydsl-jpa'
    compileOnly 'com.querydsl:querydsl-core'
    compileOnly 'org.projectlombok:lombok'

    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'

    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'javax.persistence:javax.persistence-api'
    annotationProcessor 'javax.annotation:javax.annotation-api'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"

    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

    testImplementation 'com.querydsl:querydsl-jpa'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.rest-assured:rest-assured'
}

clean {
    delete file('src/main/generated')
}

这是应用程序独立运行时的配置

plugins {
    id 'org.springframework.boot' version '2.5.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id 'war'
}

group = 'yes.youcan
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-mustache'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-validation'

    compileOnly 'com.querydsl:querydsl-jpa'
    compileOnly 'com.querydsl:querydsl-core'
    compileOnly 'org.projectlombok:lombok'

    developmentOnly 'org.springframework.boot:spring-boot-devtools'

    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'

    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'javax.persistence:javax.persistence-api'
    annotationProcessor 'javax.annotation:javax.annotation-api'
    annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"

    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.rest-assured:rest-assured'
}

clean {
    delete file('src/main/generated')
}

test {
    useJUnitPlatform()
}

应用程序.yml

spring:
  profiles:
    active: local

  mustache:
    prefix: /WEB-INF/templates/
    suffix: .html

  data:
    web:
      pageable:
        default-page-size: 5

server:
  port: 8081

---

spring:
  config:
    activate:
      on-profile: local

  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
    username: sa
    password:

  h2:
    console:
      enabled: true
      path: /h2-console

  jpa:
    hibernate.ddl-auto: create-drop
    properties.hibernate.format_sql: true
    properties.hibernate.dialect: org.hibernate.dialect.H2Dialect
    defer-datasource-initialization: true

logging:
  level:
    org.hibernate.SQL: debug
    org.springframework.security: error

---

spring:
  config:
    activate:
      on-profile: dev

  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:testdb
    username: sa
    password:

  h2:
    console:
      enabled: true
      path: /h2-console

  jpa:
    hibernate.ddl-auto: create-drop
    properties.hibernate.format_sql: true
    properties.hibernate.dialect: org.hibernate.dialect.H2Dialect

logging.level.org.hibernate.SQL: debug
logging.level.org.springframework.security: error

这是我的项目结构

├── child1
│   ├── gradle
│   │   └── wrapper
│   └── src
│       └── main
│           ├── java
│           │   └── yes
│           │       └── youcan
│           ├── resources
│           └── webapp
│               ├── resources
│               │   └── css
│               └── WEB-INF
│                   └── templates
├── child2
│   ├── gradle
│   │   └── wrapper
│   └── src
│       └── main
│           ├── generated
│           │   └── yes
│           │       └── youcan
│           ├── java
│           │   └── yes
│           │       └── youcan
│           ├── resources
│           └── webapp
│               ├── resources
│               │   ├── css
│               │   ├── img
│               │   └── js
│               └── WEB-INF
│                   └── templates
└── child3
    ├── gradle
    │   └── wrapper
    └── src
        └── main
            ├── java
            │   └── yes
            │       └── youcan
            ├── resources
            └── webapp
                ├── resources
                │   ├── css
                │   ├── img
                │   └── js
                └── WEB-INF
                    └── templates

如果你们有任何解决这个问题的想法请告诉我谢谢

===== 21 年 9 月 23 日编辑 =====

我发现了一些不同之处!当多模块项目运行时,它会检查是否存在作为模板位置的资源,/WEB-INF/templates/如下TemplateLocation.java所示

public boolean exists(ResourcePatternResolver resolver) {
        Assert.notNull(resolver, "Resolver must not be null");
        if (resolver.getResource(this.path).exists()) {
            return true;
        }
        try {
            return anyExists(resolver);
        }
        catch (IOException ex) {
            return false;
        }
    }

我在此检查处理时检查了根文件路径,另一方面,当我在单个模块项目上执行相同的工作时resolver.getResource('/').getFile(),它返回了一些临时目录,它返回了实际的项目目录/AppData/.../tomcat-docbase...D:\Java\...

我希望它可以成为解决问题的线索

标签: spring-bootgradleintellij-ideamustache

解决方案


推荐阅读