springboot05:Thymeleaf


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));
    }
}
  1. 如果spring.resources.addMappings 为false,则不进行处理.否则进入第2步
  2. 获得缓存时间,可通过spring.resources.cachePeriod 配置.
  3. 如果ResourceHandlerRegistry中不包含/webjars/** 的路径映射,则添加 /webjars/** –> classpath:/META-INF/resources/webjars/ 的映射规则
  4. 如果通过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代码(如图)

模板引擎

模板引擎的基本机理就是替换(转换),将指定的标签转换为需要的业务数据;将指定的伪语句按照某种流程来变换输出。

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

工号 姓名 生日 是否已婚 工资

文章作者: 银色回廊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 银色回廊 !
评论
  目录