一 点睛
Spring Boot通过org.springframework.boot.autoconfigure.thymeleaf包对Thymeleaf进行自动配置,相关代码如下图所示:
通过ThymeleafAutoConfiguration类对集成所需要的Bean进行自动配置,包括TemplateResolver、TemplateEngine和thymeleafViewResolver的配置。
二 源码解读
1 ThymeleafProperties类
@ConfigurationProperties("spring.thymeleaf")
public class ThymeleafProperties {
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplateLocation = true;
/**
* 前缀设置,Spring Boot默认属性,放置在classpath:/templates/目录下
*/
private String prefix = DEFAULT_PREFIX;
/**
* 后缀设置,默认为html
*/
private String suffix = DEFAULT_SUFFIX;
/**
* 模板模式设置,默认为HTML 5
*/
private String mode = "HTML5";
/**
* 模板的编码设置,默认为UTF-8
*/
private String encoding = "UTF-8";
/**
* 模板的媒体类型设置,默认为text/html
*/
private String contentType = "text/html";
private boolean cache = true;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enabled = true;
}
2 ThymeleafAutoConfiguration源码解读
package org.springframework.boot.autoconfigure.thymeleaf;
......
@Configuration
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass(SpringTemplateEngine.class)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class ThymeleafAutoConfiguration {
@Configuration
@ConditionalOnMissingBean(name = "defaultTemplateResolver")
public static class DefaultTemplateResolverConfiguration {
@Autowired
private ThymeleafProperties properties;
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void checkTemplateLocationExists() {
boolean checkTemplateLocation = this.properties.isCheckTemplateLocation();
if (checkTemplateLocation) {
TemplateLocation location = new TemplateLocation(
this.properties.getPrefix());
Assert.state(location.exists(this.applicationContext),
"Cannot find template location: " + location
+ " (please add some templates or check "
+ "your Thymeleaf configuration)");
}
}
@Bean
public TemplateResolver defaultTemplateResolver() {
TemplateResolver resolver = new TemplateResolver();
resolver.setResourceResolver(thymeleafResourceResolver());
resolver.setPrefix(this.properties.getPrefix());
resolver.setSuffix(this.properties.getSuffix());
resolver.setTemplateMode(this.properties.getMode());
resolver.setCharacterEncoding(this.properties.getEncoding());
resolver.setCacheable(this.properties.isCache());
return resolver;
}
@Bean
public SpringResourceResourceResolver thymeleafResourceResolver() {
return new SpringResourceResourceResolver();
}
}
@Configuration
@ConditionalOnMissingBean(SpringTemplateEngine.class)
protected static class ThymeleafDefaultConfiguration {
@Autowired
private final Collection<ITemplateResolver> templateResolvers = Collections
.emptySet();
@Autowired(required = false)
private final Collection<IDialect> dialects = Collections.emptySet();
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
for (ITemplateResolver templateResolver : this.templateResolvers) {
//将templateResolver加入到SpringTemplateEngine
engine.addTemplateResolver(templateResolver);
}
for (IDialect dialect : this.dialects) {
engine.addDialect(dialect);
}
return engine;
}
}
@Configuration
@ConditionalOnClass(name = "nz.net.ultraq.thymeleaf.LayoutDialect")
protected static class ThymeleafWebLayoutConfiguration {
@Bean
public LayoutDialect layoutDialect() {
return new LayoutDialect();
}
}
@Configuration
@ConditionalOnClass(DataAttributeDialect.class)
protected static class DataAttributeDialectConfiguration {
@Bean
@ConditionalOnMissingBean
public DataAttributeDialect dialect() {
return new DataAttributeDialect();
}
}
@Configuration
@ConditionalOnClass({ SpringSecurityDialect.class })
protected static class ThymeleafSecurityDialectConfiguration {
@Bean
@ConditionalOnMissingBean
public SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
}
@Configuration
@ConditionalOnClass(ConditionalCommentsDialect.class)
protected static class ThymeleafConditionalCommentsDialectConfiguration {
@Bean
@ConditionalOnMissingBean
public ConditionalCommentsDialect conditionalCommentsDialect() {
return new ConditionalCommentsDialect();
}
}
@Configuration
@ConditionalOnClass({ Servlet.class })
@ConditionalOnWebApplication
protected static class ThymeleafViewResolverConfiguration {
//注入属性
@Autowired
private ThymeleafProperties properties;
@Autowired
private SpringTemplateEngine templateEngine;
@Bean
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
@ConditionalOnProperty(name = "spring.thymeleaf.enabled", matchIfMissing = true)
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine); //将SpringTemplateEngine加入到ThymeleafViewResolver
resolver.setCharacterEncoding(this.properties.getEncoding());
resolver.setContentType(appendCharset(this.properties.getContentType(),
resolver.getCharacterEncoding()));
resolver.setExcludedViewNames(this.properties.getExcludedViewNames());
resolver.setViewNames(this.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);
return resolver;
}
private String appendCharset(String type, String charset) {
if (type.contains("charset=")) {
return type;
}
return type + ";charset=" + charset;
}
}
}