本文題材來自于狂神說https://www.bilibili.com/video/BV18E411a7mC
主要涉及網頁的結構和內容。
css主要用來設置網頁的表現樣式,css的層疊樣式表只是一門標記語言,也就是說沒有任何的語法支持,用過的人都知道css應該有如下的缺點:
基于如上的缺點誕生了【css預處理器】
什么是CSS預處理器
CSS預處理器定義了一種新的語言,其基本思想是,用一種專門的編程語言,為CSS增加了一些編程的特性,將CSS作為目標生成文件,然后開發者就只需要使用這種語言進行CSS的編碼工作。轉化成通俗易懂的話來說就是用一種專門的編程語言,進行Web頁面樣式設計,再通過編譯器轉化為正常的CSS文件,以供項目使用。
市面上常見的CSS預處理器
JavaScript一門弱類型腳本語言,其源代碼在發往客戶端運行之前不需要經過編譯,而是將文本格式的字符代碼發送給瀏覽器,由瀏覽器解釋運行。
原生JS開發
我們日常開發都是按照【ECMAScript】標準的開發方式,簡稱ES特點是所有瀏覽器都支持此規范,我們需要知道的是ES5規范對所有的游覽器都支持,但是ES6是市面上用的最多的規范版本,主流游覽器支持,所以為了兼容某些游覽器,需要將ES6規范通過webpack降級為ES5。
TypeScript出現的背景
TypeScript 起源于使用JavaScript開發的大型項目 。由于JavaScript語言本身的局限性,難以勝任和維護大型項目開發。因此微軟開發了TypeScript ,使得其能夠勝任開發大型項目。
對于后端來學Vue的小伙伴是不是有個疑問,什么叫做DOM呢?有什么用處呢?
什么叫DOM?
DOM全稱 Document Object Model,即文檔對象模型,它允許腳本(js)控制Web頁面、窗口和文檔,通俗的說就是js操作html時的API。
主要目的是實現一套代碼三端統一(PC、Android:.apk、iOS:.ipa)并能夠調用到設備底層硬件(如:傳感器、GPS、攝像頭等),打包方式主要有以下兩種:
詳見微信官網,這里就是介紹一個方便微信小程序UI開發的框架:WeUI。
前端人員為了方便開發也需要掌握一定的后端技術但我們Java后臺人員知道后臺知識體系極其龐大復雜,所以為了方便前端人員開發后臺應用,就出現了Node JS這樣的技術。
Node JS的作者已經聲稱放棄Node JS(說是架構做的不好再加上笨重的node modules,可能讓作者不爽了吧)開始開發全新架構的Deno
既然是后臺技術,那肯定也需要框架和項目管理工具, Node JS框架及項目管理工具如下:
iview是一個強大的基于Vue的UI庫, 有很多實用的基礎組件比element ui的組件更豐富, 主要服務于PC界面的中后臺產品。使用單文件的Vue組件化開發模式基于npm+webpack+babel開發, 支持ES 2015高質量、功能豐富友好的API, 自由靈活地使用空間。
備注:屬于前端主流框架,選型時可考慮使用,主要特點是移動端支持較多
Element是餓了么前端開源維護的Vue UI組件庫, 組件齊全, 基本涵蓋后臺所需的所有組件,文檔講解詳細, 例子也很豐富。主要用于開發PC端的頁面, 是一個質量比較高的Vue UI組件庫。
備注:屬于前端主流框架,選型時可考慮使用,主要特點是桌面端支持較多
飛冰是阿里巴巴團隊基于React/Angular/Vue的中后臺應用解決方案, 在阿里巴巴內部, 已經有270多個來自幾乎所有BU的項目在使用。飛冰包含了一條從設計端到開發端的完整鏈路,幫助用戶快速搭建屬于自己的中后臺應用。
備注:主要組件還是以React為主, 截止2019年02月17日更新博客前對Vue的支持還不太完善,目前尚處于觀望階段
Vant UI是有贊前端團隊基于有贊統一的規范實現的Vue組件庫, 提供了-整套UI基礎組件和業務組件。通過Vant, 可以快速搭建出風格統一的頁面,提升開發效率。
at-ui是一款基于Vue 2.x的前端UI組件庫, 主要用于快速開發PC網站產品。它提供了一套n pm+web pack+babel前端開發工作流程, CSS樣式獨立, 即使采用不同的框架實現都能保持統一的UI風格。
cube-ui是滴滴團隊開發的基于Vue js實現的精致移動端組件庫。支持按需引入和后編譯, 輕量靈活;擴展性強,可以方便地基于現有組件實現二次開發。
Flutter是谷歌的移動端UI框架, 可在極短的時間內構建Android和iOS上高質量的原生級應用。Flutter可與現有代碼一起工作, 它被世界各地的開發者和組織使用, 并且Flutter是免費和開源的。
備注:Google出品, 主要特點是快速構建原生APP應用程序, 如做混合應用該框架為必選框架
lonic既是一個CSS框架也是一個Javascript UI庫, lonic是目前最有潛力的一款HTML 5手機應用開發框架。通過SASS構建應用程序, 它提供了很多UI組件來幫助開發者開發強大的應用。它使用JavaScript MV VM框架和Angular JS/Vue來增強應用。提供數據的雙向綁定, 使用它成為Web和移動開發者的共同選擇。
mpvue是美團開發的一個使用Vue.js開發小程序的前端框架, 目前支持微信小程序、百度智能小程序,頭條小程序和支付寶小程序??蚣芑?/span>Vue.js, 修改了的運行時框架runtime和代碼編譯器compiler實現, 使其可運行在小程序環境中, 從而為小程序開發引入了Vue.js開發體驗。
備注:完備的Vue開發體驗, 井且支持多平臺的小程序開發, 推薦使用
WeUI是一套同微信原生視覺體驗一致的基礎樣式庫, 由微信官方設計團隊為微信內網頁和微信小程序量身設計, 令用戶的使用感知更加統一。包含button、cell、dialog、toast、article、icon等各式元素。
為了降低開發的復雜度, 以后端為出發點, 比如:Struts、Spring MVC等框架的使用, 就是后端的MVC時代以SpringMVC流程為例:
優點
缺點
時間回到2005年AJAX(Asynchronous JavaScript And XML, 異步JavaScript和XML,老技術新用法)被正式提出并開始使用CDN作為靜態資源存儲, 于是出現了JavaScript王者歸來(在這之前JS都是用來在網頁上貼狗皮膏藥廣告的) 的SPA(Single Page Application) 單頁面應用時代。
優點
這種模式下, **前后端的分工非常清晰, 前后端的關鍵協作點是AJAX接口。**看起來是如此美妙, 但回過頭來看看的話, 這與JSP時代區別不大。復雜度從服務端的JSP里移到了瀏覽器的JavaScript,瀏覽器端變得很復雜。類似Spring MVC, 這個時代開始出現瀏覽器端的分層架構:
缺點
此處的MVC模式如下:
優點
缺點
前端為主的MVC模式解決了很多很多問題, 但如上所述, 依舊存在不少不足之處。隨著Node JS的興起, JavaScript開始有能力運行在服務端。這意味著可以有一種新的研發模式:
在這種研發模式下,前后端的職責很清晰。對前端來說,兩個UI層各司其職:
通過Node, WebServer層也是JavaScript代碼, 這意味著部分代碼可前后復用, 需要SEO的場景可以在服務端同步渲染,由于異步請求太多導致的性能問題也可以通過服務端來緩解。前一種模式的不足,通過這種模式幾乎都能完美解決掉。
與JSP模式相比, 全棧模式看起來是一種回歸, 也的確是一種向原始開發模式的回歸, 不過是一種螺旋上升式的回歸。
MVVM(Model-View-ViewModel)是一種軟件設計模式,由微軟WPF(用于替代WinForm,以前就是用這個技術開發桌面應用程序的)和Silverlight(類似于Java Applet,簡單點說就是在瀏覽器上運行WPF)的架構師Ken Cooper和Ted Peters開發,是一種簡化用戶界面的事件驅動編程方式。由John Gossman(同樣也是WPF和Sliverlight的架構師)與2005年在他的博客上發表。
MVVM源自于經典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel層,負責轉換Model中的數據對象來讓數據變得更容易管理和使用。其作用如下:
MVVM已經相當成熟了,主要運用但不僅僅在網絡應用程序開發中。當下流行的MVVM框架有Vue.js,Anfular JS
MVVM模式和MVC模式一樣,主要目的是分離視圖(View)和模型(Model),有幾大好處
View
View是視圖層, 也就是用戶界面。前端主要由HTH L和csS來構建, 為了更方便地展現viewModel或者model層的數據, 已經產生了各種各樣的前后端模板語言, 比如FreeMarker,Thyme leaf等等, 各大MVVM框架如Vue.js.Angular JS, EJS等也都有自己用來構建用戶界面的內置模板語言。
Model
Model是指數據模型, 泛指后端進行的各種業務邏輯處理和數據操控, 主要圍繞數據庫系統展開。這里的難點主要在于需要和前端約定統一的接口規則
ViewModel
ViewModel是由前端開發人員組織生成和維護的視圖數據層。在這一層, 前端開發者對從后端獲取的Model數據進行轉換處理, 做二次封裝, 以生成符合View層使用預期的視圖數據模型。
??需要注意的是View Model所封裝出來的數據模型包括視圖的狀態和行為兩部分, 而Model層的數據模型是只包含狀態的
視圖狀態和行為都封裝在了ViewModel里。這樣的封裝使得ViewModel可以完整地去描述View層。由于實現了雙向綁定, ViewModel的內容會實時展現在View層, 這是激動人心的, 因為前端開發者再也不必低效又麻煩地通過操縱DOM去更新視圖。
??MVVM框架已經把最臟最累的一塊做好了, 我們開發者只需要處理和維護ViewModel, 更新數據視圖就會自動得到相應更新,真正實現事件驅動編程。
??View層展現的不是Model層的數據, 而是ViewModel的數據, 由ViewModel負責與Model層交互, 這就完全解耦了View層和Model層, 這個解耦是至關重要的, 它是前后端分離方案實施的重要一環。
Vue(讀音/vju/, 類似于view)是一套用于構建用戶界面的漸進式框架, 發布于2014年2月。與其它大型框架不同的是, Vue被設計為可以自底向上逐層應用。Vue的核心庫只關注視圖層, 不僅易于上手, 還便于與第三方庫(如:vue-router,vue-resource,vue x) 或既有項目整合。
在MVVM架構中, 是不允許數據Model和視圖View直接通信的, 只能通過ViewModel來通信, 而ViewModel就是定義了一個Observer觀察者(俗稱雙向綁定)
至此, 我們就明白了, Vue.js就是一個MVVM的實現者, 他的核心就是實現了DOM監聽與數據綁定
Vue不支持IE 8及以下版本, 因為Vue使用了IE 8無法模擬的ECMAScript 5特性。但它支持所有兼容ECMAScript 5的瀏覽器
如果是Java開發的小伙伴喜歡用idea的那么可以直接安裝vue的插件即可。
**可能出現的問題:**安裝完插件右鍵新建文件發現沒有vue的模板。
解決辦法:
略!
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:"hello,vue!"
}
});
</script>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!--引用參數-->
<div id="app">{{message}}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
// 定義一個vue實例對象
var vue = new Vue({
// 綁定元素
el:'#app',
// 定義參數并且賦值
data:{
message:"hello vue"
}
});
</script>
</body>
</html>
為了能夠更直觀的體驗Vue帶來的數據綁定功能, 我們需要在瀏覽器測試一番, 操作流程如下:
關于 Web 方面的配置比較多,值得慶幸的是,Spring Boot 已經幫我們預置初始化了很多基礎組件。但在實踐的過程中,某些基礎的組件并不能滿足我們的實際需求,這時就需要我們重新初始化相應組件,甚至在某些極端的情況下需要完全接管 Spring Boot 的默認配置。
本節將基于對前端模板框架 Thymeleaf 的集成,逐步向大家演示如何自定義 ViewResolver以及如何進一步 擴展 Spring MVC 配置。本實例涉及集成 Thymeleaf、自定義初始化ThymeleafViewResolver 以及擴展 Spring MVC。
Thymeleaf 是一個 Java 類庫,能夠處理 HTML/HTML5、XML、JavaScript、CSS, 甚至純文本類型的文件。通常可以用作MVC中的View層,它可以完全替代 JSP。該框架是SpringBoot 首推的前端展示框架。
首先我們創建一個集成 Thymeleaf 的 SpringBootWeb 項目。集成 Thymeleaf 的核心操作就是引入對應的 starter,對應項目中 pom.xml 的依賴如下。
<dependency>
<groupId>org. springframework. boot</groupId>
<artifactId>spring- boot- starter-thymeleaf</ artifactId>
< /dependency>
<groupId>org. springframework . boot</groupId>
<artifactId>spring- boot - starter - web</artifactId>
</ dependency>
通過前面的學習我們已經得知引入該 starter 之后,Spring Boot 便會進行一個初始化的基本配置,因此針對 Thymeleaf 的最簡單集成便完成了,關于頁面展示和基礎配置我們暫時先不考慮。當集成 Thymeleaf 之后,Thymeleaf 對應的自動配置類 ThymeleafAutoConfiguration 中會初始化一個 ThymeleafViewResolver, 用來對 Thymeleaf 的頁面進行解析和渲染。這一操作本質上同默認的 BeanNameViewResolver 作用-樣,都實現了 ViewResolver 接口。
此時,如果官方提供的 ThymeleafViewResolver 的默認設 置無法滿足我們的需求,可以通過 兩 種 途 徑 進 行 自 定 義 設 置 : 通 過 application 配 置 文 件 配 置 和 自 行 創 建ThymeleafViewResolver 對象。
通過 application 配置對應的屬性定義位于 ThymeleafProperties 類中,我們已經做過多次類似的配置,不再贅述。
我們可以通過以下方式自行創建 ThymeleafViewResolver 對象。先定義一個配置類ViewResolverConfig,并在類內部通過@Bean 注解對實例化的 ThymeleafViewResolver對象進行注入容器的操作。
@Configuration
public class ViewResolverConfig {
@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
Thyme leafViewResolver resolver = new ThymeleafViewResolver();
//設置 ViewResolver 對應的屬性 值
resolver. setCharacterEncoding("UTF-8");
resolver. setCache(false);
return resolver;
}
}
@Bean 默 認 會 將 方 法 thymeleafViewResolver 作 為 Bean 的 key, 將 返 回 的Thymeleaf-ViewResolver 對 象 作 為 Value 存 入 容 器 當 中 。 在 方 法 內 部 , 可 通 過ThymeleafViewResolver 對應的方法進行屬性的初始化設置。通過以上代碼我們便完成了自定義 Thymeleaf-ViewResolver 的注入。
那么,原來默認的 ThymeleafViewResolver 會怎么處理呢? 我們知道幾乎所有的自動配置類都是通過注解設置初始化條件的,比如 ThymeleafViewResolver 默認實例化的條件是當容器中不存在名稱為 thymeleafViewResolver 時才會使用默認的初始化。當自定義的ThymeleafViewResolver 類完成初始化之后,默認配置的初始化條件便不再滿足了。
上面針對 SpringMVC 中 Thymeleaf 的 ViewResolver 的自定義進行了講解。
其實在 Spring Boot 中,大多數組件都可以采用同樣的方式對默認配置進行覆蓋。除了上述方法,在 Spring Boot 項目中還可以通過實現 WebMvcConfigurer 接口來進行更靈活地自定義配置。
通過 WebMvcConfigurer 接口實現自定義配置是 Spring 內部的一-種配置方式,它替代了傳統的 XML 形式的配置。通過對該接口具體方法的實現,可以自定義一些 Handler、Interceptor 、ViewResolver 、MessageConverter 等參 數 。 以 上 面 配 置ThymeleafViewResolver 為例,我們也可以通過實現該接口的 configureViewResolvers 方法來進行配置,達到同樣的效果,具體示例代碼如下:
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers (ViewResolverRegistry registry) {
Thyme leafViewResolver resolver = new ThymeleafViewResolver();
//設置 ViewResolver 對應的屬 性值
resolver. setCharacterEncoding("UTF-8");
resolver . setCache(false);
registry . viewResolver(resolver);
}
}
使用 WebMvcConfigurer 接口時需注意 Spring Boot 版本,以上代碼是基于 Spring Boot 2.0以后的版本。WebMvcConfigurer 接口還提供 了其他關于擴展 SpringMVC 配置的接口,使用方法與上述示例基本一樣,大家可以查閱對應的代碼進一步了解, 這里就不再逐一舉例了。
最后,關于 SpringMVC 自定義配置的最徹底操作就是完全接管 SpringBoot 關于 SpringMVC的默認配置,具體操作就是在 WebMvcConfigurer 的實現類上使用@EnableWebMvc 注解,示例如下。
@EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
使用該注解等于擴展了 WebMvcConfigurationSupport,但是沒有重寫任何方法,因此所需的功能都需要開發人員自行實現。-般情況下不推薦使用這種方式,該方式更適合基于 SpringBoot 提供的默認配置,針對特別需求進行有針對性拓展的場景。
其實,本節內容的重點并不只是讓大家學會簡單的 Web 自定義配置,更深的用意是希望大家了解在 Spring Boot 默認自動配置的基礎上,我們可以通過什么方式以及如何進行自定義的拓展。本節中提到但未列出實例的內容,大家可以根據已經學習到的思路相應練習。
本章重點針對 Spring Boot 中 Web 應用的自動配置和 Spring MVC 的自動配置展開,并以Spring MVC 中的一些典型配置為例進行了源碼講解。
其 實 圍 繞 Web 應 用 還 有 一 系 列 的 自 動 配 置 比 如HttpEncodingAutoConfigurationMultipartAutoConfiguration和HttpMessageConvertersAutoConfiguration 等。我們只需領悟自動配置的精髓:這些相關配置只不過是將之前通過 xml 來配置 Bean,轉換成了基于類的形式來配置而已。讀者可按照以上方法對其他 Web 相關的配置項進行相應的閱讀和分析。
雖然現在流行前后端分離,但是后端模版在一些關鍵地方還是非常有用的,例如郵件模版、代碼模版等。當然也不排除一些古老的項目后端依然使用動態模版。
Thymeleaf 簡潔漂亮、容易理解,并且完美支持 HTML5,可以直接打開靜態頁面,同時不新增標簽,只需增強屬性,這樣也降低了學習成本。
因此松哥今天花點時間和大家仔細分享一下 Thymeleaf。
Thymeleaf 是新一代 Java 模板引擎,它類似于 Velocity、FreeMarker 等傳統 Java 模板引擎,但是與傳統 Java 模板引擎不同的是,Thymeleaf 支持 HTML 原型。
它既可以讓前端工程師在瀏覽器中直接打開查看樣式,也可以讓后端工程師結合真實數據查看顯示效果,同時,SpringBoot 提供了 Thymeleaf 自動化配置解決方案,因此在 SpringBoot 中使用 Thymeleaf 非常方便。
事實上, Thymeleaf 除了展示基本的 HTML ,進行頁面渲染之外,也可以作為一個 HTML 片段進行渲染,例如我們在做郵件發送時,可以使用 Thymeleaf 作為郵件發送模板。
另外,由于 Thymeleaf 模板后綴為 .html,可以直接被瀏覽器打開,因此,預覽時非常方便。
Spring Boot 中整合 Thymeleaf 非常容易,只需要創建項目時添加 Thymeleaf 即可:
創建完成后,pom.xml 依賴如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
當然,Thymeleaf 不僅僅能在 Spring Boot 中使用,也可以使用在其他地方,只不過 Spring Boot 針對 Thymeleaf 提供了一整套的自動化配置方案,這一套配置類的屬性在 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 中,部分源碼如下:
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = DEFAULT_PREFIX;
private String suffix = DEFAULT_SUFFIX;
private String mode = "HTML";
private Charset encoding = DEFAULT_ENCODING;
private boolean cache = true;
//...
}
而我們剛剛提到的,Spring Boot 為 Thymeleaf 提供的自動化配置類,則是 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration ,部分源碼如下:
@Configuration
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {
}
可以看到,在這個自動化配置類中,首先導入 ThymeleafProperties ,然后 @ConditionalOnClass 注解表示當當前系統中存在 TemplateMode 和 SpringTemplateEngine 類時,當前的自動化配置類才會生效,即只要項目中引入了 Thymeleaf 相關的依賴,這個配置就會生效。
這些默認的配置我們幾乎不需要做任何更改就可以直接使用了。如果開發者有特殊需求,則可以在 application.properties 中配置以 spring.thymeleaf 開頭的屬性即可。
接下來我們就可以創建 Controller 了,實際上引入 Thymeleaf 依賴之后,我們可以不做任何配置。新建的 IndexController 如下:
@Controller
public class IndexController {
@GetMapping("/index")
public String index(Model model) {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User u = new User();
u.setId((long) i);
u.setName("javaboy:" + i);
u.setAddress("深圳:" + i);
users.add(u);
}
model.addAttribute("users", users);
return "index";
}
}
public class User {
private Long id;
private String name;
private String address;
//省略 getter/setter
}
在 IndexController 中返回邏輯視圖名+數據,邏輯視圖名為 index ,意思我們需要在 resources/templates 目錄下提供一個名為 index.html 的 Thymeleaf 模板文件。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<td>編號</td>
<td>用戶名</td>
<td>地址</td>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
<td th:text="${user.address}"></td>
</tr>
</table>
</body>
</html>
在 Thymeleaf 中,通過 th:each 指令來遍歷一個集合,數據的展示通過 th:text 指令來實現,
注意 index.html 最上面引入 thymeleaf 名稱空間(最新版并無強制要求)。
配置完成后,就可以啟動項目了,訪問 /index 接口,就能看到集合中的數據了:
前面我們說的是返回一個 Thymeleaf 模板,我們也可以手動渲染 Thymeleaf 模板,這個一般在郵件發送時候有用,例如我在 resources/templates 目錄下新建一個郵件模板,如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>hello 歡迎 <span th:text="${username}"></span>加入 XXX 集團,您的入職信息如下:</p>
<table border="1">
<tr>
<td>職位</td>
<td th:text="${position}"></td>
</tr>
<tr>
<td>薪水</td>
<td th:text="${salary}"></td>
</tr>
</table>
<img src="http://www.javaboy.org/images/sb/javaboy.jpg" alt="">
</body>
</html>
這一個 HTML 模板中,有幾個變量,我們要將這個 HTML 模板渲染成一個 String 字符串,再把這個字符串通過郵件發送出去,那么如何手動渲染呢?
@Autowired
TemplateEngine templateEngine;
@Test
public void test1() throws MessagingException {
Context context = new Context();
context.setVariable("username", "javaboy");
context.setVariable("position", "Java工程師");
context.setVariable("salary", 99999);
String mail = templateEngine.process("mail", context);
//省略郵件發送
}
前面兩個案例讓小伙伴們大致上理解了在 Spring Boot 中要如何使用 Thymeleaf,接下來,松哥將詳細介紹 Thymeleaf 本身的一些具體用法。
${...}
直接使用 th:xx = "${}" 獲取對象屬性。這個在前面的案例中已經演示過了,不再贅述。
*{...}
可以像 ${...} 一樣使用,也可以通過 th:object 獲取對象,然后使用 th:xx = "*{}" 獲取對象屬性,這種簡寫風格極為清爽,推薦大家在實際項目中使用。
<table border="1" th:object="${user}">
<tr>
<td>用戶名</td>
<td th:text="*{username}"></td>
</tr>
<tr>
<td>地址</td>
<td th:text="*{address}"></td>
</tr>
</table>
#{...}
通常的國際化屬性:#{...} 用于獲取國際化語言翻譯值。
在 resources 目錄下新建兩個文件:messages.properties 和 messages_zh_CN.properties,內容如下:
messages.properties:
message = javaboy
messages_zh_CN.properties:
message = 江南一點雨
然后在 thymeleaf 中引用 message,系統會根據瀏覽器的語言環境顯示不同的值:
<div th:text="#{message}"></div>
@{...}
<script type="text/javascript" th:src="@{http://localhost:8080/hello.js}"></script>
等價于:
<script type="text/javascript" src="http://localhost:8080/hello.js"></script>
首先在 application.properties 中配置 Spring Boot 的上下文,以便于測試:
server.servlet.context-path=/myapp
引用路徑:
<script type="text/javascript" th:src="@{/hello.js}"></script>
等價于:
<script type="text/javascript" src="/myapp/hello.js"></script>
這個相對是指相對于服務器的 URL,例如如下引用:
<script type="text/javascript" th:src="@{~/hello.js}"></script>
等價于:
<script type="text/javascript" src="/hello.js"></script>
應用程序的上下文 /myapp 將被忽略。
<script type="text/javascript" th:src="@{//localhost:8080/hello.js}"></script>
等價于:
<script type="text/javascript" src="//localhost:8080/hello.js"></script>
<script type="text/javascript" th:src="@{//localhost:8080/hello.js(name='javaboy',age=99)}"></script>
等價于:
<script type="text/javascript" th:src="//localhost:8080/hello.js?name=javaboy&age=99"></script>
~{...}
片段表達式是 Thymeleaf 的特色之一,細粒度可以達到標簽級別,這是 JSP 無法做到的。片段表達式擁有三種語法:
舉個簡單例子。
在 resources/templates 目錄下新建 my_fragment.html 文件,內容如下:
<div th:fragment="javaboy_link"><a href="http://www.javaboy.org">www.javaboy</a></div>
<div th:fragment="itboyhub_link"><a href="http://www.itboyhub.com">www.itboyhub.com</a></div>
這里有兩個 div,通過 th:fragment 來定義片段,兩個 div 分別具有不同的名字。
然后在另外一個頁面中引用該片段:
<table border="1" th:object="${user}" th:fragment="aaa">
<tr>
<td>用戶名</td>
<td th:text="*{username}"></td>
</tr>
<tr>
<td>地址</td>
<td th:text="*{address}"></td>
</tr>
</table>
<hr>
<div th:replace="my_fragment.html"></div>
<hr>
<div th:replace="~{my_fragment.html::javaboy_link}"></div>
<hr>
<div th:replace="~{::aaa}"></div>
通過 th:replace 來引用片段。第一個表示引用完整的 my_fragment.html 頁面;第二個表示引用 my_fragment.html 中的名為 javaboy_link 的片段;第三個表示引用當前頁面名為 aaa 的片段,也就是上面那個 table。
這些是一些可以直接寫在表達式中的字符,主要有如下幾種:
案例:
<div th:text="'這是 文本字面量(有空格)'"></div>
<div th:text="javaboy"></div>
<div th:text="99"></div>
<div th:text="true"></div>
如果文本是英文,并且不包含空格、逗號等字符,可以不用加單引號。
文本可以使用 + 進行拼接。
<div th:text="'hello '+'javaboy'"></div>
<div th:text="'hello '+${user.username}"></div>
如果字符串中包含變量,也可以使用另一種簡單的方式,叫做字面量置換,用 | 代替 '...' + '...',如下:
<div th:text="|hello ${user.username}|"></div>
<div th:text="'hello '+${user.username}+' '+|Go ${user.address}|"></div>
算術運算有:+, -, *, / 和 %。
<div th:with="age=(99*99/99+99-1)">
<div th:text="${age}"></div>
</div>
th:with 定義了一個局部變量 age,在其所在的 div 中可以使用該局部變量。
案例:
<div th:with="age=(99*99/99+99-1)">
<div th:text="9 eq 9 or 8 ne 8"></div>
<div th:text="!(9 eq 9 or 8 ne 8)"></div>
<div th:text="not(9 eq 9 or 8 ne 8)"></div>
</div>
表達式里的值可以使用 >, <, >= 和 <= 符號比較。== 和 != 運算符用于檢查相等(或者不相等)。注意 XML規定 < 和 > 標簽不能用于屬性值,所以應當把它們轉義為 < 和 >。
如果不想轉義,也可以使用別名:gt (>);lt (<);ge (>=);le (<=);not (!)。還有 eq (==), neq/ne (!=)。
舉例:
<div th:with="age=(99*99/99+99-1)">
<div th:text="${age} eq 197"></div>
<div th:text="${age} ne 197"></div>
<div th:text="${age} ge 197"></div>
<div th:text="${age} gt 197"></div>
<div th:text="${age} le 197"></div>
<div th:text="${age} lt 197"></div>
</div>
類似于我們 Java 中的三目運算符。
<div th:with="age=(99*99/99+99-1)">
<div th:text="(${age} ne 197)?'yes':'no'"></div>
</div>
其中,: 后面的部分可以省略,如果省略了,又同時計算結果為 false 時,將返回 null。
基本內置對象:
在頁面可以訪問到上面這些內置對象,舉個簡單例子:
<div th:text='${#session.getAttribute("name")}'></div>
實用內置對象:
這是一些內置對象以及工具方法,使用方式也都比較容易,如果使用的是 IntelliJ IDEA,都會自動提示對象中的方法,很方便。
舉例:
<div th:text="${#execInfo.getProcessedTemplateName()}"></div>
<div th:text="${#arrays.length(#request.getAttribute('names'))}"></div>
這個是給 HTML 元素設置屬性值??梢砸淮卧O置多個,多個之間用 , 分隔開。
例如:
<img th:attr="src=@{/1.png},title=${user.username},alt=${user.username}">
會被渲染成:
<img src="/myapp/1.png" title="javaboy" alt="javaboy">
當然這種設置方法不太美觀,可讀性也不好。Thymeleaf 還支持在每一個原生的 HTML 屬性前加上 th: 前綴的方式來使用動態值,像下面這樣:
<img th:src="@{/1.png}" th:alt="${user.username}" th:title="${user.username}">
這種寫法看起來更清晰一些,渲染效果和前面一致。
上面案例中的 alt 和 title 則是兩個特殊的屬性,可以一次性設置,像下面這樣:
<img th:src="@{/1.png}" th:alt-title="${user.username}">
這個等價于前文的設置。
數組/集合/Map/Enumeration/Iterator 等的遍歷也算是一個非常常見的需求,Thymeleaf 中通過 th:each 來實現遍歷,像下面這樣:
<table border="1">
<tr th:each="u : ${users}">
<td th:text="${u.username}"></td>
<td th:text="${u.address}"></td>
</tr>
</table>
users 是要遍歷的集合/數組,u 則是集合中的單個元素。
遍歷的時候,我們可能需要獲取遍歷的狀態,Thymeleaf 也對此提供了支持:
u 后面的 state 表示遍歷狀態,通過遍歷狀態可以引用上面的屬性。
<table border="1">
<tr th:each="u,state : ${users}">
<td th:text="${u.username}"></td>
<td th:text="${u.address}"></td>
<td th:text="${state.index}"></td>
<td th:text="${state.count}"></td>
<td th:text="${state.size}"></td>
<td th:text="${state.current}"></td>
<td th:text="${state.even}"></td>
<td th:text="${state.odd}"></td>
<td th:text="${state.first}"></td>
<td th:text="${state.last}"></td>
</tr>
</table>
只顯示奇數次的遍歷,可以使用 th:if,如下:
<table border="1">
<tr th:each="u,state : ${users}" th:if="${state.odd}">
<td th:text="${u.username}"></td>
<td th:text="${u.address}"></td>
<td th:text="${state.index}"></td>
<td th:text="${state.count}"></td>
<td th:text="${state.size}"></td>
<td th:text="${state.current}"></td>
<td th:text="${state.even}"></td>
<td th:text="${state.odd}"></td>
<td th:text="${state.first}"></td>
<td th:text="${state.last}"></td>
</tr>
</table>
th:if 不僅僅只接受布爾值,也接受其他類型的值,例如如下值都會判定為 true:
但是如果值為 null,th:if 會求值為 false。
th:unless 的判定條件則與 th:if 完全相反。
<table border="1">
<tr th:each="u,state : ${users}" th:unless="${state.odd}">
<td th:text="${u.username}"></td>
<td th:text="${u.address}"></td>
<td th:text="${state.index}"></td>
<td th:text="${state.count}"></td>
<td th:text="${state.size}"></td>
<td th:text="${state.current}"></td>
<td th:text="${state.even}"></td>
<td th:text="${state.odd}"></td>
<td th:text="${state.first}"></td>
<td th:text="${state.last}"></td>
</tr>
</table>
這個顯示效果則與上面的完全相反。
當可能性比較多的時候,也可以使用 switch:
<table border="1">
<tr th:each="u,state : ${users}">
<td th:text="${u.username}"></td>
<td th:text="${u.address}"></td>
<td th:text="${state.index}"></td>
<td th:text="${state.count}"></td>
<td th:text="${state.size}"></td>
<td th:text="${state.current}"></td>
<td th:text="${state.even}"></td>
<td th:text="${state.odd}"></td>
<td th:text="${state.first}"></td>
<td th:text="${state.last}"></td>
<td th:switch="${state.odd}">
<span th:case="true">odd</span>
<span th:case="*">even</span>
</td>
</tr>
</table>
th:case="*" 則表示默認選項。
這個我們前面已經涉及到了,使用 th:with 可以定義一個本地變量。
我們可以使用屬性將數據放入頁面模版中,但是很多時候,內聯的方式看起來更加直觀一些,像下面這樣:
<div>hello [[${user.username}]]</div>
用內聯的方式去做拼接也顯得更加自然。
[[...]] 對應于 th:text (結果會是轉義的 HTML),[(...)]對應于 th:utext,它不會執行任何的 HTML 轉義。
像下面這樣:
<div th:with="str='hello <strong>javaboy</strong>'">
<div>[[${str}]]</div>
<div>[(${str})]</div>
</div>
最終的顯示效果如下:
不過內聯方式有一個問題。我們使用 Thymeleaf 的一大優勢在于不用動態渲染就可以直接在瀏覽器中看到顯示效果,當我們使用屬性配置的時候確實是這樣,但是如果我們使用內聯的方式,各種表達式就會直接展示在靜態網頁中。
也可以在 js 或者 css 中使用內聯,以 js 為例,使用方式如下:
<script th:inline="javascript">
var username=[[${user.username}]]
console.log(username)
</script>
js 中需要通過 th:inline="javascript" 開啟內聯。
好啦,Thymeleaf 跟大家也介紹的差不多了,應付日常的工作應該是可以了。對 Thymeleaf 感興趣的小伙伴,也可以看看它的官方文檔: https://www.thymeleaf.org。
最后,松哥還搜集了 50+ 個項目需求文檔,想做個項目練練手的小伙伴不妨看看哦~
需求文檔地址:https://gitee.com/lenve/javadoc
*請認真填寫需求信息,我們會在24小時內與您取得聯系。