thymeleaf 简介
官网:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
应用:thymeleaf是spring boot官方推荐使用的模版引擎,提供了对spring mvc的完美支持
****************
引入 jar 包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
****************
相关类与接口
ThymeleafAutoConfiguration:自动配置类
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({ThymeleafProperties.class}) //创建Thymeleaf配置属性实例
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
public class ThymeleafAutoConfiguration {
public ThymeleafAutoConfiguration() {
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({Java8TimeDialect.class})
static class ThymeleafJava8TimeDialect {
ThymeleafJava8TimeDialect() {
}
@Bean
@ConditionalOnMissingBean
Java8TimeDialect java8TimeDialect() {
return new Java8TimeDialect();
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({SpringSecurityDialect.class})
static class ThymeleafSecurityDialectConfiguration {
ThymeleafSecurityDialectConfiguration() {
}
@Bean
@ConditionalOnMissingBean
SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({DataAttributeDialect.class})
static class DataAttributeDialectConfiguration {
DataAttributeDialectConfiguration() {
}
@Bean
@ConditionalOnMissingBean
DataAttributeDialect dialect() {
return new DataAttributeDialect();
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({LayoutDialect.class})
static class ThymeleafWebLayoutConfiguration {
ThymeleafWebLayoutConfiguration() {
}
@Bean
@ConditionalOnMissingBean
LayoutDialect layoutDialect() {
return new LayoutDialect();
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.REACTIVE
)
@ConditionalOnProperty(
name = {"spring.thymeleaf.enabled"},
matchIfMissing = true
)
static class ThymeleafWebFluxConfiguration {
ThymeleafWebFluxConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"thymeleafReactiveViewResolver"}
)
ThymeleafReactiveViewResolver thymeleafViewResolver(ISpringWebFluxTemplateEngine templateEngine, ThymeleafProperties properties) {
//reactive 视图解析器
ThymeleafReactiveViewResolver resolver = new ThymeleafReactiveViewResolver();
resolver.setTemplateEngine(templateEngine);
this.mapProperties(properties, resolver);
this.mapReactiveProperties(properties.getReactive(), resolver);
resolver.setOrder(2147483642);
return resolver;
}
private void mapProperties(ThymeleafProperties properties, ThymeleafReactiveViewResolver resolver) {
PropertyMapper map = PropertyMapper.get();
properties.getClass();
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();
properties.getClass();
map.from(properties::getMediaTypes).whenNonNull().to(resolver::setSupportedMediaTypes);
properties.getClass();
map.from(properties::getMaxChunkSize).asInt(DataSize::toBytes).when((size) -> {
return size > 0;
}).to(resolver::setResponseMaxChunkSizeBytes);
properties.getClass();
map.from(properties::getFullModeViewNames).to(resolver::setFullModeViewNames);
properties.getClass();
map.from(properties::getChunkedModeViewNames).to(resolver::setChunkedModeViewNames);
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnWebApplication(
type = Type.REACTIVE
)
@ConditionalOnProperty(
name = {"spring.thymeleaf.enabled"},
matchIfMissing = true
)
static class ThymeleafReactiveConfiguration {
ThymeleafReactiveConfiguration() {
}
@Bean
@ConditionalOnMissingBean({ISpringWebFluxTemplateEngine.class})
SpringWebFluxTemplateEngine templateEngine(ThymeleafProperties properties, ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {
//reactive 模版引擎
SpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine();
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.SERVLET
)
@ConditionalOnProperty(
name = {"spring.thymeleaf.enabled"},
matchIfMissing = true
)
static class ThymeleafWebMvcConfiguration {
ThymeleafWebMvcConfiguration() {
}
@Bean
@ConditionalOnEnabledResourceChain
@ConditionalOnMissingFilterBean({ResourceUrlEncodingFilter.class})
FilterRegistrationBean<ResourceUrlEncodingFilter> resourceUrlEncodingFilter() {
FilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean(new ResourceUrlEncodingFilter(), new ServletRegistrationBean[0]);
registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ERROR});
return registration;
}
@Configuration(
proxyBeanMethods = false
)
static class ThymeleafViewResolverConfiguration {
ThymeleafViewResolverConfiguration() {
}
@Bean
@ConditionalOnMissingBean(
name = {"thymeleafViewResolver"}
)
ThymeleafViewResolver thymeleafViewResolver(ThymeleafProperties properties, SpringTemplateEngine templateEngine) {
//web 视图解析器
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine);
resolver.setCharacterEncoding(properties.getEncoding().name());
resolver.setContentType(this.appendCharset(properties.getServlet().getContentType(), resolver.getCharacterEncoding()));
resolver.setProducePartialOutputWhileProcessing(properties.getServlet().isProducePartialOutputWhileProcessing());
resolver.setExcludedViewNames(properties.getExcludedViewNames());
resolver.setViewNames(properties.getViewNames());
resolver.setOrder(2147483642);
resolver.setCache(properties.isCache());
return resolver;
}
private String appendCharset(MimeType type, String charset) {
if (type.getCharset() != null) {
return type.toString();
} else {
LinkedHashMap<String, String> parameters = new LinkedHashMap();
parameters.put("charset", charset);
parameters.putAll(type.getParameters());
return (new MimeType(type, parameters)).toString();
}
}
}
}
@Configuration(
proxyBeanMethods = false
)
protected static class ThymeleafDefaultConfiguration {
protected ThymeleafDefaultConfiguration() {
}
@Bean
@ConditionalOnMissingBean({ISpringTemplateEngine.class})
SpringTemplateEngine templateEngine(ThymeleafProperties properties, ObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {
//web 模版引擎
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
)
@ConditionalOnMissingBean(
name = {"defaultTemplateResolver"}
)
static class DefaultTemplateResolverConfiguration {
private static final Log logger = LogFactory.getLog(ThymeleafAutoConfiguration.DefaultTemplateResolverConfiguration.class);
private final ThymeleafProperties properties;
private final ApplicationContext applicationContext;
DefaultTemplateResolverConfiguration(ThymeleafProperties properties, ApplicationContext applicationContext) {
this.properties = properties;
this.applicationContext = applicationContext;
}
@PostConstruct
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 or check your Thymeleaf configuration)");
}
}
}
@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()); //模版模式,默认 html
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;
}
}
}
ThymeleafProperties
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enableSpringElCompiler;
private boolean renderHiddenMarkersBeforeCheckboxes;
private boolean enabled;
private final ThymeleafProperties.Servlet servlet;
private final ThymeleafProperties.Reactive reactive;
public ThymeleafProperties() {
this.encoding = DEFAULT_ENCODING;
this.cache = true;
this.renderHiddenMarkersBeforeCheckboxes = false;
this.enabled = true;
this.servlet = new ThymeleafProperties.Servlet();
this.reactive = new ThymeleafProperties.Reactive();
}