springboot05: Thymeleaf
静态资源的映射
Web前端使用了越来越多的JS或CSS,如JQuery,Backbone.js和Bootstrap。一般情况下,我们是将这些Web资源拷贝到Java Web项目的webapp相应目录下进行管理。这种通过人工方式管理可能会产生版本误差,拷贝版本错误,漏拷等现象,导致前端页面无法正确展示,版本不一致,文件混乱等,导致出现一些莫名其妙的错误等。
WebJars是将web前端资源(js,css等)打成jar包文件,然后借助Maven工具,以jar包形式对web前端资源进行统一依赖管理,保证这些Web资源版本唯一性。WebJars的jar包部署在Maven中央仓库上。
自动配置的原理
在WebMvcAutoConfiguration类下的addResourceHandlers方法会将 web 对应url为 /webjars/** 的静态资源自动映射 => classpath:/META-INF/resources/webjars
addResourceHandlers.代码如下:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 如果spring.resources.addMappings 为false,则不进行处理
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
// 获得缓存时间,默认没配置
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
// 如果ResourceHandlerRegistry中不包含/webjars/**的路径映射,
// 则添加 /webjars/** --> classpath:/META-INF/resources/webjars/ 的映射规则
customizeResourceHandlerRegistration(
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
// 获得静态资源的映射路径,默认为 /**
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
// 如果ResourceHandlerRegistry中不包含静态资源的映射路径,
// 则添加 staticPathPattern --> classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/, classpath:/public/ 的映射规则
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}
- 如果spring.resources.addMappings 为false,则不进行处理.否则进入第2步
- 获得缓存时间,可通过spring.resources.cachePeriod 配置.
- 如果ResourceHandlerRegistry中不包含/webjars/** 的路径映射,则添加 /webjars/** –> classpath:/META-INF/resources/webjars/ 的映射规则
- 如果通过spring.mvc.staticPathPattern 配置的静态资源的映射路径在ResourceHandlerRegistry不存在,则添加 配置映射路径 –>classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/, classpath:/public/ 的映射规则
欢迎页映射
在WebMvcAutoConfiguration类下,welcomePageHandlerMapping.代码如下:
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
getWelcomePage()
private Resource getWelcomePage() {
String[] var1 = this.resourceProperties.getStaticLocations();
int var2 = var1.length;
// 从StaticLoaction,按照顺序查找index
for(int var3 = 0; var3 < var2; ++var3) {
String location = var1[var3];
Resource indexHtml = this.getIndexHtml(location);
if (indexHtml != null) {
return indexHtml;
}
}
ServletContext servletContext = this.getServletContext();
if (servletContext != null) {
return this.getIndexHtml((Resource)(new ServletContextResource(servletContext, "/")));
} else {
return null;
}
}
默认拦截路径为/**, 首页为在如下路径下查找:
- classpath:/META-INF/resources/index.html
- classpath:/resources/index.html
- classpath:/static/index.html
- classpath:/public/index.html
哪些配置可以自定义
static-location:自定义静态资源文件夹位置
spring.web.resources.static-locations=classpath:/abcd/, classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
static-path-pattern: 映射位置
spring.mvc.static-path-pattern=/aaa/**
但是这样欢迎页就无法实现了,解决办法如下(添加页面跳转)
@Controller
public class MyController {
@RequestMapping("/")
public String welcomePage(){
return "forward:/aaa/index.html";
}
}
模板引擎
概念
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。
模板引擎的实现方式有很多,最简单的是“置换型”模板引擎,这类模板引擎只是将指定模板内容(字符串)中的特定标记(子字符串)替换一下便生成了最终需要的业务数据(比如网页)。
置换型模板引擎实现简单,但其效率低下,无法满足高负载的应用需求(比如有海量访问的网站),因此还出现了“解释型”模板引擎和“编译型”模板引擎等。
原理
模板的诞生是为了将显示与数据分离,其本质是将模板文件和数据通过模板引擎生成最终的HTML代码(如图)
.png)
模板引擎的基本机理就是替换(转换),将指定的标签转换为需要的业务数据;将指定的伪语句按照某种流程来变换输出。
Thymeleaf
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。
启用Thymeleaf,只需要在 <html>加上这个
<html lang="en" xmlns:th="http://www.thymeleaf.org">
修改/添加标签属性
模板文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
h2{
color:red;
}
.green-div{
color: green;
}
.box-border{
border: 3px solid black;
}
</style>
</head>
<body>
<div th:text="${msg}">原来的内容</div>
<h2>1. th:text,th:utext</h2>
<!-- th:text: 不转义字符,HTML标记被当作字符串处理 -->
<div th:text="${msg1}"></div>
<!-- th:utext: 转义字符,HTML标记被当作标记处理 -->
<!-- 修改属性 th:attr,但是不能修改class属性 -->
<div th:utext="${msg1}"></div>
<!-- th:attrappend 在class后面添加属性,需要添加空格-->
<div id="div1" class="green-div" th:attrappend="class=${' ' + boxBorder}" th:id="${divId}">AAA</div>
<!-- th:attrprepend 在class前面添加属性-->
<div id="div2" class="green-div" th:attrprepend="class=${ boxBorder+' '}" th:id="${divId}">BBB</div>
<!-- th:attrappend简写方式-->
<div id="div3" class="green-div" th:classappend="${' '+ boxBorder}" th:id="${divId}">CCC</div>
<input type="button" value="按钮" th:value="${btnName}"/>
<h2>2. th:attrprepend</h2>
</body>
</html>
在Controller中添加/修改变量属性
@RequestMapping("/th1")
public String th1(Map<String,Object>map){
map.put("msg","<h1>Hello,World!</h1>");
map.put("msg1","<h1>Hello,World!</h1>");
map.put("divId","divArgs1");
map.put("boxBorder","box-border");
map.put("btnName","修改后的按钮");
return "th1";
}
条件判断
th:if
<!--
map.put("trueVariable",true);
map.put("falseVariable",false);
-->
<div class="background-green" th:if="${trueVariable}">111</div>
<div class="background-green" th:if="${falseVariable}">222</div>
<!--
map.put("zeroNumber",0);
map.put("s1","false");
map.put("s2","off");
map.put("s3","no");
map.put("nullObject",null);
-->
<!--有哪些情况下 th:if被当作false-->
<div class="background-green" th:if="${zeroNumber}">333</div>
<div class="background-green" th:if="${s1}">444</div>
<div class="background-green" th:if="${s2}">555</div>
<div class="background-green" th:if="${s3}">666</div>
<div class="background-green" th:if="${nullObject}">777</div>
<!--th:unless = th:if not-->
<div class="background-green" th:unless="${falseVariable}">888888</div>
<!--th:switch-->
<div th:switch="${level}">
<p th:case="1">Level 1</p>
<p th:case="2">Level 2</p>
<p th:case="3">Level 3</p>
<p th:case="*">Other Levels</p>
</div>
循环控制
对于信息页面,数据格式是一样时,页面通常都是循环迭代它们,写过 JSP 的 JSTL 的就知道,JSTL 有一个 <c:foreach>,同理 Thymeleaf 也有一个 th:each。作用都是一样的,都是用于遍历数组、List、Set、Map 等数据。
```html
| 工号 | 姓名 | 生日 | 是否已婚 | 工资 |
|---|---|---|---|---|