SpringBoot起飛系列-Web開發(五)
一、前言
從今天你開始我們就開始進行我們的web開發,之前的一篇用SpringBoot起飛系列-使用idea搭建環境(二)已經說明了我們如何進行開發,當然這是搭建起步,接下來我們就開始進行詳細的開發,包括springboot中各種starters的使用,真正的使用到的功能都是我們實際專案中能用到的。
這裡要提到的時,springboot的開發是分模組化的,每個模組可以對應一個starter,例如:web開發模組就對應spring-boot-starter-web,除此之外還有訪問資料庫的模組、Redis模組等等,我們需要什麼樣的功能就去引入什麼模組,這樣我們的專案管理起來也是十分方便,專案的條理也更加的清晰。
首先我們要搭建一個web專案,所以我們要先選中web模組,這是必須的,之後的模組需要什麼我們再逐一引入。
二、SpringBoot的Web開發約定
2.1 配置約定
俗話說,springboot這個框架本身就是用約定大於配置的方式設計的,很多配置都成了我們的約定(預設的配置),我們雖然可以更改,但是還是有必要知道的。下面我們簡單介紹一下springboot的自動配置原理,這就是springboot中的約定的實現方法。
首先,springboot會把配置檔案中以某個字首開頭的配置對映的bean中去,這樣我們的配置就在程式啟動的時候成了一個一個bean,使用起來也比較方便,預設情況下springboot會用一個Configuration和一個Properites類來配置,如下:
xxxxAutoConfiguration:幫我們給容器中自動配置元件; xxxxProperties:配置類來封裝配置檔案的內容;
每一個的AutoConfiguration對應一個Properties,springboot中所有的配置都是這麼實現的。xxxAutoConfiguration類都是容器中的一個元件,都加入到容器中;用他們來做自動配置;xxxProperties是接受配置的bean。
我們以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋自動配置原理:
@Configuration //表示這是一個配置類,以前編寫的配置檔案一樣,也可以給容器中新增元件 @EnableConfigurationProperties(HttpEncodingProperties.class) //啟動指定類的ConfigurationProperties功能;將配置檔案中對應的值和HttpEncodingProperties繫結起來;並把HttpEncodingProperties加入到ioc容器中 @ConditionalOnWebApplication //Spring底層@Conditional註解(Spring註解版),根據不同的條件,如果滿足指定的條件,整個配置類裡面的配置就會生效; 判斷當前應用是否是web應用,如果是,當前配置類生效 @ConditionalOnClass(CharacterEncodingFilter.class) //判斷當前專案有沒有這個類CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器; @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) //判斷配置檔案中是否存在某個配置 spring.http.encoding.enabled;如果不存在,判斷也是成立的 //即使我們配置檔案中不配置pring.http.encoding.enabled=true,也是預設生效的; public class HttpEncodingAutoConfiguration { //他已經和SpringBoot的配置檔案映射了 private final HttpEncodingProperties properties; //只有一個有參構造器的情況下,引數的值就會從容器中拿 public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) { this.properties = properties; } @Bean //給容器中新增一個元件,這個元件的某些值需要從properties中獲取 @ConditionalOnMissingBean(CharacterEncodingFilter.class) //判斷容器沒有這個元件? public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE)); return filter; }
所以說springboot有很多這樣的類,我們預設只關注配置的prefix就行了, 這是我們以後要覆蓋修改springboot的預設配置所需要的配置key。
2.2 靜態資源對映約定
首先我們可以先看一下靜態資源的配置類,和我們上邊說的是一樣的,字首使用的是spring.resources:
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware { //可以設定和靜態資源有關的引數,快取時間等 }
具體程式碼就不再貼了,直接說結果吧,如果我們用maven管理下載我們的靜態資源包時,比如jquery.js什麼的,那麼我們的預設訪問路徑是 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源。
webjars:http://www.webjars.org/,是以jar包的方式引入靜態資源。例如我們引入jquery.js庫,那麼可以再pom.xml中這麼寫:
<!--引入jquery-webjar-->在訪問的時候只需要寫webjars下面資源的名稱即可 <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1</version> </dependency>
訪問地址:localhost:8080/webjars/jquery/3.3.1/jquery.js
如果我們以普通的方式訪問我們的靜態資源,如html,css,js什麼的,所有的訪問路徑都會從下邊的路徑裡邊去找,classpath:指的就是我們的resources資料夾。優先順序:/META-INF/resources>resources>static>public。
"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" "/":當前專案的根路徑
http://localhost:8080/asserts/css/index.css對應static/asserts/css/index.css。
三、模板引擎
3.1 介紹
模板引擎可能這個詞聽起來很高大上,其實我們之前就接觸過,最早的就是jsp,還有現在比較高階的Velocity、Freemarker、Thymeleaf,其實模板引擎這一類的功能大都具有以下特點,我們可以用一張圖來解釋:
都是資料+表示式,生成html,原理都很簡單了,只是我們看哪個寫起來比較順手,功能更加強大了。springboot推薦使用Thymeleaf來作為模板引擎。
3.2 引入Thymeleaf
首先引入依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
然後在resources資料夾下新增templates資料夾,下邊新增一個index.html,因為預設配置thymeleaf用的字首是classpath:/templates,字尾是.html。
然後我們新增一個HomeController,設定為mvc的控制器,用@Controller註解,如果你用了RestController就直接返回字串了而不是去找檢視了。
@Controller @RequestMapping("/home") public class HomeController { @RequestMapping("/index") public String index(ModelMap map) { map.put("hello","你好"); return "index"; } }
然後修改index.html模板,寫上thymeleaf語法:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>成功!</h1> <!--th:text 將div裡面的文字內容設定為 --> <div th:text="${hello}">這是顯示歡迎資訊</div> </body> </html>
其中xmlns:th="http://www.thymeleaf.org",是匯入名稱空間,可以讓我們編碼的時候有thymeleaf語法提示,不得不說這語法和vue是一樣的啊。
我們直接訪問http://localhost:8080/home/index就可以看到效果了。
3.3 設定預設啟動頁
當我們訪問一個站點域名的時候,可以預設設定跳轉到哪一個頁面,這也是許多網站最基本的操作。
下邊我們新增一個配置類WebConfig,來設定啟動頁:
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { //所有的WebMvcConfigurerAdapter元件都會一起起作用 @Bean //將元件註冊在容器 public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){ WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("forward:/home/index"); registry.addViewController("/index.html").setViewName("forward:/home/index"); } }; return adapter; } }
上邊程式碼的意思是放我們訪問/或者/index.html的時候,預設轉發到/home/index路徑,我們直接設定home/index的頁面就行了。
3.4 Thymeleaf語法
3.4.1 標準表示式
使用${},和ognl表示式一樣,也是為了照顧我們jsp的開發習慣。
java程式碼:
@Controller @RequestMapping("/home") public class HomeController { @RequestMapping("/index") public String index(Map<String,Object> map) { map.put("hello","你好啊"); Person person = new Person(); person.setName("zhangsan"); person.setAge(25); map.put("person",person); return "home/index"; } }
html程式碼:
<body> <h1>成功!</h1> <!--th:text 將div裡面的文字內容設定為 --> <div th:text="${hello}">這是顯示歡迎資訊</div> <br> <p>姓名:<span th:text="${person.name}"></span></p> <p>年齡:<span th:text="${person.age}"></span></p> </body>
3.4.2 選擇變量表達式
選擇變量表達式,也叫星號變量表達式,使用th:object屬性來繫結物件。
html程式碼:
<p>==========選擇變量表達式===========</p> <div th:object="${person}"> <div th:text="*{name}"></div> <div th:text="*{age}"></div> </div>
選擇變量表達式使用th:object來表示要選擇的物件,然後使用*來代表這個物件,後邊的{}裡邊寫物件中的屬性。
也可以直接使用*{person.name}來獲取資料,不同的是${}是在上細紋的map中獲取資料,而*是在選擇的物件上獲取資料。
<p>==========選擇變量表達式===========</p> <div > <div th:text="*{person.name}"></div> <div th:text="*{person.age}"></div> </div>
3.4.3 url表示式
生成一個url地址或者一個路徑。可用於<script src="..">、<link href="..">、<a href="..">等。
<p>==========Url表示式===========</p> <div > <!--相對路徑--> <a th:href="@{'person?name='+${person.name}}" >地址1</a> <!--相對於專案的根路徑--> <a th:href="@{'/person?name='+${person.name}}" >地址2</a> </div> <script th:src="@{'/asserts/js/index.js'}"></script>
幾乎所有的html屬性都能用th:xxx的形式替換,經過thymeleaf解析後會直接替換為原始html屬性和值。
3.4.4 內建物件
thymeleaf提供了一些內建物件,可以讓我們直接使用,訪問一些請求資訊。
#request:
${#request.getContextPath()}
${#request.getAttribute("name")}
#session:
{#session.getAttribute("loginUser")}
{#session.id}
3.4.5 工具物件
工具物件可以幫助我們格式化一樣資料,簡單的處理一資料。
- #dates:java.util.Date物件的實用方法,<span th:text="${#dates.format(curDate,'yyyy-MM-dd HH:mm:ss')}"></span>
- #calendars:和dates類似,但是是java.util.Calendar物件。
- #numbers:格式化資料物件的實用方法。
- #strings:字串物件的實用方法。contains,startsWith,prepending/appending等。
- #objects:對objects操作的實用方法。
- #bools:對布林值求值的實用方法。
- #arrays:陣列的實用方法。
- #lists:list的實用方法.
- #sets:set的實用方法.
- #maps:map的實用方法
- #aggregates:對陣列或集合建立聚合的實用方法。
3.4.6 thymeleaf模板片段與佈局頁
1. 模板片段:可以讓我們引入一個寫好的html片段,相當於jsp:include功能了,比如頭部和尾部我們都一樣就可以複用,也可以引入一個頁面當做layout佈局頁,以後的頁面都使用這個模板。
我們可以使用th:fragment來定義一個模板,使用th:insert、th:replace、th:include來替換模板。
其中:
- th:insert 3.0+版本新加的。
- th:replace 2.0+ 3.0+都可用。
- th:include 這個在3.0版本已經不建議使用。
這三個命令的語法格式為templatename::[domselector]。
我們先新增模板fragment/footer.html:
<html xmlns:th="http://www.thymeleaf.org"> <body> <span th:fragment="copyright">© 2019 <strong>xxx公司</strong></span> </body> </html>
home/index.html引用模板:
<!--th:include--> <div th:include="fragment/footer :: copyright"></div> <!--th:replace 直接替換--> <div th:replace="fragment/footer :: copyright"></div> <!--th:insert 把html插入到內部--> <div th:insert="fragment/footer :: copyright"></div>
三個命令生成html結構如下,稍微有些不一樣:
2. 佈局頁:設定一個母版頁,其他頁面以這個頁面做為母版,有父類的意思。
首先需要添加布局包依賴:
<dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> <version>2.2.2</version> </dependency>
新增一個layout頁面(父頁面):
html程式碼:
<!DOCTYPE html> <html xmlns:layout="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <header>這是頭部</header> <div layout:fragment="content"></div> <footer>這是底部</footer> </body> </html>
新增一個子頁面,以這個_home.html為父頁面:
其中:layout:decorator="_layout/_home" 指明佈局頁的路徑,layout:fragment="content",指明要替換佈局頁中的位置。
html程式碼:
<!DOCTYPE html> <html lang="en" xmlns:layout="http://www.w3.org/1999/xhtml" layout:decorator="_layout/_home"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div layout:fragment="content"> 這是child頁內容 </div> </div> </body> </html>
輸出:
四、總結
這次介紹了web開發的基本流程、包括靜態檔案、模板引擎等,我們現在已經做好了web開發的準備工作,接下來就可以進行業務功能的編寫了,接下來我們會做一個簡單的CRUD來具體瞭解一下Web的基本流