参考文章: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案例

  1. 整合thymeleaf
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
  1. 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>
  1. 编写跳转页面的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";
    }
}
  1. 测试页面显示结果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=.html

2.2、疑难问题

问题:为什么thymeleaf页面放在templates文件夹里面,并且后缀要是.html呢

springboot框架会将内置支持的功能组件放在spring-boot-autoconfigure-2.5.0.jar包下,而thymeleaf框架就是内置支持的。所以在这个包里面可以找到对应的自动配置代码,如下图:

springboot 制作二进制包_配置文件

如果找默认的属性配置,应该找XxxProperties类,如图所示,thymeleaf模板的前后缀如下:

springboot 制作二进制包_spring boot_02

所以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配置类中。

springboot 制作二进制包_springboot 制作二进制包_03

@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>

测试结果:

springboot 制作二进制包_html_04

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,它会自动管理国际化资源文件。

springboot 制作二进制包_配置文件_05

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

springboot 制作二进制包_spring_06

当然,我们也可以自己定义国际化文件名称,这里我们将国际化配置文件命名为message。

  1. 去yml配置文件中配置国际化
spring:
  messages:
    basename: i18n.message # 配置国际化支持
    encoding: utf-8 # 配置编码
  1. 要确保文件编码是utf-8,可以到idea的设置里去设置并让其自动转换,Editor->File Encodings
  2. springboot 制作二进制包_spring_07

  3. 3. 创建i18n文件夹及3个国际化配置文件,如图: 其中message.properties是基础配置文件(默认),如果你的浏览器它是其他语言比如法语,是没有办法国际化的,所以它就会采用message.properties
  4. springboot 制作二进制包_配置文件_08

    springboot 制作二进制包_配置文件_09

  5. 在idea里只要创建两个国际化的配置文件就会自动加入到Resource Bundle 'xxx',当然我们还是需要创建三个properties配置文件。后缀必须按格式写,_en_US就是英文,_zh_CN就是中文。
  6. 编写国际化 我们直接点进message.properties,可以看到下方有个切换到Resource Bundle的按钮,点击切换,添加国际化,然后分别在右侧写上对应国际化语言
  7. springboot 制作二进制包_spring_10

  8. 想添加多少,就可以添加多少。
  9. 可以在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>
  1. 一般来说 我们在页面会做个切换中英文的按你来进行切换
<!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>
  1. 做完以上步骤,我们还需要编写一个本地解析器来进行解析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();
    }
}
  1. 编写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";
    }
}
  1. 测试

3.1.5、链接表达式

链接表达式的作用:用来指定的跳转的链接

  1. 绝对网址,绝对URL用于创建到其他服务器的链接,需要指定协议名称http或者https,如:
<a th:href="@{https://www.baidu.com}">百度</a>
  1. 上下文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>
  1. 服务器相关URL,它与上下文路径很相似,它主要用于一个Tomcat下运行有多个项目的情况。比如说我们当前项目为app,如果tomcat还运行着一个otherApp,我们就可以通过该方法访问otherApp的请求路径。
<!-- 在页面这样写 -->
<a th:href="@{~/otherApp/blog/search}">跳转</a>
<!-- Thymeleaf解析之后是这样的 -->
<a href="/otherApp/blog/search">跳转</a>
  1. 有时候我们需要页面带参数传递到后端,则可以使用下面这个方法
<!-- 在页面这样写 -->
<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>