学习目标
熟悉Thymeleaf模板引擎基础语法
熟悉SpringBoot模板配置和静态资源映射规则
掌握SpringBoot整合Thymeleaf模板引擎使用
掌握SpringBoot国际化功能实现
在一个web应用中,通常会采用MVC设计模式实现对应的模型、视图和控制器,其中,视图时用户看到并与之交互的界面。对最初的web应用来说,视图时由html元素组成的静态揭秘那;而后期的web应用更倾向于使用动态模板技术,从而实现前后端分离和页面的动态数据展示。SpringBoot框架为简化项目的整体开发,提供了一些视图技术支持,并主要推荐整合模板引擎实现前端页面的动态化内容。本章将对SpringBoot支持的视图技术进行介绍,并使用SpringBoot整合常用的Thymeleaf模板引擎进行视图页面的实现。
前端模板引擎技术的出现,使前端开发人员无须关注后端业务的具体实现,只关注自己页面的呈现鲜果即可,从而解决了前端代码错综复杂的问题,实现了全后端分离开发。SpringBoot对很多模板引擎技术提供了支持,具体介绍如下:
(1) FreeMarker: FreeMarker是一个基于模板生成输出文本(HTML页面、电子邮件、配置文件等)的模板引素,它不是面向最终用户的,而是一个Java类库,是一款程序员可以做入所开发产品的组件。
(2)Groovy: Groovy是一种基于JM( Java虚拟机)的敏捷开发语言,它结合了Pyhon.Ruby和Sltalkl的许多强大特性,能够与Java代码很好地结合,也能扩展现有代码。Groovy运行在JVM上,它可以使用Java语言编写的其他库。
(3) Thymeleal: 它是一种用于Web和独立环境的现代服务器端的Java模板引擎,其主要目标是将优雅的Java模板带到开发工作流程中,将HTML在浏览器中正确显示,并且可以作为静态原型,让开发团队能更容易地协作。Thymeleaf能够处理HTML, XML, JavaScript, CSsS 甚至纯文本。
(4) Mustache: Mustache是轻逻辑的模板引擎(Logic-less templates),它是一个JS模板,用于对JS进行分离展示。Mustache的优势在于可以应用在JavaScript. PHP、Python、Perl等多种编程语言中。
Spring Boot不太支持常用的JSP模板,并且没有提供对应的整合配置,这是因为使用嵌入式Servlet容器的Spring Boot应用程序对于JSP模板存在一些限制, 具体如下所示。
(1) Spring Boo默认使用嵌入式Servlet容器以JAR包的方式进行项目打包部署,这种JAR包方式不支持JSP模板
(2)使用Undertow嵌入式容器部署Spring Boot项目时,不支持JSP模板。
(3)Spin Boot默认提供了一个处理请求路径Ierror”的统-错误处理器,返回具体的异常信息。使用JSP模板时,无法使用Spring Boo自带的异常处理器,只能根据要求在SpringBoot项目的指定位置定制错误页面。
上面对Sping Boo支持的根板引降进行了介绍,并指出了整合JSP极板的一一些限制。接下来,本章将选择其中常用的Thymeleal模板引擎进行介绍,并完成与Spring Boo框架的整合实现。
Thymeleaf 是一种现代的基于服务器端的Java模板引擎技术,也是一个优秀的面向Java的XML,XHTML,HTML5页面模板,它具有丰富的标签语言,函数和表达式,在使用SpringBoot框架进行页面设计时,一般会选择Thymeleaf 模板。本节将针对Thymeleaf 常用的标签,表达式进行讲解。
在HTML页面上使用Thymeleaf 标签,Thymeleaf 标签能够动态的替换静态内容,动态显示页面内容。
为了让大家更直观的认识Thymeleaf 模板,下面我们展示一个在HTML文件中嵌入了Thymeleaf 的页面文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.Thymeleaf.org">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" media="all" href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
<title>Title</title>
</head>
<body>
<p th:text="#{hello}">
欢迎进入Thymeleaf 的学习
</p>
</body>
</html>
上述代码中,xmlns:th="Thymeleaf"用于引入Thymeleaf模板引擎,关键字“th”标签时Thymeleaf模板提供的标签,其中,“th:href”用于引入外联样式文件,“th:text”用于动态先似乎标签文本内容。除此之外,Thymeleaf模板提供了很多标签,接下来我们通过一张表罗列Thymeleaf的常用标签
th:标签 | 说明 |
---|---|
th:insert | 页面片段包含(类似于JSP中的include标签) |
th:replace | 页面片段包含(类似于JSP中的include标签) |
th:each | 元素遍历(类似于JSP中的c:forEach标签) |
th:if | 条件判断,条件成立时显示th标签的内容 |
th:unless | 条件判断,条件不成立时显示th标签的内容 |
th:switch | 条件判断,进行选择性匹配 |
th:case | th:switch分支的条件判断 |
th:object | 用于替换对象 |
th:with | 用于定义局部变量 |
th:attr | 通用属性修改 |
th:attrprepend | 通用属性修改,将计算结果追加前缀到现有属性值 |
th:attrappend | 通用属性修改,将计算结果追加前缀到现有属性值 |
th:value | 属性值修改,指定标签属性值 |
th:href | 用于设定链接地址 |
th:src | 用于设定链接地址 |
th:text | 用于指定标签显示的文本内容 |
th:utext | 用于指定标签显示的文本内容,对特殊标签不转义 |
th:fragment | 声明片段 |
th:remove | 移除片段 |
在HTML5中这种标签已经不是一个规范的HTML5的属性,需要修改为data-th-*的格式。
但是以上的属性是没有属性快捷方式的,需要读者手动输出如,对开发来说比较麻烦,因此在实际开发中,相对推荐使用引入Thymeleaf标签的形式进行模板引擎页面的开发。
Thymeleaf模板引擎提供了多种标准表达式语法,在正式学习之前,我们先通过一张表展示其主要语法及说明
说明 | 表达式语法 |
---|---|
变量表达式 | ${……} |
选择变量表达式 | *{……} |
消息表达式 | #{……} |
连接URL表达式 | @{……} |
片段表达式 | ~{……} |
上表中列举了Thymeleaf模板引擎最常用的简单表达式语法,并对这些语法进行了功能说明。除此之外,Thymeleaf还提供了其他更多的语法支持,例如文本表达式,算数表达式,布尔表达式,比较表达式等,读者在使用过程中可以查看具体的官方文档说明。下面对表中的表达式进行讲解和说明。
变量表达式
变量表达式${……}主要用于获取上下文中的变量值
<p th:text="${title}">这是标题</p>
上述代码使用了Thymeleaf模板的变量表达式${……}用来动态获取p标签中的内容,如果当前程序没有启动或者当前上下文中不存在title变量,该片段会显示标签默认值“这是标题”;如果当前上下文中存在title变量并且程序已经启动,当前p标签中的默认文本内容将会被title变量的值所替换,从而达到模板引擎页面数据动态替换的效果。
同时,Thymeleaf为变量所有域提供了一些内置对象
#ctx:上下文对象
#vars:上下文变量
#locale:上下问区域设置
#request:(仅限Web Context)HttpServletRequest对象
#response:(仅限Web Context)HttpServletResponse对象
#Session:(仅限Web Context)HttpSession对象
#servletContext:(仅限Web Context)ServletContext对象
结合上述内置对象的说明,假设要在Thymeleaf模板引擎页面中动态获取当前国家信息,可以使用#locale内置对象
The locale country is :<span th:text="${#locale.country}">US</span>
上述代码中,使用th:text="${#locale.country}"动态获取当前用户所在国家信息,其中<span>标签内默认内容为US(美国),程序启动后通过浏览器查看当前页面时,Thymeleaf会通过浏览器语言设置来识别当前用户所在国家信息,从而实现动态替换。
选择变量表达式
选择变量表达式和变量表达式用法类似,一般用于从被选定对象而不是上下文中获取属性值,如果没有选定对象,则和变量表达式一样
<div th:object="${session.user}">
<p>name:<span th:text="${#object.firstName}">Sebastian</span>.</p>
<p>surname:<span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality:<span th:text="*{Nationality}">Saturn</span>.</p>
</div>
上述代码中,${#object.firstName}变量表达式使用Thymeleaf模板提供的内置对象object获取当前上下文对象中的firstname属性值;${session.user.lastName}变量表达式获取当前user对象的lastname属性值;*{Nationality}选择变量表达式获取当前指定user的Nationality属性值。
3.消息表达式
消息表达式#{……}主要用于Thymeleaf模板页面国际化内容的动态替换和展示。使用消息表达式#{……}进行国际化设置时,还需要提供一些国际化配置文件。这部分内容会在后续小节中详细说明。
4.链接表达式
链接表达式@{……}一般用于页面跳转或者资源的引入,在web开发中占据着非常重要的地位,并且使用也非常频繁。
<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
上述代码中,链接表达式分别编写了绝对链接地址和相对链接地址。在有参表达式中,需要按照@{路径(参数名称=参数值,参数名称=参数值)}的形式编写,同时该参数的值可以使用变量表达式来传递动态参数值。
5.片段表达式
片段表达式时一种用来将标记片段移动到模板中的方法。其中,最常见的用法时使用th:insert或th:replace属性插入片段
<div th:insert="~{thymeleafDemo::title}"></div>
上述代码中,使用th:insert属性将title片段模板引用到该<div>标签中。thymeleafDemo为模板名称,Thymeleaf会自动查找“classpath:/resources/templates/”目录下的thymeleafDemo模板,title为声明的片段名称。
在SpringBoot项目中使用Thymeleaf模板,首先必须保证引入Thymeleaf依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
其次,在全局配置文件中配置Thymeleaf模板的一些参数。一般web项目都会使用下列配置
spring.thymeleaf.cache=true #启用模板缓存
spring.thymeleaf.encoding=UTF-8 #模板编码
spring.thymeleaf.mode=HTML5 #应用于模板的模板模式
spring.thymeleaf.prefix=classpath:/resources/templates/ #指定模板页面存放路径
spring.thymeleaf.suffix=.html #指定模板页面名称的后缀
上述配置中,spring.thymleaf.cache表示是否开启Thymeleaf模板缓存,默认为true,在开发过程中通过会关闭缓存,保证项目调试过程中数据能够及时响应;spring.thymeleaf.prefix指定了Thymeleaf模板页面的存放路径,默认为:classpath:/templates/;spring.thymeleaf.suffix指定了Thymeleaf模板页面的名称后缀,默认为.html
开发web应用时,难免需要使用静态资源。SpringBoot默认设置了静态资源的访问路径,默认将/**所有访问映射到以下目录。
classpath:META-INF/resources/:项目类路径下的META-INF文件夹下的resources文件夹下的所有文件
classpath:/resources/:项目类路径下的resources文件夹下的所有文件
classpath:/static/:项目类路径下的static文件夹下的所有文件
classpath:/public/:项目类路径下的public文件夹下的所有文件
使用Spring Initializr方式创建的SpringBoot项目会默认生成一个resources目录,在resources目录中新建public,resources,static3个目录,SpringBoot默认会一次从public,resources,static里面查找静态资源。
创建SpringBoot项目,引入Thymeleaf依赖
使用Spring Initializr方式创建项目,并选择Template Engines模块下的Thymeleaf依赖,并选择当前匹配的jdk版本。
2.编写配置文件
打开application.properties全局配置文件,在该文件中对Thymeleaf模板页面的数据缓存进行设置
#Thymeleaf页面缓存设置(默认为true),开发中方便调试应设置为false,上线稳定后应保持默认为true
spring.thymeleaf.cache=false
以上代码用于关闭模板页面的缓存。
3.创建web控制类
在项目中创建controller包,并在该包下创建一个用于前端欧版页面动态数据替换效果测试的访问实体类LoginController
这里@GetMapping注解报错,需要添加web依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
package com.example.demo4.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Calendar;
@Controller
public class LoginController {
/**
* 获取并封装当前年份,跳转到登录页login.html
*/
@GetMapping("/toLoginPage")
public String toLoginPage(Model model){
model.addAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR));
return "login";
}
}
上述代码中,toLoginPage(Model model)方法想登录也也买你login.html跳转时,携带了表示当前年份信息的currentYear参数。
4.创建模板页面并引入静态资源文件
在resources文件夹下创建templates目录,并在该文件夹下创建一个用户登录的模板页面login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1,shrink-to-fit=no">
<title>用户登录界面</title>
<link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<!-- 用户登录form表单 -->
<form class="form-signin">
<img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" >请登录</h1>
<input type="text" class="form-control"
th:placeholder="用户名" required="" autofocus="">
<input type="password" class="form-control"
th:placeholder="密码" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> 记住我
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" >登录</button>
<p class="mt-5 mb-3 text-muted">? <span th:text="${currentYear}">2018</span>-<span th:text="${currentYear}+1">2019</span></p>
<a class="btn btn-sm" >中文</a>
<a class="btn btn-sm" >English</a>
</form>
</body>
</html>
以上代码中,先通过xmlns:th="Thymeleaf"引入了Thymeleaf模板标签,然后使用th:href和th:src分别引入了两个外联的样式文件和一个图片,最后使用th:text引入了后台动态传递过来的当前年份currentYear。该页面中需要一些css样式和图片文件,因此我们需要在resources文件夹下创建static和css,img文件夹等等。
5.效果测试
启动项目及逆行测试,启动项目成功后,在浏览器地址上访问“http://loaclhost:8080/toLoginPage”进入用户登录页面
1.编写多语言国际化文件及配置文件
在项目的类路径resources文件夹下创建i18n的文件夹,并在该文件夹下创建对应的多语言国际化文件。
login.properties
login.tip=请登录
login.username=用户名
login.password=密码
login.rememberme=记住我
login.button=登录
?login_zh_CN.properties
login.tip=请登录
login.username=用户名
login.password=密码
login.rememberme=记住我
login.button=登录
login_en_US.properties
login.tip=Please sign in
login.username=Username
login.password=Password
login.rememberme=Remember me
login.button=Login
login.properties文件为默认语言配置文件,其他两个文件为自定义国际化语言配置文件,自定义国际化语言配置文件的名称必须严格按照“文件前缀名_语言代码__国家代码.properties”的形式命名
2.编写配置文件
在项目的全局配置文件中添加国际化文件的基础名
#配置国际化文件基础名
spring.messages.basename=i18n.login
该配置表示指定国际化配置文件路径为i18n文件夹下的以login开头的所有文件。
3.定制区域信息解析器
以上这种实现方式默认是使用请求头中的语言信息(浏览器语言信息)自动进行语言切换的,有些项目还会提供手动语言切换的功能,这就需要定制区域解析器了。在项目中创建config包,并创建用于定制国际化功能区域信息解析器的自定义配置类
package com.example.demo4.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
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;
/**
* @Classname MyLocalResovel
* @Description 自定义区域信息解析器配置类
* @Date 2019-3-1 17:24
* @Created by CrazyStone
*/
@Configuration
public class MyLocalResovel implements LocaleResolver {
// 自定义区域解析方式
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
// 获取页面手动切换传递的语言参数l
String l = httpServletRequest.getParameter("l");
// 获取请求头自动传递的语言参数Accept-Language
String header = httpServletRequest.getHeader("Accept-Language");
Locale locale=null;
// 如果手动切换参数不为空,就根据手动参数进行语言切换,否则默认根据请求头信息切换
if(!StringUtils.isEmpty(l)){
String[] split = l.split("_");
locale=new Locale(split[0],split[1]);
}else {
// Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
String[] splits = header.split(",");
String[] split = splits[0].split("-");
locale=new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, @Nullable
HttpServletResponse httpServletResponse, @Nullable Locale locale) {
}
// 将自定义的MyLocalResovel类重新注册为一个类型LocaleResolver的Bean组件
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResovel();
}
}
MyLocalResovel配置类实现了LocaleResolver接口,并重写了resolveLocale方法解析自定义语言。使用@Bean注解将当前配置类注册成Spring容器中一个Bean组件。该方法可以根据不同的需求切换语言信息从而获取请求的参数,只有请求参数不为空时,才可以及逆行语言的切换。在请求参数l的语言手动切换组装时,使用的时下划线“_”进行的切割,这是由多语言配置文件的格式决定的,而在请求头参数Accept-Language的语言自动切换组装时,使用的时短横线“-”进行的切割,这是由浏览器发送的请求头信息样式决定的,例如Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
4.页面国际化使用
打开login.html页面将中文部分修改为对应于国际化语言配置文件的属性参数
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1,shrink-to-fit=no">
<title>用户登录界面</title>
<link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/login/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<!-- 用户登录form表单 -->
<form class="form-signin">
<img class="mb-4" th:src="@{/login/img/login.jpg}" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">请登录</h1>
<input type="text" class="form-control"
th:placeholder="#{login.username}" required="" autofocus="">
<input type="password" class="form-control"
th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> [[#{login.rememberme}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.button}">登录</button>
<p class="mt-5 mb-3 text-muted">? <span th:text="${currentYear}">2018</span>-<span th:text="${currentYear}+1">2019</span></p>
<a class="btn btn-sm" th:href="@{/toLoginPage(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/toLoginPage(l='en_US')}">English</a>
</form>
</body>
</html>
5.整合效果测试
运行后发现页面出现了中文乱码,这是因为idea开发工具编写的properties文件默认使用的时GBK编码格式,这些文件内容显示时最终会转换为ASCII码的形式,这就是导致了中文乱码的原因。因此,在浏览器展示之前,必须对idea开发工具的properties文件编码格式进行设置。
打开idea开发软件的设置界面,找到file encoding选项
再找到file-》other setting中的内容
修改完成后,将之前的内容重新编写以下配置信息即可,重新运行
本章介绍了SpringBoot支持的视图技术,然后介绍了Thymeleaf模板引擎的基本语法及其用法,最后介绍了SpringBoot于Thymeleaf模板这个和实现页面数据的展示以及国际化。
一、填空题
针对于WebFlux框架的整合实现,SpringBoot实现了与()、Thymeleaf和Mustache模板引擎技术的整合和自动化配置。
Thymeleaf时适用于()和独立环境的现代服务器端Java模板引擎。
针对HTML页面处理,Thymeleaf的()属性可以进行数据遍历。
使用Thymeleaf模板及逆行HTML页面处理,可以使用()属性替换th:*属性进行页面开发。
Thymeleaf模板中使用()可以动态获取当前用户所在的国家信息。
二、判断题
SpringBoot不能使用JSP进行项目开发。()
如果想要使用Thymeleaf模板进行纯HTML5的页面开发,可以使用data-th-* 属性替换th:* 属性进行页面开发。()
Thymeleaf是针对Web开发中HTML静态页面的处理,实现动态数据展示。()
SpringBoot中编写国际化时,必须要在全局配置文件进行国际化文件配置。()
国际化文件的名称必须严格按照“文件前缀名_语言代码__国家代码.properties”的形式命名。()
三、选择题
以下选项中,SpringBoot整合SpringMVC框架支持的模板引擎技术有()。(多选)
A. FreeMarker B.Groovy C.Mustache D.Thymeleaf
关于SpringBoot整合JSP模板技术的限制,以下说法错误的是()。
A.SpringBoot默认的JAR包部署方式不支持JSP模板
B.Undertow嵌入式容器部署SpringBoot项目,不支持JSP模板
C.使用JSP模板时,无法对默认的错误处理器进行覆盖
D.使用JSP模板时,无法自定义错误页面
Thymeleaf支持处理那些模板页面?()
A. HTML B.XML C.JS D.CSS
以下关于Thymeleaf模板中th:*属性的说法,错误的是()
A.th:forEach属性用来进行数据遍历
B.th:utext属性进行文本内容展示,且不进行转义
C.th:fragment属性用来声明片段
D.th:value属性用于内容修改
SpringBoot中,可以存放静态资源文件的位置有()。(多选)
A.项目根路径下的/META-INF/resources/文件夹下
B.项目根路径下的resources及其子文件夹下
C.项目根路径下的static文件夹下
D.项目根路径下的public及其子文件夹下