Spring Boot 整合 Thymeleaf

控制器

@Controller
public class BackstageController {
 
	@RequestMapping("/home")
	String home(Model  model) {
		model.addAttribute("mesg", "hello word!");
		return "home";
	}
    ...
 

引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

thymeleaf 的一些配置

spring.thymeleaf.cache=false//开发环境,禁用缓存
spring.thymeleaf.prefix=classpath:/templates/ //模版路径
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html //后缀
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.mode=HTML5

建立 thymeleaf 模版文件

在类组建路径建立templates(上配置的)目录, 一般都约定在./resources/templates 在建个home.html文件
内容为:

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" >
<head>
    <meta content="text/html;charset=UTF-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1"/>
</head>
<body>
    <h1>hi this is home page</h1>
    <p th:text="${mesg}">message</p>
 
</body>
</html>

请注意命名空间xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"是必须的

测试

访问: http://127.0.0.1:8080/home
可以看到 <p th:text="${mesg}">message</p> 元素的 message, 被替换为 ${mesg}的值

thymeleaf的常用替换

  • 文本替换
    <p th:text="${collect.description}">description</p>

  • 样式替换
    th:style="'display:' + @{(${sitrue} ? 'none': 'inline-block')} + ''"

  • 属性替换
    <input th:value="${user.name}" />

  • href
    <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> />

其他大多数html都能被替换

foreach

th:each属性用于迭代循环, 语法: th:each=“obj,iterStat:${objList}“

<ol>
    <li>List循环: 
        <table border="1">
            <tr>
            <th>用户名</th>
            <th>邮箱</th>
            <th>管理员</th>
            <th>状态变量: index</th>
            <th>状态变量: count</th>
            <th>状态变量: size</th>
            <th>状态变量: current.userName</th>
            <th>状态变量: even</th>
            <th>状态变量: odd</th>
            <th>状态变量: first</th>
            <th>状态变量: last</th>
            </tr>
            <tr  th:each="user,userStat: ${list}">
            <td th:text="${user.userName}">Onions</td>
            <td th:text="${user.email}">test@test.com.cn</td>
            <td th:text="${user.isAdmin}">yes</td>
                <th th:text="${userStat.index}">状态变量: index</th>
            <th th:text="${userStat.count}">状态变量: count</th>
            <th th:text="${userStat.size}">状态变量: size</th>
            <th th:text="${userStat.current.userName}">状态变量: current</th>
            <th th:text="${userStat.even}">状态变量: even****</th>
            <th th:text="${userStat.odd}">状态变量: odd</th>
            <th th:text="${userStat.first}">状态变量: first</th>
            <th th:text="${userStat.last}">状态变量: last</th>
            </tr>
        </table>
    </li>
    <li>Map循环: 
        <div th:each="mapS:${map}">
        <div th:text="${mapS}"></div>
        </div>
    </li>
    <li>数组循环: 
        <div th:each="arrayS:${arrays}">
        <div th:text="${arrayS}"></div>
        </div>
    </li>
</ol>
 

字符串分割迭代

参考

<tbody id="portfolio" class="clear fix">
  <tr th:each="brickset: ${bricksets}" th:alt="${brickset.description}">
    <td>
      <div th:unless="${brickset.imageNames == null}">
        <div th:each="image,status: ${#strings.arraySplit(brickset.imageNames, '|')}">
          <a href="#" th:href="${imageBaseUrl + image}" th:remove="${image} == null ? tag" th:title="${brickset.brand.name}">
            <img src="#" th:src="${imageBaseUrl + image}" height="64" th:remove="${status.index} > 0 ? tag"/>
          </a>
        </div>
      </div>
    </td>
  </tr>
</tbody>
 

关于 thymeleaf 的各种使用可以参考: https://www.cnblogs.com/ityouknow/p/5833560.html

静态资源

  • 默认静态资源映射规则

Spring Boot 默认将 / 所有访问映射到以下目录:**

classpath:/static
classpath:/public
classpath:/resources
classpath:/META-INF/resources

在application.properties中, 增加如下配置:

# 配置静态资源访问前缀(打包后相对于jar为根目录,放入的文件依然有效, 打包时这个目录无文件是无效的)
spring.mvc.static-path-pattern=/mystatic/**
# 配置静态资源路径 (注意,如果指定了配置, 默认配置将失效)
spring.resources.static-locations[0]=classpath:/mystatic
spring.resources.static-locations[1]=classpath:/public
spring.resources.static-locations[2]=classpath:/static

本地路径可以使用file:前缀 spring.resources.static-locations[2]=file:${user.dir}/static spring.resources.static-locations[2]=file:f:/root/static

注意以上配置也会被WebMvcConfigurer接口的配置方法addResourceHandlers覆盖!

代码配置

@Configuration
@EnableWebMvc
public class ConfigurerAdapter implements WebMvcConfigurer {
 
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedHeaders("*")
                .allowedOrigins("*")
                .allowedMethods("GET","POST","PUT","DELETE","OPTIONS");
    }
 
//spring.resources.static-locations=file:${user.dir}/static/, classpath:/static/,classpath:/public/, classpath:/META-INF/resources,classpath:/META-INF/static
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
        	.addResourceLocations("classpath:/META-INF/resources/")
        	.addResourceLocations("classpath:/META-INF/static/")
        	//
        	.addResourceLocations("classpath:/static/")
        	.addResourceLocations("classpath:/public/")
        	.addResourceLocations("classpath:/resources/")
        	//本地路径
        	.addResourceLocations("file:${user.dir}/static/")
        	
        .setCachePeriod(0);
    }
}

获取资源目录

//获取jar内的资源
String PROJECT_ROOT_PATH = ClassUtils.getDefaultClassLoader().getResource("").getPath(); 
 
//获取运行jar目录
protected String getResourceDirectory(String directory) {
    File path = null;
    try {
        path = new File(ResourceUtils.getURL("classpath:").getPath());
        if(!path.exists() ) path = new File("");
        path = new File(path.getAbsolutePath()+"/static/res/"+directory+"/");
        if(!path.exists()) path.mkdirs();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return path.getAbsolutePath();
}

html模板热更新

另外,修改html模板不自动更新, 还需要引入

	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>

再注意 spring.thymeleaf.cache=false,禁用缓存