参考文章:SpringBoot【Thymeleaf篇】Thymeleaf - 使用方法及国际化(超详细)
在springboot【ssm+jsp篇】中使用了JSP来作为视图,需要我们自己将项目打成war包,并且部署到Tomcat上,随后项目才可以访问,觉得这有点麻烦,对于springboot这个微服务框架来说,如果使用thymeleaf或者freemarker模板引擎,那么就可以直接打成jar包运行了,而且使用模板引擎,相对于jsp来说,优点多多,那么就来看看什么是thymeleaf。 thymeleaf官网:https://www.thymeleaf.org/
一、thymeleaf概述
1.1、thymeleaf是什么
thymeleaf是一个模板引擎,主要用于编写动态页面。
1.2、thymeleaf的作用
问题:动态页面技术已经有JSP,为什么还要用thymeleaf?
主要原因包括以下几点: 1.使用模板引擎来编写动态页面,让开发人员无法在页面上编写java代码,使得java代码和前端代码绝对的分离。 2.springboot默认整合thymeleaf,不需要任何配置,直接整合成功;打成jar包发布不需要做任何配置。 3.thymeleaf相对于其他的模板引擎(如:Freemark、Velocity),有强大的工具支持。 4.相对于jsp页面,执行效率高。
总结:所有jsp可以使用的地方,thymeleaf都可以使用,并根据thymeleaf的优势,可以得出结论:thymeleaf的作用就是取代jsp。
二、thymeleaf入门配置
需求:配置springboot整合thymeleaf框架。
2.1、HelloWorld案例
- 整合thymeleaf
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>- index.html页面 在resources/templates目录创建一个index.html页面。 注意:必须加上命名空间:xmlns:th="http://www.thymeleaf.org",否则thymeleaf的自定义标签没有提示。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 使用th:text属性输出 -->
<div th:text="${msg}"></div>
</body>
</html>- 编写跳转页面的controller
package com.xbmu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class TestController {
@GetMapping("/index")
public String showMsg(Model model)
{
model.addAttribute("msg","Hello World");
return "index";
}
}- 测试页面显示结果5.application.properties 配置 Thymeleaf 信息
# 启用缓存:建议生产开启
spring.thymeleaf.cache=false
# 建议模版是否存在
spring.thymeleaf.check-template-location=true
# Content-Type 值
spring.thymeleaf.servlet.content-type=text/html
# 是否启用
spring.thymeleaf.enabled=true
# 模版编码
spring.thymeleaf.encoding=utf-8
# 应该从解析中排除的视图名称列表(用逗号分隔)
spring.thymeleaf.excluded-view-names=
# 模版模式
spring.thymeleaf.mode=HTML5
# 模版存放路径
spring.thymeleaf.prefix=classpath:/templates/
# 模版后缀
spring.thymeleaf.suffix=.html2.2、疑难问题
问题:为什么thymeleaf页面放在templates文件夹里面,并且后缀要是.html呢
springboot框架会将内置支持的功能组件放在spring-boot-autoconfigure-2.5.0.jar包下,而thymeleaf框架就是内置支持的。所以在这个包里面可以找到对应的自动配置代码,如下图:
如果找默认的属性配置,应该找XxxProperties类,如图所示,thymeleaf模板的前后缀如下:
所以thymeleaf的页面存放在templates文件夹中,并且页面的后缀为 .html。
Controller层返回页面示例
// 假如我们的默认文件夹就是templates
// controller层返回到admin文件下的index.html页面
return "admin/index";
// 返回到templates下的index页面
return "index";
// 重定向到某个请求 - 会去执行一次admin请求
return "redirect:/admin" // 可以拼接参数
// 返回到index.html页面,但只更新blogList片段
return "index :: blogList"; // 通常就是Ajax请求问题: 项目结构中还有一个static文件夹,是用来放什么的呢?
用来存放静态资源(css、js、image等等),springboot将通用的web模块的配置参数放在web分包中,具体资源配置信息放置在WebProperties配置类中。
@ConfigurationProperties("spring.web")
public class WebProperties {
...
public static class Resources {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
}
}三、thymeleaf语法说明
既然springboot默认集成thymeleaf,以及thymeleaf相对于jsp的多个优势,那么学习thymeleaf是大势所趋,回想起当初我们学习jsp的时候,也是通过作用域对象、基础语法、标签库等等语法学习jsp,那么thymeleaf同样的可以从语法进行学习。
3.1、表达式
3.1.1、表达式—览表
表达式 | 说明 |
${…} | 变量表达式 |
*{…} | 选择变量表达式 |
#{…} | 消息表达式 |
@{…} | 连接网址表达式 |
~{…} | 片段表达式 |
[[…]] | 内联表达式,经过转义之后再输出 |
[(…)] | 内联表达式,原文直接输出 |
注意事项: thymeleaf表达式只能放置标签的thymeleaf的自定义属性里面(如div标签中的 th:text属性)。如果要放在非thymeleaf的自定义属性里面,那么需要使用内联表达式包起来。 内联表达式的意思是:在内嵌表达式的基础上嵌入基本表达式(变量、选择变量、消息等等)
3.1.2、变量表达式
变量表达式的作用是:从web作用域里面取到对应的值,作用域包括:request、session、application。后端代码
package com.xbmu.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
private Long id;
private String name;
private String address;
}@GetMapping("/showUser")
public String showUserInfo(HttpServletRequest request, HttpSession session)
{
User user1 = new User(1L,"张三","陕西省西安市");
request.setAttribute("user1",user1);
User user2 = new User(2L,"李四","甘肃省兰州市");
session.setAttribute("user2",user2);
User user3 = new User(3L,"王五","河南省郑州市");
ServletContext application = request.getServletContext();
application.setAttribute("user3",user3);
return "index";
}页面代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
request: <br/>
<div>
编号:<label th:text="${user1.id}"></label><br/>
姓名:<label th:text="${user1.name}"></label> <br/>
地址:<label th:text="${user1.address}"></label><br/>
</div>
session:<br/>
<div>
编号: <label th:text="${session.user2.id}"></label><br/>
姓名:<label th:text="${session.user2.name}"></label> <br/>
地址:<label th:text="${session.user2.address}"></label><br/>
</div>
application:<br/>
<div>
编号:<label th:text="${application.user3.id}"></label><br/>
姓名:<label th:text="${application.user3.name}"></label><br/>
地址:<label th:text="${application.user3.address}"></label><br/>
</div>
</body>
</html>测试结果:

3.1.3、选择变量表达式
问题: 使用变量表达式来取request、session、application作用域上的属性时,可以发现,我们需要重复编写user、session.user2和application.user3三次,如果user对象的属性有十几个怎么办?显然写十几次相同的代码不是我们想要解决方案。对这种问题,thymeleaf提供了选择变量表达式来解决。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
request: <br/>
<div>
编号:<label th:text="${user1.id}"></label><br/>
姓名:<label th:text="${user1.name}"></label> <br/>
地址:<label th:text="${user1.address}"></label><br/>
</div>
session:<br/>
<div>
编号: <label th:text="${session.user2.id}"></label><br/>
姓名:<label th:text="${session.user2.name}"></label> <br/>
地址:<label th:text="${session.user2.address}"></label><br/>
</div>
application:<br/>
<div>
编号:<label th:text="${application.user3.id}"></label><br/>
姓名:<label th:text="${application.user3.name}"></label><br/>
地址:<label th:text="${application.user3.address}"></label><br/>
</div>
<!--等价于===-->
request: <br/>
<div th:object="${user1}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
session:<br/>
<div th:object="${session.user2}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
application:<br/>
<div th:object="${application.user3}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
</body>
</html><!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
request: <br/>
<div th:object="${user1}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
session:<br/>
<div th:object="${session.user2}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
application:<br/>
<div th:object="${application.user3}">
编号: <label th:text="*{id}"></label><br/>
姓名:<label th:text="*{name}"></label> <br/>
地址:<label th:text="*{address}"></label><br/>
</div>
</body>
</html>3.1.4、消息表达式(国际化)
3.1.4.1、说明
消息表达式的作用,就是用于对国际化功能的支持。所谓的国际化功能就是指,根据浏览器的编码,返回对应编码的内容的支持。
在springboot项目里面做国际化,只需要在/resources/i18n路径下创建xxx.properties、xxx_en_US.properties``、xxx_zh_CN.properties``即可。
在springboot中有一个MessageSourceAutoConfiguration,它会自动管理国际化资源文件。

也就是说,我们在/resources/i18n创建的国际化配置文件前缀名为message时,SpringBoot会自动加载。

当然,我们也可以自己定义国际化文件名称,这里我们将国际化配置文件命名为message。
- 去yml配置文件中配置国际化
spring:
messages:
basename: i18n.message # 配置国际化支持
encoding: utf-8 # 配置编码- 要确保文件编码是utf-8,可以到idea的设置里去设置并让其自动转换,Editor->File Encodings
- 3. 创建i18n文件夹及3个国际化配置文件,如图: 其中message.properties是基础配置文件(默认),如果你的浏览器它是其他语言比如法语,是没有办法国际化的,所以它就会采用message.properties
- 在idea里只要创建两个国际化的配置文件就会自动加入到Resource Bundle 'xxx',当然我们还是需要创建三个properties配置文件。后缀必须按格式写,_en_US就是英文,_zh_CN就是中文。
- 编写国际化 我们直接点进message.properties,可以看到下方有个切换到Resource Bundle的按钮,点击切换,添加国际化,然后分别在右侧写上对应国际化语言
- 想添加多少,就可以添加多少。
- 可以在thymeleaf页面进行获取了,用到前面所说的 #{}




templates/hello.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
标签消息表达式取值:<span th:text="#{home.welcome}"></span><br />
内嵌消息表达式取值:[[#{home.welcome}]]<br />
</body>
</html>- 一般来说 我们在页面会做个切换中英文的按你来进行切换
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
标签消息表达式取值:<span th:text="#{home.welcome}"></span><br />
内嵌消息表达式取值:[[#{home.welcome}]]<br />
<a th:href="@{/hello(lan='zh_CN')}">中文</a>
<a th:href="@{/hello(lan='en_US')}">英文</a>
</body>
</html>- 做完以上步骤,我们还需要编写一个本地解析器来进行解析com/xbmu/component/MyLocaleResolver.java
package com.xbmu.component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public /**
* 本地解析器
*/
class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 接收语言的参数 - 传进来的就是形如'zh_CN'这样的参数
String lan = request.getParameter("lan");
// 使用默认的语言 - 在文中就是login.properties文件里配置的
Locale locale = Locale.getDefault();
// 判断接收的参数是否为空,不为空就设置为该语言
if (StringUtils.hasLength(lan)) {
// 将参数分隔 - 假设传进来的是'zh_CN'
String[] s = lan.split("_");
// 语言编码:zh 地区编码:CN
locale = new Locale(s[0], s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}com/xbmu/config/MyMvcConfig.java
package com.xbmu.config;
import com.xbmu.component.MyLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
}- 编写controller
package com.xbmu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
@GetMapping("/hello")
private String sayHello()
{
return "hello";
}
}- 测试
3.1.5、链接表达式
链接表达式的作用:用来指定的跳转的链接
- 绝对网址,绝对URL用于创建到其他服务器的链接,需要指定协议名称http或者https,如:
<a th:href="@{https://www.baidu.com}">百度</a>- 上下文RL,即与项目根相关联的URL,这里假设我们的war包为app.war,且没有在tomcat的server.xml配置项目的路径(Context),则在Tomcat启动之后,就会在webapps文件下产生一个app文件夹,此时app就是上下文路径(Context)
<!-- 在页面这样写 -->
<a th:href="@{/blog/search}">跳转</a>
<!-- Thymeleaf解析之后是这样的 -->
<a href="/app/blog/search">跳转</a>- 服务器相关URL,它与上下文路径很相似,它主要用于一个Tomcat下运行有多个项目的情况。比如说我们当前项目为app,如果tomcat还运行着一个otherApp,我们就可以通过该方法访问otherApp的请求路径。
<!-- 在页面这样写 -->
<a th:href="@{~/otherApp/blog/search}">跳转</a>
<!-- Thymeleaf解析之后是这样的 -->
<a href="/otherApp/blog/search">跳转</a>- 有时候我们需要页面带参数传递到后端,则可以使用下面这个方法
<!-- 在页面这样写 -->
<a th:href="@{/blog/search(id=3,blogName='Java')}" >跳转</a>
<!-- Thymeleaf解析之后是这样的,这里忽略项目路径 -->
<a href="/blog/search?id=3&blogName=Java" >跳转</a>
<!-- 还可以这样写,实现restful风格的效果 -->
<a th:href="/blog/{id}/search(id=3&blogName=Java)">跳转</a>
<!-- Thymeleaf解析之后是这样的,这里忽略项目路径 -->
<a href="/blog/3/search?blogName=java">跳转</a>



















