#spring-boot #gradle #intellij-idea #mustache
Вопрос:
Я управляю своим проектом с помощью 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)
Это странно, потому что я запускаю приложение независимо, которое не является открытым проектом как многомодульный проект, просто откройте проект как отдельный проект, он работает хорошо.
Вот моя сборка.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()
}
application.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
And this is my project structure
├── 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
Если у вас, ребята, есть какие-либо идеи по решению этой проблемы, пожалуйста, дайте мне знать, спасибо
===== ОТРЕДАКТИРОВАНО 23/09/21 === = =
Я нашел кое-что необычное! Когда запускается проект с несколькими модулями, он проверяет наличие ресурса, в котором находятся шаблоны /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...
Я надеюсь, что это может быть ключом к разгадке проблемы
Комментарии:
1. Итак, где в проекте
templates
находится ваша папка? Вы добавляете его в путь к классу в Gradle, если он не находится в стандартном каталоге источника/ресурса?2.
It's weird because i run the application independently which is not open project as a multi module project just open project as a single project it works well.
Тогда возникает вопрос — какой файл Gradle используется для настройки этого проекта, когда он работает, а когда не работает. Сравните эти конфигурации, чтобы по возможности найти проблему.3. @Andrey Спасибо за ваш комментарий, я забыл указать расположение шаблонов дерева, поэтому добавил в виде текста. Они идут дальше
webapp/WEB-INF/templates/
. Также я добавил файл сборки, но я не думаю, что он выглядит по-другому4. Проверьте это baeldung.com/spring-thymeleaf-template-directory#change-default
5. @Andrey Спасибо за ваше предложение, но, к сожалению, оно не подходит для моего случая, и я приложил более подробную информацию о своей проблеме, надеюсь, это вам поможет