開發傳統Java WEB工程時,我們可以使用JSP頁面模板語言,但是在SpringBoot中已經不推薦使用了。SpringBoot支持如下頁面模板語言
- Thymeleaf
- FreeMarker
- Velocity
- Groovy
- JSP
上面並沒有列舉所有SpringBoot支持的頁面模板技術。其中Thymeleaf是SpringBoot官方所推薦使用的,下面來談談Thymeleaf一些常用的語法規則。
添加Thymeleaf依賴
要想使用Thhymeleaf,首先要在pom.xml文件中單獨添加Thymeleaf依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Spring Boot默認存放模板頁面的路徑在src/main/resources/templates
或者src/main/view/templates
,這個無論是使用什麼模板語言都一樣,當然默認路徑是可以自定義的,不過一般不推薦這樣做。另外Thymeleaf默認的頁面文件後綴是.html
。
數據顯示
在MVC的開發過程中,我們經常需要通過Controller
將數據傳遞到頁面中,讓頁面進行動態展示。
顯示普通文本
創建一個Controller對象,在其中進行參數的傳遞
@Controller
public class ThymeleafController {
@RequestMapping(value = "show", method = RequestMethod.GET)
public String show(Model model){
model.addAttribute("uid","123456789");
model.addAttribute("name","Jerry");
return "show";
}
}
在SpringBoot默認的頁面路徑下創建show.html文件,內容如下
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="'用戶ID:' + ${uid}"/>
<p th:text="'用戶名稱:' + ${name}"/>
</body>
</html>
可以看到在p
標籤中有th:text
屬性,這個就是thymeleaf的語法,它表示顯示一個普通的文本信息。
如果我們要顯示的信息是存在資源文件中的,同樣可以在頁面中顯示,例如資源文件中定義了內容welcome.msg=歡迎{0}光臨!
。可以在頁面中將其顯示
<h2 th:text="#{welcome.msg('admin')}"/>
另外,在th:utext
中還能做一些基礎的數學運算
<p th:text="'數學計算:1+2=' + (1 + 2)"/>
顯示帶有樣式的普通文本
如果我們想要傳遞到的頁面的信息,它本身是帶有CSS樣式的,這個時候如何在頁面中將攜帶的樣式信息也顯示出來?此時我們的控制器方法這樣寫。
@RequestMapping(value = "showStyle", method = RequestMethod.GET)
public String showStyle(Model model){
model.addAttribute("uid","123456789");
model.addAttribute("name","<span style='color:red'>Jerry</span>");
return "show_style";
}
此時頁面中需要藉助th:utext
屬性進行顯示
<p th:utext="'用戶名稱:' + ${name}"/>
通過瀏覽器查看頁面源碼可以看出th:utext
和th:text
的區別是:th:text
會對<
和>
進行轉義,而th:utext
不會轉義。
顯示對象
我們常常需要將一個bean信息展示在前端頁面當中。
- 用於前端展示的VO類
public class User implements Serializable {
private Long uid ;
private String name ;
private Integer age ;
private Date birthday ;
private Double salary ;
//省略get/set方法
}
- 控制器方法
@RequestMapping(value = "/message/member_show", method = RequestMethod.GET)
public String memberShow(Model model) {
User vo = new User();
vo.setUid(12345678L);
vo.setName("尼古拉丁.趙四");
vo.setAge(59);
vo.setSalary(1000.00);
vo.setBirthday(new Date());
model.addAttribute("member", vo);
return "message/member_show";
}
- 頁面展示
<div>
<p th:text="'用戶編號:' + ${member.uid}"/>
<p th:text="'用戶姓名:' + ${member.name}"/>
<p th:text="'用戶年齡:' + ${member.age}"/>
<p th:text="'用戶工資:' + ${member.salary}"/>
<p th:text="'出生日期:' + ${member.birthday}"/>
<p th:text="'出生日期:' + ${#dates.format(member.birthday,'yyyy-MM-dd')}"/>
</div>
<hr/>
<div th:object="${member}">
<p th:text="'用戶編號:' + *{uid}"/>
<p th:text="'用戶姓名:' + *{name}"/>
<p th:text="'用戶年齡:' + *{age}"/>
<p th:text="'用戶工資:' + *{salary}"/>
<p th:text="'出生日期:' + *{birthday}"/>
<p th:text="'出生日期:' + *{#dates.format(birthday,'yyyy-MM-dd')}"/>
</div>
上面給出了兩種展現方式,一種是通過${屬性},另外一種是通過{屬性}。
關於“${屬性}”和“{屬性}”的區別?
$訪問完整信息,而訪問指定對象中的屬性內容, 如果訪問的只是普通的內容兩者沒有區別;
數據處理
在 thymeleaf 之中提供有相應的集合的處理方法,例如:在使用 List 集合的時候可以考慮採用 get()方法獲取指定索引的數據,那麼在使用 Set 集合的時候會考慮使用 contains()來判斷某個數據是否存在,使用 Map 集合的時候也希望可以使用 containsKey()判斷某個 key 是否存在,以及使用get()根據 key 獲取對應的 value,而這些功能在之前並不具備,下面來觀察如何在頁面中使用此類操作
- 控制器方法向頁面傳遞一些數據,以供操作
@RequestMapping(value = "/user/set", method = RequestMethod.GET)
public String set(Model model) {
Set<String> allNames = new HashSet<String>() ;
List<Integer> allIds = new ArrayList<Integer>() ;
for (int x = 0 ; x < 5 ; x ++) {
allNames.add("boot-" + x) ;
allIds.add(x) ;
}
model.addAttribute("names", allNames) ;
model.addAttribute("ids", allIds) ;
model.addAttribute("mydate", new java.util.Date()) ;
return "user_set" ;
}
- 數據處理
<body>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"/>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss.SSS')}"/>
<hr/>
<p th:text="${#strings.replace('www.baidu.cn','.','$')}"/>
<p th:text="${#strings.toUpperCase('www.baidu.cn')}"/>
<p th:text="${#strings.trim('www.baidu.cn')}"/>
<hr/>
<p th:text="${#sets.contains(names,'boot-0')}"/>
<p th:text="${#sets.contains(names,'boot-9')}"/>
<p th:text="${#sets.size(names)}"/>
<hr/>
<p th:text="${#sets.contains(ids,0)}"/>
<p th:text="${ids[1]}"/>
<p th:text="${names[1]}"/>
</body>
路徑處理
在傳統WEB工程開發時,路徑的處理操作是有點麻煩的。SpringBoot中爲我們簡化了路徑的處理。
-
在"src/main/view/static/js"中創建一個js文件
js文件路徑
- 然後在頁面中可以通過“@{路徑}”來引用。
<script type="text/javascript" th:src="@{/js/main.js}"></script>
頁面之間的跳轉也能通過@{}來實現
<a th:href="@{/show}">訪問controller方法</a>
<a th:href="@{/static_index.html}">訪問靜態頁面</a>
操作內置對象
雖然在這種模版開發框架裏面是不提倡使用內置對象的,但是很多情況下依然需要使用內置對象進行處理,所以下面來看下如何在頁面中使用JSP內置對象。
- 在控制器裏面增加一個方法,這個方法將採用內置對象的形式傳遞屬性。
@RequestMapping(value = "/inner", method = RequestMethod.GET)
public String inner(HttpServletRequest request, Model model) {
request.setAttribute("requestMessage", "springboot-request");
request.getSession().setAttribute("sessionMessage", "springboot-session");
request.getServletContext().setAttribute("applicationMessage",
"springboot-application");
model.addAttribute("url", "www.baidu.cn");
request.setAttribute("url2",
"<span style='color:red'>www.baidu.cn</span>");
return "show_inner";
}
- 在頁面之中如果要想訪問不同屬性範圍中的內容,則可以採用如下的做法完成:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<script type="text/javascript" th:src="@{/js/main.js}"></script>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="${#httpServletRequest.getRemoteAddr()}"/>
<p th:text="${#httpServletRequest.getAttribute('requestMessage')}"/>
<p th:text="${#httpSession.getId()}"/>
<p th:text="${#httpServletRequest.getServletContext().getRealPath('/')}"/>
<hr/>
<p th:text="'requestMessage = ' + ${requestMessage}"/>
<p th:text="'sessionMessage = ' + ${session.sessionMessage}"/>
<p th:text="'applicationMessage = ' + ${application.applicationMessage}"/>
</body>
</html>
thymeleaf 考慮到了實際的開發情況,因爲 request 傳遞屬性是最爲常用的,但是 session 也有可能使用,例如:用戶登錄之後需要顯示用戶 id,那麼就一定要使用到 session,所以現在必須增加屬性範圍的形式後才能夠正常使用。在 thymeleaf 裏面也支持有 JSP 內置對象的獲取操作,不過一般很少這樣使用。
邏輯處理
所有的頁面模版都存在各種基礎邏輯處理,例如:判斷、循環處理操作。在 Thymeleaf 之中對於邏輯可以使用如下的一些運算符來完成,例如:and、or、關係比較(>、<、>=、<=、==、!=、lt、gt、le、ge、eq、ne)。
通過控制器傳遞一些屬性內容到頁面之中:
<span th:if="${member.age lt 18}">
未成年人!
</span>
<span th:if="${member.name eq '啊三'}">
歡迎小三來訪問!
</span>
不滿足條件的判斷
<span th:unless="${member.age gt 18}">
你還不滿18歲,不能夠看電影!
</span>
通過swith進行分支判斷
<span th:switch="${member.uid}">
<p th:case="100">uid爲101的員工來了</p>
<p th:case="99">uid爲102的員工來了</p>
<p th:case="*">沒有匹配成功的數據!</p>
</span>
數據遍歷
在實際開發過程中常常需要對數據進行遍歷展示,一般會將數據封裝成list或map傳遞到頁面進行遍歷操作。
- 定義控制器類,向頁面傳遞List數據和Map數據
@Controller
public class UserController {
@RequestMapping(value = "/user/map", method = RequestMethod.GET)
public String map(Model model) {
Map<String,User> allMembers = new HashMap<String,User>();
for (int x = 0; x < 10; x++) {
User vo = new User();
vo.setUid(101L + x);
vo.setName("趙四 - " + x);
vo.setAge(9);
vo.setSalary(99999.99);
vo.setBirthday(new Date());
allMembers.put("mldn-" + x, vo);
}
model.addAttribute("allUsers", allMembers);
return "user_map";
}
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public String list(Model model) {
List<User> allMembers = new ArrayList<User>();
for (int x = 0; x < 10; x++) {
User vo = new User();
vo.setUid(101L + x);
vo.setName("趙四 - " + x);
vo.setAge(9);
vo.setSalary(99999.99);
vo.setBirthday(new Date());
allMembers.add(vo) ;
}
model.addAttribute("allUsers", allMembers);
return "user_list";
}
}
- list類型數據遍歷
<body>
<table>
<tr><td>No.</td><td>UID</td><td>姓名</td><td>年齡</td><td>偶數</td><td>奇數</td></tr>
<tr th:each="user,memberStat:${allUsers}">
<td th:text="${memberStat.index + 1}"/>
<td th:text="${user.uid}"/>
<td th:text="${user.name}"/>
<td th:text="${user.age}"/>
<td th:text="${memberStat.even}"/>
<td th:text="${memberStat.odd}"/>
</tr>
</table>
</body>
- map類型數據遍歷
<body>
<table>
<tr><td>No.</td><td>KEY</td><td>UID</td><td>姓名</td><td>年齡</td><td>偶數</td><td>奇數</td></tr>
<tr th:each="memberEntry,memberStat:${allUsers}">
<td th:text="${memberStat.index + 1}"/>
<td th:text="${memberEntry.key}"/>
<td th:text="${memberEntry.value.uid}"/>
<td th:text="${memberEntry.value.name}"/>
<td th:text="${memberEntry.value.age}"/>
<td th:text="${memberStat.even}"/>
<td th:text="${memberStat.odd}"/>
</tr>
</table>
</body>
頁面引入
我們常常需要在一個頁面當中引入另一個頁面,例如,公用的導航欄以及頁腳頁面。thymeleaf中提供了兩種方式進行頁面引入。
- th:replace
- th:include
- 新建需要被引入的頁面文件,路徑爲"src/main/view/templates/commons/footer.html"
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<footer th:fragment="companyInfo">
<p>設爲首頁 ©2018 SpringBoot 使用<span th:text="${projectName}"/>前必讀
意見反饋 京ICP證030173號 </p>
</footer>
可以看到頁面當中還存在一個變量projectName,這個變量的值可以在引入頁面中通過th:with="projectName=百度"
傳過來。
- 引入頁面中只需要添加如下代碼即可
<div th:include="@{/commons/footer} :: companyInfo" th:with="projectName=百度"/>