Spring Boot 之 Thymeleaf 篇
在Spring boot中,官方默认采用的是Thymeleaf模块引擎,通过org.springframework.boot.autoconfigure.thymeleaf包对Thymeleaf进行了自动配置。
通过Thymeleaf2Configuration类对集成所需要的Bean进行自动配置,包括templateResolver、templateViewResolver 和templateEngine 的配置。
通过ThymeleafProperties来配置Thymeleaf,在application.properties中以 spring.thymeleaf开头来配置,通过查看ThymeleafProperties的主要源码,可以看出如何设置属性及默认配置:
/* * Copyright 2012-2017 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 * * http://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.autoconfigure.thymeleaf; import java.nio.charset.Charset; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.MimeType; /** * Properties for Thymeleaf. * * @author Stephane Nicoll * @since 1.2.0 */ @ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html"); public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; /** * 在渲染之前检查模板是否存在(Thymeleaf 3+)。 */ private boolean checkTemplate = true; /** * 检查模板位置是否存在。 */ private boolean checkTemplateLocation = true; /** * Spring boot 默认模板路径,默认在classpath:/templates/目录下 */ private String prefix = DEFAULT_PREFIX; /** * 后缀设置,默认为html. */ private String suffix = DEFAULT_SUFFIX; /** * 模板模式设置,默认为html5 */ private String mode = "HTML5"; /** * 模板的编码设置,默认UTF-8 */ private Charset encoding = DEFAULT_ENCODING; /** * 模板的媒体类型设置,默认为text/html */ private MimeType contentType = DEFAULT_CONTENT_TYPE; /** * 是否开启模板缓存,默认是开启的,开发时建议关闭 */ 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; /** * Comma-separated list of view names that can be resolved. */ private String[] viewNames; /** * Comma-separated list of view names that should be excluded from resolution. */ private String[] excludedViewNames; /** * Enable MVC Thymeleaf view resolution. */ private boolean enabled = true; 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 MimeType getContentType() { return this.contentType; } public void setContentType(MimeType contentType) { this.contentType = contentType; } 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; } }
以上关于ThymeleafProperties类的中文注释,为个人根据代码理解及其原代码英文注释而来。
在spring boot中整合Thymeleaf需要加入对Thymeleaf的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
创建一个HelloController 类,通过spring mvc 返回页面,来通过Thymeleaf渲染一个页面。
import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @RequestMapping(value = "/hello") public String hello(ModelMap map){ // 加入一个属性,用来在模板中读取 map.addAttribute("host", "http://www.baikeyang.com"); // return模板文件的名称,对应src/main/resources/templates/index.html return "index"; } }
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head lang="en"> <meta charset="UTF-8" > <title></title> </head> <body> <h1 th:text="${host}">Hello World</h1> <br/> </body> </html>
直接打开html页面展现Hello World,但是启动程序后,访问http://localhost:8080/hello,则是展示Controller中host的值:http://www.baikeyang.com,做到了不破坏HTML自身内容的数据逻辑分离。
#Thymeleaf配置 #Thymeleaf模板模式 spring.thymeleaf.mode = HTML5 #Thymeleaf 编码 spring.thymeleaf.encoding = UTF-8 #模板缓存(热部署静态文件) spring.thymeleaf.cache = false #spring.thymeleaf.prefix=classpath:/templates/:指定Thymeleaf的页面文件放置的位置(也就是页面文件的前缀),这里的classpath:/templates/指的目录就是src/resources/templates,所以需要创建templates这个目录(默认是没有这个目录的) spring.thymeleaf.prefix = classpath:/templates/ #检查模板位置是否存在 spring.thymeleaf.check-template-location = true #指定页面文件的后缀,这里配置所有页面文件都是.html的文件 spring.thymeleaf.suffix = .html #内容类型 spring.thymeleaf.content-type = text/html
启动项目,直接访问,会有一个异常抛出:
org.xml.sax.SAXParseException: 元素类型 "meta" 必须由匹配的结束标记 "</meta>" 终止。
spring.thymeleaf.mode的默认值是HTML5,其实是一个很严格的检查,对.html的内容要求很严格,比如<meta charset="UTF-8" />,如果少最后的标签封闭符号/,就会报错而转到错误页。也比如你在使用<br/>、<link>、<meta>这样的html标签,也会被thymeleaf认为不符合要求而抛出错误。
因为,我可以调整spring.thymeleaf.mode,改为LEGACYHTML5可以得到一个可能更友好亲切的格式要求。
需要注意的是,LEGACYHTML5需要搭配一个额外的库NekoHTML才可用。需要给项目添加NekoHTML的依赖:
<dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.22</version> </dependency>
最后重启项目就可以感受到不那么严格的thymeleaf了,访问正常。