Create spring-boot-thymeleaf module
This commit is contained in:
committed by
Phillip Webb
parent
b2b849b30d
commit
843867c0f4
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.thymeleaf.autoconfigure;
|
||||
|
||||
import org.thymeleaf.ITemplateEngine;
|
||||
import org.thymeleaf.dialect.IDialect;
|
||||
import org.thymeleaf.spring6.ISpringTemplateEngine;
|
||||
import org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;
|
||||
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||
import org.thymeleaf.spring6.SpringWebFluxTemplateEngine;
|
||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configuration classes for Thymeleaf's {@link ITemplateEngine}. Imported by
|
||||
* {@link ThymeleafAutoConfiguration}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class TemplateEngineConfigurations {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class DefaultTemplateEngineConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ISpringTemplateEngine.class)
|
||||
SpringTemplateEngine templateEngine(ThymeleafProperties properties,
|
||||
ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {
|
||||
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||
engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler());
|
||||
engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes());
|
||||
templateResolvers.orderedStream().forEach(engine::addTemplateResolver);
|
||||
dialects.orderedStream().forEach(engine::addDialect);
|
||||
return engine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
@ConditionalOnBooleanProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
|
||||
static class ReactiveTemplateEngineConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ISpringWebFluxTemplateEngine.class)
|
||||
SpringWebFluxTemplateEngine templateEngine(ThymeleafProperties properties,
|
||||
ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {
|
||||
SpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine();
|
||||
engine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler());
|
||||
engine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes());
|
||||
templateResolvers.orderedStream().forEach(engine::addTemplateResolver);
|
||||
dialects.orderedStream().forEach(engine::addDialect);
|
||||
return engine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.thymeleaf.autoconfigure;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import com.github.mxab.thymeleaf.extras.dataattribute.dialect.DataAttributeDialect;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;
|
||||
import org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;
|
||||
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
|
||||
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
|
||||
import org.thymeleaf.spring6.view.reactive.ThymeleafReactiveViewResolver;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.boot.autoconfigure.template.TemplateLocation;
|
||||
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.boot.thymeleaf.autoconfigure.ThymeleafProperties.Reactive;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.web.server.csrf.CsrfToken;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
|
||||
import org.springframework.web.servlet.view.AbstractCachingViewResolver;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Thymeleaf.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @author Eddú Meléndez
|
||||
* @author Daniel Fernández
|
||||
* @author Kazuki Shimizu
|
||||
* @author Artsiom Yudovin
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(afterName = { "org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration",
|
||||
"org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration" })
|
||||
@EnableConfigurationProperties(ThymeleafProperties.class)
|
||||
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
|
||||
@Import({ TemplateEngineConfigurations.ReactiveTemplateEngineConfiguration.class,
|
||||
TemplateEngineConfigurations.DefaultTemplateEngineConfiguration.class })
|
||||
public class ThymeleafAutoConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnMissingBean(name = "defaultTemplateResolver")
|
||||
static class DefaultTemplateResolverConfiguration {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DefaultTemplateResolverConfiguration.class);
|
||||
|
||||
private final ThymeleafProperties properties;
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
DefaultTemplateResolverConfiguration(ThymeleafProperties properties, ApplicationContext applicationContext) {
|
||||
this.properties = properties;
|
||||
this.applicationContext = applicationContext;
|
||||
checkTemplateLocationExists();
|
||||
}
|
||||
|
||||
private void checkTemplateLocationExists() {
|
||||
boolean checkTemplateLocation = this.properties.isCheckTemplateLocation();
|
||||
if (checkTemplateLocation) {
|
||||
TemplateLocation location = new TemplateLocation(this.properties.getPrefix());
|
||||
if (!location.exists(this.applicationContext)) {
|
||||
logger.warn("Cannot find template location: " + location
|
||||
+ " (please add some templates, check your Thymeleaf configuration, or set spring.thymeleaf."
|
||||
+ "check-template-location=false)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
SpringResourceTemplateResolver defaultTemplateResolver() {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setApplicationContext(this.applicationContext);
|
||||
resolver.setPrefix(this.properties.getPrefix());
|
||||
resolver.setSuffix(this.properties.getSuffix());
|
||||
resolver.setTemplateMode(this.properties.getMode());
|
||||
if (this.properties.getEncoding() != null) {
|
||||
resolver.setCharacterEncoding(this.properties.getEncoding().name());
|
||||
}
|
||||
resolver.setCacheable(this.properties.isCache());
|
||||
Integer order = this.properties.getTemplateResolverOrder();
|
||||
if (order != null) {
|
||||
resolver.setOrder(order);
|
||||
}
|
||||
resolver.setCheckExistence(this.properties.isCheckTemplate());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnBooleanProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
|
||||
static class ThymeleafWebMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnEnabledResourceChain
|
||||
@ConditionalOnMissingFilterBean
|
||||
FilterRegistrationBean<ResourceUrlEncodingFilter> resourceUrlEncodingFilter() {
|
||||
FilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean<>(
|
||||
new ResourceUrlEncodingFilter());
|
||||
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(AbstractCachingViewResolver.class)
|
||||
static class ThymeleafViewResolverConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
|
||||
ThymeleafViewResolver thymeleafViewResolver(ThymeleafProperties properties,
|
||||
SpringTemplateEngine templateEngine) {
|
||||
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
|
||||
resolver.setTemplateEngine(templateEngine);
|
||||
resolver.setCharacterEncoding(properties.getEncoding().name());
|
||||
resolver.setContentType(
|
||||
appendCharset(properties.getServlet().getContentType(), resolver.getCharacterEncoding()));
|
||||
resolver.setProducePartialOutputWhileProcessing(
|
||||
properties.getServlet().isProducePartialOutputWhileProcessing());
|
||||
resolver.setExcludedViewNames(properties.getExcludedViewNames());
|
||||
resolver.setViewNames(properties.getViewNames());
|
||||
// This resolver acts as a fallback resolver (e.g. like a
|
||||
// InternalResourceViewResolver) so it needs to have low precedence
|
||||
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
|
||||
resolver.setCache(properties.isCache());
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private String appendCharset(MimeType type, String charset) {
|
||||
if (type.getCharset() != null) {
|
||||
return type.toString();
|
||||
}
|
||||
LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
|
||||
parameters.put("charset", charset);
|
||||
parameters.putAll(type.getParameters());
|
||||
return new MimeType(type, parameters).toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
@ConditionalOnBooleanProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
|
||||
static class ThymeleafWebFluxConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "thymeleafReactiveViewResolver")
|
||||
ThymeleafReactiveViewResolver thymeleafViewResolver(ISpringWebFluxTemplateEngine templateEngine,
|
||||
ThymeleafProperties properties) {
|
||||
ThymeleafReactiveViewResolver resolver = new ThymeleafReactiveViewResolver();
|
||||
resolver.setTemplateEngine(templateEngine);
|
||||
mapProperties(properties, resolver);
|
||||
mapReactiveProperties(properties.getReactive(), resolver);
|
||||
// This resolver acts as a fallback resolver (e.g. like a
|
||||
// InternalResourceViewResolver) so it needs to have low precedence
|
||||
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
private void mapProperties(ThymeleafProperties properties, ThymeleafReactiveViewResolver resolver) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
map.from(properties::getEncoding).to(resolver::setDefaultCharset);
|
||||
resolver.setExcludedViewNames(properties.getExcludedViewNames());
|
||||
resolver.setViewNames(properties.getViewNames());
|
||||
}
|
||||
|
||||
private void mapReactiveProperties(Reactive properties, ThymeleafReactiveViewResolver resolver) {
|
||||
PropertyMapper map = PropertyMapper.get();
|
||||
map.from(properties::getMediaTypes).whenNonNull().to(resolver::setSupportedMediaTypes);
|
||||
map.from(properties::getMaxChunkSize)
|
||||
.asInt(DataSize::toBytes)
|
||||
.when((size) -> size > 0)
|
||||
.to(resolver::setResponseMaxChunkSizeBytes);
|
||||
map.from(properties::getFullModeViewNames).to(resolver::setFullModeViewNames);
|
||||
map.from(properties::getChunkedModeViewNames).to(resolver::setChunkedModeViewNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(LayoutDialect.class)
|
||||
static class ThymeleafWebLayoutConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
LayoutDialect layoutDialect() {
|
||||
return new LayoutDialect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(DataAttributeDialect.class)
|
||||
static class DataAttributeDialectConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DataAttributeDialect dialect() {
|
||||
return new DataAttributeDialect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ SpringSecurityDialect.class, CsrfToken.class })
|
||||
static class ThymeleafSecurityDialectConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SpringSecurityDialect securityDialect() {
|
||||
return new SpringSecurityDialect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.thymeleaf.autoconfigure;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
/**
|
||||
* Properties for Thymeleaf.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @author Daniel Fernández
|
||||
* @author Kazuki Shimizu
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.thymeleaf")
|
||||
public class ThymeleafProperties {
|
||||
|
||||
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
|
||||
|
||||
public static final String DEFAULT_PREFIX = "classpath:/templates/";
|
||||
|
||||
public static final String DEFAULT_SUFFIX = ".html";
|
||||
|
||||
/**
|
||||
* Whether to check that the template exists before rendering it.
|
||||
*/
|
||||
private boolean checkTemplate = true;
|
||||
|
||||
/**
|
||||
* Whether to check that the templates location exists.
|
||||
*/
|
||||
private boolean checkTemplateLocation = true;
|
||||
|
||||
/**
|
||||
* Prefix that gets prepended to view names when building a URL.
|
||||
*/
|
||||
private String prefix = DEFAULT_PREFIX;
|
||||
|
||||
/**
|
||||
* Suffix that gets appended to view names when building a URL.
|
||||
*/
|
||||
private String suffix = DEFAULT_SUFFIX;
|
||||
|
||||
/**
|
||||
* Template mode to be applied to templates. See also Thymeleaf's TemplateMode enum.
|
||||
*/
|
||||
private String mode = "HTML";
|
||||
|
||||
/**
|
||||
* Template files encoding.
|
||||
*/
|
||||
private Charset encoding = DEFAULT_ENCODING;
|
||||
|
||||
/**
|
||||
* Whether to enable template caching.
|
||||
*/
|
||||
private boolean cache = true;
|
||||
|
||||
/**
|
||||
* Order of the template resolver in the chain. By default, the template resolver is
|
||||
* first in the chain. Order start at 1 and should only be set if you have defined
|
||||
* additional "TemplateResolver" beans.
|
||||
*/
|
||||
private Integer templateResolverOrder;
|
||||
|
||||
/**
|
||||
* List of view names (patterns allowed) that can be resolved.
|
||||
*/
|
||||
private String[] viewNames;
|
||||
|
||||
/**
|
||||
* List of view names (patterns allowed) that should be excluded from resolution.
|
||||
*/
|
||||
private String[] excludedViewNames;
|
||||
|
||||
/**
|
||||
* Enable the SpringEL compiler in SpringEL expressions.
|
||||
*/
|
||||
private boolean enableSpringElCompiler;
|
||||
|
||||
/**
|
||||
* Whether hidden form inputs acting as markers for checkboxes should be rendered
|
||||
* before the checkbox element itself.
|
||||
*/
|
||||
private boolean renderHiddenMarkersBeforeCheckboxes = false;
|
||||
|
||||
/**
|
||||
* Whether to enable Thymeleaf view resolution for Web frameworks.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
private final Servlet servlet = new Servlet();
|
||||
|
||||
private final Reactive reactive = new Reactive();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isCheckTemplate() {
|
||||
return this.checkTemplate;
|
||||
}
|
||||
|
||||
public void setCheckTemplate(boolean checkTemplate) {
|
||||
this.checkTemplate = checkTemplate;
|
||||
}
|
||||
|
||||
public boolean isCheckTemplateLocation() {
|
||||
return this.checkTemplateLocation;
|
||||
}
|
||||
|
||||
public void setCheckTemplateLocation(boolean checkTemplateLocation) {
|
||||
this.checkTemplateLocation = checkTemplateLocation;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public String getSuffix() {
|
||||
return this.suffix;
|
||||
}
|
||||
|
||||
public void setSuffix(String suffix) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Charset getEncoding() {
|
||||
return this.encoding;
|
||||
}
|
||||
|
||||
public void setEncoding(Charset encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
public boolean isCache() {
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
public void setCache(boolean cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public Integer getTemplateResolverOrder() {
|
||||
return this.templateResolverOrder;
|
||||
}
|
||||
|
||||
public void setTemplateResolverOrder(Integer templateResolverOrder) {
|
||||
this.templateResolverOrder = templateResolverOrder;
|
||||
}
|
||||
|
||||
public String[] getExcludedViewNames() {
|
||||
return this.excludedViewNames;
|
||||
}
|
||||
|
||||
public void setExcludedViewNames(String[] excludedViewNames) {
|
||||
this.excludedViewNames = excludedViewNames;
|
||||
}
|
||||
|
||||
public String[] getViewNames() {
|
||||
return this.viewNames;
|
||||
}
|
||||
|
||||
public void setViewNames(String[] viewNames) {
|
||||
this.viewNames = viewNames;
|
||||
}
|
||||
|
||||
public boolean isEnableSpringElCompiler() {
|
||||
return this.enableSpringElCompiler;
|
||||
}
|
||||
|
||||
public void setEnableSpringElCompiler(boolean enableSpringElCompiler) {
|
||||
this.enableSpringElCompiler = enableSpringElCompiler;
|
||||
}
|
||||
|
||||
public boolean isRenderHiddenMarkersBeforeCheckboxes() {
|
||||
return this.renderHiddenMarkersBeforeCheckboxes;
|
||||
}
|
||||
|
||||
public void setRenderHiddenMarkersBeforeCheckboxes(boolean renderHiddenMarkersBeforeCheckboxes) {
|
||||
this.renderHiddenMarkersBeforeCheckboxes = renderHiddenMarkersBeforeCheckboxes;
|
||||
}
|
||||
|
||||
public Reactive getReactive() {
|
||||
return this.reactive;
|
||||
}
|
||||
|
||||
public Servlet getServlet() {
|
||||
return this.servlet;
|
||||
}
|
||||
|
||||
public static class Servlet {
|
||||
|
||||
/**
|
||||
* Content-Type value written to HTTP responses.
|
||||
*/
|
||||
private MimeType contentType = MimeType.valueOf("text/html");
|
||||
|
||||
/**
|
||||
* Whether Thymeleaf should start writing partial output as soon as possible or
|
||||
* buffer until template processing is finished.
|
||||
*/
|
||||
private boolean producePartialOutputWhileProcessing = true;
|
||||
|
||||
public MimeType getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
public void setContentType(MimeType contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public boolean isProducePartialOutputWhileProcessing() {
|
||||
return this.producePartialOutputWhileProcessing;
|
||||
}
|
||||
|
||||
public void setProducePartialOutputWhileProcessing(boolean producePartialOutputWhileProcessing) {
|
||||
this.producePartialOutputWhileProcessing = producePartialOutputWhileProcessing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Reactive {
|
||||
|
||||
/**
|
||||
* Maximum size of data buffers used for writing to the response. Templates will
|
||||
* execute in CHUNKED mode by default if this is set.
|
||||
*/
|
||||
private DataSize maxChunkSize = DataSize.ofBytes(0);
|
||||
|
||||
/**
|
||||
* Media types supported by the view technology.
|
||||
*/
|
||||
private List<MediaType> mediaTypes;
|
||||
|
||||
/**
|
||||
* Comma-separated list of view names (patterns allowed) that should be executed
|
||||
* in FULL mode even if a max chunk size is set.
|
||||
*/
|
||||
private String[] fullModeViewNames;
|
||||
|
||||
/**
|
||||
* Comma-separated list of view names (patterns allowed) that should be the only
|
||||
* ones executed in CHUNKED mode when a max chunk size is set.
|
||||
*/
|
||||
private String[] chunkedModeViewNames;
|
||||
|
||||
public List<MediaType> getMediaTypes() {
|
||||
return this.mediaTypes;
|
||||
}
|
||||
|
||||
public void setMediaTypes(List<MediaType> mediaTypes) {
|
||||
this.mediaTypes = mediaTypes;
|
||||
}
|
||||
|
||||
public DataSize getMaxChunkSize() {
|
||||
return this.maxChunkSize;
|
||||
}
|
||||
|
||||
public void setMaxChunkSize(DataSize maxChunkSize) {
|
||||
this.maxChunkSize = maxChunkSize;
|
||||
}
|
||||
|
||||
public String[] getFullModeViewNames() {
|
||||
return this.fullModeViewNames;
|
||||
}
|
||||
|
||||
public void setFullModeViewNames(String[] fullModeViewNames) {
|
||||
this.fullModeViewNames = fullModeViewNames;
|
||||
}
|
||||
|
||||
public String[] getChunkedModeViewNames() {
|
||||
return this.chunkedModeViewNames;
|
||||
}
|
||||
|
||||
public void setChunkedModeViewNames(String[] chunkedModeViewNames) {
|
||||
this.chunkedModeViewNames = chunkedModeViewNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.thymeleaf.autoconfigure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link TemplateAvailabilityProvider} that provides availability information for
|
||||
* Thymeleaf view templates.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Madhura Bhave
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class ThymeleafTemplateAvailabilityProvider implements TemplateAvailabilityProvider {
|
||||
|
||||
@Override
|
||||
public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,
|
||||
ResourceLoader resourceLoader) {
|
||||
if (ClassUtils.isPresent("org.thymeleaf.spring6.SpringTemplateEngine", classLoader)) {
|
||||
String prefix = environment.getProperty("spring.thymeleaf.prefix", ThymeleafProperties.DEFAULT_PREFIX);
|
||||
String suffix = environment.getProperty("spring.thymeleaf.suffix", ThymeleafProperties.DEFAULT_SUFFIX);
|
||||
return resourceLoader.getResource(prefix + view + suffix).exists();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Thymeleaf.
|
||||
*/
|
||||
package org.springframework.boot.thymeleaf.autoconfigure;
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"groups": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.thymeleaf.prefix",
|
||||
"defaultValue": "classpath:/templates/"
|
||||
},
|
||||
{
|
||||
"name": "spring.thymeleaf.reactive.media-types",
|
||||
"defaultValue": [
|
||||
"text/html",
|
||||
"application/xhtml+xml",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
"application/rss+xml",
|
||||
"application/atom+xml",
|
||||
"application/javascript",
|
||||
"application/ecmascript",
|
||||
"text/javascript",
|
||||
"text/ecmascript",
|
||||
"application/json",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/event-stream"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spring.thymeleaf.suffix",
|
||||
"defaultValue": ".html"
|
||||
}
|
||||
],
|
||||
"hints": [],
|
||||
"ignored": {
|
||||
"properties": [
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Template Availability Providers
|
||||
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
|
||||
org.springframework.boot.thymeleaf.autoconfigure.ThymeleafTemplateAvailabilityProvider
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration
|
||||
Reference in New Issue
Block a user