在asp.net mvc 中, 有一個視圖解析器, 可以支持Razor語法. 使用起來, 是非常的方便, 并且, 寫在前臺頁面的后臺方法, 是可調試的.
但是在java中, 目前我還沒有接觸到, 像.net vs 那么強大的功能.
對于mvc來說, 視圖的解析, 是必不可少的. 實現的功能, 和上面是一樣的, 而且, 有很多種, 例如: jsp, freemarker, thymeleaf 等.
這里, 我主要記錄 thymeleaf 的一些學習筆記. 這里不牽涉原理, 只記錄使用方法.
一. 添加依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
這里如果只添加到這里, 引用的版本, 是比較低的, 如果要使用自己特定的版本, 只需要在 pom.xml 的properties 中指定版本就行了.
<thymeleaf.version>3.0.5.RELEASE</thymeleaf.version> <thymeleaf-layout-dialect.version>2.0.0</thymeleaf-layout-dialect.version>
二. spring boot 中, thymeleaf 的默認配置
這里首先看一下, 默認配置接收的類
/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.thymeleaf; import java.nio.charset.Charset; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.MimeType; /** * Properties for Thymeleaf. * * @author Stephane Nicoll * @since 1.2.0 */ @ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html"); public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; /** * Check that the template exists before rendering it (Thymeleaf 3+). */ private boolean checkTemplate = true; /** * Check that the templates location exists. */ private boolean checkTemplateLocation = true; /** * Prefix that gets prepended to view names when building a URL. */ private String prefix = DEFAULT_PREFIX; /** * Suffix that gets appended to view names when building a URL. */ private String suffix = DEFAULT_SUFFIX; /** * Template mode to be applied to templates. See also StandardTemplateModeHandlers. */ private String mode = "HTML5"; /** * Template encoding. */ private Charset encoding = DEFAULT_ENCODING; /** * Content-Type value. */ private MimeType contentType = DEFAULT_CONTENT_TYPE; /** * Enable template caching. */ private boolean cache = true; /** * Order of the template resolver in the chain. By default, the template resolver is * first in the chain. Order start at 1 and should only be set if you have defined * additional "TemplateResolver" beans. */ private Integer templateResolverOrder; /** * Comma-separated list of view names that can be resolved. */ private String[] viewNames; /** * Comma-separated list of view names that should be excluded from resolution. */ private String[] excludedViewNames; /** * Enable MVC Thymeleaf view resolution. */ private boolean enabled = true; ...... }
從這里可以看到, 默認的是 html 格式的, 且放在 classpath:/templates/ 目錄下. 一般情況下, 我們不需要再對thymeleaf進行配置, 但是在開發的過程中, 可能要屏蔽緩存功能. 最后我們要做的, 只是將路徑拼接進去就行了.
application.yml文件中, 可以禁用緩存.
spring: thymeleaf: cache: false
三. 基本使用
1. 表達式
變量表達式: ${...}
選擇變量表達式: *{...}
URL表達式: @{...}
消息表達式: #{...}
片段表達式: ~{...}
2. 文字
文本: '123', 'abc'
數字: 1,2,0.5
布爾: true, false
空: null
3. 文本操作
字符串連接: +
文本替換: |雙豎線隔起來 ${name}|
4. 算數運算符
二進制運算法(加減乘除,取模): + - * / %
5. 負號: -
6. 布爾運算符
and or not !
7. 比較和相等運算符
比較運算符(這里建議使用英文字符代替 > >= < <=) gt ge lt le
相等運算符: == !=
8. 條件運算符
三元運算符: if(...)? 'then' : 'else'
if(...)? 'then' 這里沒有else, 因為else默認為 ''
為空判斷 (aaa)?:bbb 如果aaa為空, 則使用bbb的值, 否則使用aaa
9. 啞操作符 _ (一個下劃線)
接下來對以上部分進行測試.
controller:
package org.elvin.learn.springboot.controller; import org.elvin.learn.springboot.pojo.Book; import org.joda.time.DateTime; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.thymeleaf.util.MapUtils; import java.util.*; @Controller @RequestMapping("thy") public class ThyController { @GetMapping("index") public String index(Model model) { model.addAttribute("book0", null); Book book = new Book("springmvc", new DateTime().toString("yyyy-MM-dd"), 10000L); model.addAttribute("book", book); Book book1 = new Book("springboot", new DateTime().toString("yyyy-MM-dd"), 21000L); model.addAttribute("book1", book1); model.addAttribute("color", "red"); model.addAttribute("msg", "welcome"); model.addAttribute("nowTime", new Date()); return "thy/index"; } }
html:
大體框架
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Title</title> <!--@ { } 鏈接網址表達式, 會自動加入虛擬路徑--> <link th:href="@{/bootstrap-3.3.7/css/bootstrap.css}" rel="stylesheet"/> <link th:href="@{/bootstrap-3.3.7/css/bootstrap-theme.css}" rel="stylesheet"/> <style th:inline="css"> /*通過[ [ $ { }]]的方式訪問model中的屬性*/ .bgcolor { background-color: [[${color}]] } </style> </head> <body> <script th:src="@{/js/jquery1.11.1/jquery-1.11.1.js}" type="text/javascript"></script> <script th:src="@{/bootstrap-3.3.7/js/bootstrap.js}" type="text/javascript"></script> <script th:inline="javascript"> $(function () { var book = [[${book}]]; console.log(book.name); }); </script> </body> </html>
數據準備:
在messages.properties中加入以下數據:
welcome=welcome here! {0}
hello={0} say hello to {1}
startWorkd=start from here
在templates中新建文件夾 common, 在下面建兩個文件 footer.html, header.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Title</title> </head> <body> <div th:fragment="footerDiv"> <p>common.footer 底部菜單</p> </div> </body> </html> <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Title</title> </head> <body> <div id="headerDiv"> <p>common.header 頭部菜單</p> </div> </body> </html>
接下來, 就是在里面添加內容了.
<div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">URL表達式 / 消息表達式</h3> <!-- URL 表達式 --> <a style="background-color: #0f0f0f" th:href="@{/thy/index(lang='en_US')}">English(US)</a> <a style="background-color: #0f0f0f" th:href="@{http://localhost:8080/springboot/thy/index?lang=zh_CN}">簡體中文</a> </div> <div class="panel-body"> <!-- 1. # { }消息表達式 : 替換文本 1.1 文本中, 預留參數 1.2 消息key用變量替換 --> <!--1.1 在消息中加入參數, 多個參數, 在傳值的時候用逗號隔開--> <p th:text="#{startWorkd}"></p> <p th:utext="#{welcome(${book.name})}">hahaha</p> <p th:utext="#{hello(${book.name}, ${bookList[1].name})}">hahaha</p> <!--1.2 消息用變量替換--> <p th:utext="#{${msg}(${book.name})}">hahaha</p> </div> </div> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">選擇變量表達式</h3> </div> <div class="panel-body"> <!-- 選擇變量表達式 * { } --> <p th:object="${book0 ?: book1}"> <span th:text="*{name}"></span> <span th:text="*{price gt 10000}?'大于100元':'小于等于100元'"></span> <span th:text="*{publishTime.length() ge 10}?'時間長度過長'"></span> </p> <p> <!--星號語法計算所選對象而不是整個上下文的表達式, 所以, 只要沒有選定的對象, $ 和 * 語法就完全相同--> <span th:text="*{book.name}"></span> <span th:text="*{book.price} / 100 + '元'"></span> <span th:text="*{book.publishTime}"></span> </p> </div> </div> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">選擇變量表達式</h3> </div> <div class="panel-body"> <div style="display:none"> <!--assert 都成立才會執行, 否則拋出異常 th:assert="${!#strings.isEmpty(onevar)},${!#strings.isEmpty(twovar)}" --> <!--這里將模板定義成了函數的方式, temp1表示函數名, name1, name2 表示參數, 不同的是, 可以不寫在這里, 直接在下面用的時候會寫也可以--> <div th:fragment="temp1(name1, name2)"> <span th:utext="|book: ${name1} , book1: ${name2}|"></span> </div> <!--th:assert="${price > 100}, ${!#strings.isEmpty(name)}"--> <div th:fragment="temp2"> <span th:utext="'book: ' + ${name} + ', price: ' + ${price}"></span> </div> </div> <!--replace可以替換能成insert,但是他們之間是有區別的, insert會保留當前標簽--> <div th:replace=":: temp1(${book.name}, ${book1.name})"></div> <div th:insert="~{:: temp2(name=${book.name}, price=${book.price})}"></div> <!--include官方3.0后不推薦使用--> <div th:include=":: temp1(name1=${book.name}, name2=${book1.name})"></div> <!--引入外部的文件中的某一部分內容--> <div th:insert="~{common/header :: #headerDiv}"></div> <div th:insert="~{common/footer :: footerDiv}"></div> <!--這里可以通過判斷表達式來控制插入什么, 或者什么也不插入--> <div th:insert="_">啥也不插入, 也不替換任何東西</div> <div th:insert="${book0 == null}? ~{:: temp1(${book.name}, ${book1.name})}:~{}"></div> </div> </div>
結果:
文章列表