1. 程式人生 > >SpringBoot起飛系列-Web開發(五)

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的基本流