【Java笔记+踩坑】SpringBoot——基础
??導航:
【黑馬Java筆記+踩坑匯總】JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外賣+SpringCloud/SpringCloudAlibaba+黑馬旅游+谷粒商城
目錄
1,SpringBoot簡介
1.0 SpringMvc回顧?
1.1 SpringBoot快速入門
1.1.1 開發步驟
1.1.2 SpringBoot 對比Spring
1.1.3 官網構建工程
1.1.4 SpringBoot工程打包啟動
1.2 SpringBoot概述
1.2.1 起步依賴
1.2.2 程序啟動
1.2.3 切換web服務器,由Tomcat切換成Jetty
2,配置文件
2.1 配置文件格式
2.1.1 環境準備
2.1.2 不同配置文件配置端口
2.1.3 三種配置文件的優先級
2.2 yaml配置文件介紹
2.2.1 概述
2.2.2 語法規則
2.2.3 常用配置、清理控制臺
2.3 yaml配置文件數據讀取
2.3.1 環境準備
2.3.2 三種讀取yaml配置數據的方式
2.4 多環境配置
2.4.1 yaml文件
2.4.2 properties文件
2.4.3 命令行啟動參數設置,修改端口、環境
2.4.4 maven和springboot多環境開發兼容
2.5 配置文件分類
2.5.1 概述
2.5.1 代碼演示
3,SpringBoot整合junit
3.0 回顧 Spring 整合 junit
3.1 環境準備
3.2 編寫測試類,@SpringBootTest
4,SpringBoot整合mybatis
4.1 回顧Spring整合Mybatis
4.2 SpringBoot整合mybatis
4.3 案例,整合ssm的書籍增刪改查項目
4.3.1 創建工程
4.3.2 代碼拷貝,@Mapper
4.3.3 配置文件
4.3.4 靜態資源
4.4 SpringBoot整合MyBatis-Plus回顧
5、SSMP整合綜合案例,Book增刪改查分頁
0.模塊創建
1.實體類開發,lombok
2.數據層開發——基礎CRUD
3.數據層開發——分頁功能制作
4.數據層開發——條件查詢功能制作
5.業務層開發
業務層快速開發(慎用)
6.表現層開發
7.表現層消息一致性處理
8.前后端聯通性測試
9.頁面基礎功能開發
F-1.列表功能(非分頁版)
F-2.添加功能
F-3.刪除功能
F-4.修改功能
10.業務消息一致性處理
11.頁面功能開發
F-5.分頁功能
F-6.刪除功能維護
F-7.條件查詢功能
1,SpringBoot簡介
1.0 SpringMvc回顧?
SpringBoot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化 Spring 應用的初始搭建以及開發過程。
使用了 Spring 框架后已經簡化了我們的開發。而 SpringBoot 又是對 Spring 開發進行簡化的,可想而知 SpringBoot 使用的簡單及廣泛性。
回顧 SpringMVC :
- 1.創建工程,并在 pom.xml 配置文件中配置所依賴的坐標,還可以導入jackson,JSON類型轉換
-  2.編寫 web3.0 的配置類 作為 web 程序,web3.0 的配置類不能缺少,而這個配置類還是比較麻煩的,代碼如下 
- 3.編寫 SpringMVC 的配置類
做到這只是將工程的架子搭起來。要想被外界訪問,最起碼還需要提供一個 Controller 類,在該類中提供一個方法。
- 4.編寫 Controller 類
從上面的 SpringMVC 程序開發可以看到,前三步都是在搭建環境,而且這三步基本都是固定的。SpringBoot 就是對這三步進行簡化了。接下來我們通過一個入門案例來體現 SpingBoot 簡化 Spring 開發。
1.1 SpringBoot快速入門
1.1.1 開發步驟
SpringBoot 開發起來特別簡單,分為如下幾步:
知道了 SpringBoot 的開發步驟后,接下來我們進行具體的操作
創建新模塊
- 點擊 + 選擇 New Module 創建新模塊
-  選擇 Spring Initializr ,用來創建 SpringBoot 工程 以前我們選擇的是 Maven ,今天選擇 Spring Initializr 來快速構建 SpringBoot 工程。而在 Module SDK 這一項選擇我們安裝的 JDK 版本。 
-  對 SpringBoot 工程進行相關的設置 我們使用這種方式構建的 SpringBoot 工程其實也是 Maven 工程,而該方式只是一種快速構建的方式而已。注意選擇的包是jar,不是war。java版本和jdk版本一致,包名跟組名寫一樣方便閱讀。 注意:打包方式這里需要設置為 Jar 
-  選中 Web,然后勾選 Spring Web 由于我們需要開發一個 web 程序,使用到了 SpringMVC 技術,所以按照下圖紅框進行勾選 
- 下圖界面不需要任何修改,直接點擊 Finish 完成 SpringBoot 工程的構建
經過以上步驟后就創建了如下結構的模塊,它會幫我們自動生成一個 Application 類,而該類一會再啟動服務器時會用到。
- 刪除選中的文件、目錄:
報錯解決:
如果maven模塊的pom圖標顯示不正常,就右鍵pom.xml,添加成Maven項目:
找不到插件 'org.springframework.boot:spring-boot-maven-plugin:':
手動導入版本,版本號與springboot一致:
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.7.3</version></plugin>注意:
在創建好的工程中不需要創建SpringConfig和SpringMvcConfig配置類
創建好的項目會自動生成其他的一些文件,而這些文件目前對我們來說沒有任何作用,所以可以將這些文件刪除。
可以刪除的目錄和文件如下:
- .mvn
- .gitignore
- HELP.md
- mvnw
- mvnw.cmd
所有文件介紹:
- \1. .gitignore:分布式版本控制系統git的配置文件,意思為忽略提交
- 在 .gitingore 文件中,遵循相應的語法,即在每一行指定一個忽略規則。 如:.log、/target/、.idea
- \2. mvnw:全名是maven wrapper的文件
- 它的作用是在maven-wrapper.properties文件中記錄你要使用的maven版本,當用戶執行mvnw clean 命令時,發現當前用戶的maven版本和期望的版本不一致,那么就下載期望的版本,然后用期望的版本來執行mvn命令,比如mvn clean命令。
- \3. mvn文件夾:存放mvnw相關文件
- 存放著maven-wrapper.properties和相關jar包以及名為MavenWrapperDownloader的java文件
- \4. mvn.cmd:執行mvnw命令的cmd入口
- 注:mvnw文件適用于Linux(bash),mv斜體樣式*nw.cmd適用于Windows 環境。
- \5. .iml文件:intellij idea的工程配置文件
- 里面包含當前project的一些配置信息,如模塊開發的相關信息,比如java組件,maven組件,插件組件等,還可能會存儲一些模塊路徑信息,依賴信息以及一些別的信息。
- \6. .idea文件夾:存放項目的配置信息
- 包括數據源,類庫,項目字符編碼,歷史記錄,版本控制信息等。
- \7. pom.xml:項目對象模型(核心重要)
- pom.xml主要描述了項目的maven坐標,依賴關系,開發者需要遵循的規則,缺陷管理系統,組織和licenses,以及其他所有的項目相關因素,是項目級別的配置文件。
創建 Controller
在 com.itheima.controller 包下創建 BookController ,代碼如下:
@RestController @RequestMapping("/books") public class BookController {@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println("id ==> "+id);return "hello , spring boot!";} }啟動服務器
運行 SpringBoot 工程不需要使用本地的 Tomcat 和 插件,只需要右鍵運行項目 com.itheima 包下的 Application 類,我們就可以在控制臺看出如下信息
啟動后修改配置:
如果報錯:找不到插件org.springframework.boot spring-boot-*maven*-plugin
進入C:\Users\用戶名.m2\repository
然后在這個文件夾下搜索spring-boot-maven-plugin,打開這個文件夾,里面都是版本號
選擇加入pom.xml即可:
進行測試
使用 Postman 工具來測試我們的程序
SpringBoot 是如何讓開發變簡單的呢?
我們代碼之所以能簡化,就是因為指定的父工程和 Spring Web 依賴實現的。
要研究這個問題,我們需要看看 Application 類和 pom.xml 都書寫了什么。先看看 Applicaion 類,該類內容如下:
@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} }這個類中的東西很簡單,就在類上添加了一個 @SpringBootApplication 注解,而在主方法中就一行代碼。我們在啟動服務器時就是執行的該類中的主方法。
再看看 pom.xml 配置文件中的內容,可以發現除了打包插件之外,引入的父工程、兩個依賴前綴都是spring-boot-starter
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!--指定了一個父工程,父工程中的東西在該工程中可以繼承過來使用--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.0</version></parent><groupId>com.itheima</groupId><artifactId>springboot_01_quickstart</artifactId><version>0.0.1-SNAPSHOT</version><!--JDK 的版本--><properties><java.version>8</java.version></properties><dependencies><!--該依賴就是我們在創建 SpringBoot 工程勾選的那個 Spring Web 產生的--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--這個是單元測試的依賴,我們現在沒有進行單元測試,所以這個依賴現在可以沒有--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><!--這個插件是在打包時需要的,而這里暫時還沒有用到--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>1.1.2 SpringBoot 對比Spring
做完 SpringBoot 的入門案例后,接下來對比一下 Spring 程序和 SpringBoot 程序。如下圖
-  坐標 Spring 程序中的坐標需要自己編寫,而且坐標非常多 SpringBoot 程序中的坐標是我們在創建工程時進行勾選自動生成的 
-  web3.0配置類 Spring 程序需要自己編寫這個配置類。這個配置類大家之前編寫過,肯定感覺很復雜 SpringBoot 程序不需要我們自己書寫 
-  配置類 Spring/SpringMVC 程序的配置類需要自己書寫。而 SpringBoot 程序則不需要書寫。 
注意:基于Idea的 Spring Initializr 快速構建 SpringBoot 工程時需要聯網。
1.1.3 官網構建工程
在入門案例中之所以能快速構建 SpringBoot 工程,是因為 Idea 使用了官網提供了快速構建 SpringBoot 工程的組件實現的。那如何在官網進行工程構建呢?通過如下步驟構建
進入SpringBoot官網
官網地址如下:
https://spring.io/projects/spring-boot進入到 SpringBoot 官網后拖到最下方就可以看到如下內容
然后點擊 Spring Initializr 超鏈接就會跳轉到如下頁面
這個頁面內容是不是感覺很眼熟的,這和我們使用 Idea 快速構建 SpringBoot 工程的界面基本相同。在上面頁面輸入對應的信息
選擇依賴
選擇 Spring Web 可以點擊上圖右上角的 ADD DEPENDENCIES... CTRL + B 按鈕,就會出現如下界面
生成工程
以上步驟完成后就可以生成 SpringBoot 工程了。在頁面的最下方點擊 GENERATE CTRL + 回車 按鈕生成工程并下載到本地,如下圖所示
打開下載好的壓縮包可以看到工程結構和使用 Idea 生成的一模一樣,如下圖
而打開 pom.xml 文件,里面也包含了父工程和 Spring Web 的依賴。
通過上面官網的操作,我們知道 Idea 中快速構建 SpringBoot 工程其實就是使用的官網的快速構建組件,那以后即使沒有 Idea 也可以使用官網的方式構建 SpringBoot 工程。
1.1.4 SpringBoot工程打包啟動
問題導入
以后我們和前端開發人員協同開發,而前端開發人員需要測試前端程序就需要后端開啟服務器,這就受制于后端開發人員。為了擺脫這個受制,前端開發人員嘗試著在自己電腦上安裝 Tomcat 和 Idea ,在自己電腦上啟動后端程序,這顯然不現實。
我們后端可以將 SpringBoot 工程打成 jar 包,該 jar 包運行不依賴于 Tomcat 和 Idea 這些工具也可以正常運行,只是這個 jar 包在運行過程中連接和我們自己程序相同的 Mysql 數據庫即可。這樣就可以解決這個問題,如下圖
打包
打包package前先clean是好習慣。
先終止當前運行的項目。由于我們在構建 SpringBoot 工程時已經在 pom.xml 中配置了spring-boot-maven-plugin插件
//spring-boot-maven-plugin插件打包時需要的 <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId> </plugin>所以我們只需要使用 Maven 的 package 指令打包就會在 target 目錄下生成對應的 Jar 包。
注意:該插件必須配置,不然打好的 jar 包也是有問題的。
啟動
進入 jar 包所在位置,地址欄輸入cmd回車,在 命令提示符 中輸入如下命令(將jar包名字改為自己的):
java -jar springboot_01_quickstart-0.0.1-SNAPSHOT.jar啟動jar包并覆蓋設置端口、 切換環境:
java –jar springboot.jar –-server.port=88 –-spring.profiles.active=test執行上述命令就可以看到 SpringBoot 運行的日志信息
然后postman發請求,可以看到命令行里輸出后端信息,postman展示響應信息。
非springboot的maven是不能用java -jar命令的。
1.2 SpringBoot概述
SpringBoot 是由Pivotal團隊提供的全新框架,其設計目的是用來簡化Spring應用的初始搭建以及開發過程。
大家已經感受了 SpringBoot 程序,回過頭看看 SpringBoot 主要作用是什么,就是簡化 Spring 的搭建過程和開發過程。
原始 Spring 環境搭建和開發存在以下問題:
- 配置繁瑣
- 依賴設置繁瑣
SpringBoot 程序優點恰巧就是針對 Spring 的缺點
- 自動配置。這個是用來解決 Spring 程序配置繁瑣的問題
- 起步依賴(簡化以來配置)。這個是用來解決 Spring 程序依賴設置繁瑣的問題
- 輔助功能(內置服務器,...)。我們在啟動 SpringBoot 程序時既沒有使用本地的 tomcat 也沒有使用 tomcat 插件,而是使用 SpringBoot 內置的服務器。
接下來我們來說一下 SpringBoot 的起步依賴
1.2.1 起步依賴
我們使用 Spring Initializr 方式創建的 Maven 工程的的 pom.xml 配置文件中自動生成了很多包含 starter 的依賴,如下圖
這些依賴就是啟動依賴,接下來我們探究一下他是如何實現的。
1.2.1.1 探索父工程
爺工程spring-boot-dependencies.pom里配置了各依賴插件的特定版本,因此我們只需要使用對應版本的springboot,在pom.xml里配置不含版本的插件或依賴,就可以繼承對應插件或依賴。
爺工程pom.xml查看:
從上面的文件中可以看到指定了一個父工程,我們ctrl+b進入到父工程,發現父工程中又指定了一個父工程,如下圖所示
再進入到該父工程中,在該工程中我們可以看到配置內容結構如下圖所示
上圖中的 properties 標簽中定義了各個技術軟件依賴的版本,避免了我們在使用不同軟件技術時考慮版本的兼容問題。
在 properties 中我們找 servlet 和 mysql 的版本如下圖
爺工程pom.xml里依賴管理標簽:
dependencyManagement 標簽是進行依賴版本鎖定,但是并沒有導入對應的依賴。
如果我們工程需要哪個依賴只需要引入依賴的 groupid 和 artifactId 不需要定義 version。
爺工程pom.xml里插件管理:
而 build 標簽中也對插件的版本進行了鎖定,如下圖
看完了父工程中 pom.xml 的配置后不難理解我們工程的的依賴不配置 version的原因。
1.2.1.2 探索依賴
在我們創建的工程中的 pom.xml 中配置了spring-boot-starter-web如下依賴
進入到該依賴,查看 pom.xml 的依賴會發現它引入了如下的依賴
里面引入了 spring-web 和 spring-webmvc 的依賴,這就是為什么我們的工程中沒有依賴這兩個包還能正常使用 springMVC 中的注解的原因。
而依賴 spring-boot-starter-tomcat ,從名字基本能確認內部依賴了 tomcat,所以我們的工程才能正常啟動。
結論:以后需要使用技術,只需要引入該技術對應的起步依賴即可
同樣方法,spring-boot-starter-test依賴里有spring-test等依賴。
小結:
starter
- 只要依賴名字中有starter,就一定是起步以來。starter是SpringBoot 中常見項目名稱,定義了當前項目使用的所有項目坐標,以達到減少依賴配置的目的。
parent
- 所有 SpringBoot 項目要繼承的項目,定義了若干個坐標版本號(依賴管理,而非依賴),以達到減少依賴沖突的目的
- spring-boot-starter-parent(2.5.0)與 spring-boot-starter-parent(2.4.6)共計57處坐標版本不同。springboot版本也不是越新越好,實際開發中要看公司項目的spring-boot-starter-parent版本,然后使用對應的springboot版本。
實際開發
-  使用任意坐標時,僅書寫GAV中的G和A,V由SpringBoot提供 G:groupid A:artifactId V:version 
-  如發生坐標錯誤,再指定version(要小心版本沖突) 
1.2.2 程序啟動
創建的每一個 SpringBoot 程序時都包含一個類似于下面的類,我們將這個類稱作引導類、主啟動類
@SpringBootApplication public class Springboot01QuickstartApplication {public static void main(String[] args) {SpringApplication.run(Springboot01QuickstartApplication.class, args);} }注意:
-  SpringBoot 在創建項目時,采用jar的打包方式 
-  SpringBoot 的引導類是項目的入口,運行 main 方法就可以啟動項目 因為我們在 pom.xml 中配置了 spring-boot-starter-web 依賴,而該依賴通過前面的學習知道它依賴 tomcat ,所以運行 main 方法就可以使用 tomcat 啟動咱們的工程。 
1.2.3 切換web服務器,由Tomcat切換成Jetty
使用spring-boot-starter-web 依賴實現內置Tomcat服務器,是springboot帶來的輔助功能。
現在我們啟動工程使用的是 tomcat 服務器,那能不能不使用 tomcat 而使用 jetty 服務器。
jetty 在我們 maven 高級時講 maven 私服使用的服務器,比Tomcat更輕量級,可擴展性強,谷歌應用引擎已全面切換為Jetty,但目前大型應用一般用的還是Tomcat。
而要切換 web 服務器就需要使用 exclusion 標簽將默認的 tomcat 服務器給排除掉。
排除Tomcat依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions> </dependency>引入 jetty 的起步依賴:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jetty</artifactId> </dependency>接下來再次運行引導類,在日志信息中就可以看到使用的是 jetty 服務器
小結:
通過切換服務器,我們不難發現在使用 SpringBoot 換技術時只需要導入該技術的起步依賴即可。
2,配置文件
2.1 配置文件格式
我們現在啟動服務器默認的端口號是 8080,訪問路徑可以書寫為
http://localhost:8080/books/1在線上環境我們還是希望將端口號改為 80,這樣在訪問的時候就可以不寫端口號了,如下
http://localhost/books/1SpringBoot 提供了多種屬性配置方式
-  application.properties,常用,在resources包下 server.port=80
-  application.yml(以后用這種) server:port: 81
-  application.yaml server:port: 82
注意:SpringBoot 程序的配置文件名必須是 application ,只是后綴名不同而已。
2.1.1 環境準備
創建一個新工程 springboot_02_base_config 用來演示不同的配置文件,工程環境和入門案例一模一樣,結構如下:
在該工程中的 com.itheima.controller 包下創建一個名為 BookController 的控制器。內容如下:
@RestController @RequestMapping("/books") public class BookController {@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println("id ==> "+id);return "hello , spring boot!";} }2.1.2 不同配置文件配置端口
- 方法一(默認,不建議):application.properties配置文件
現在需要進行配置,配合文件必須放在 resources 目錄下,而該目錄下有一個名為 application.properties 的配置文件,我們就可以在該配置文件中修改端口號,在該配置文件中書寫 port ,Idea 就會提示,如下
application.properties 配置文件內容如下:
#端口號 server.port = 8888 #項目名,如果不設定,默認是 / server.servlet.context-path : /demo啟動服務,會在控制臺打印出日志信息,從日志信息中可以看到綁定的端口號已經修改了
- 方法二(以后使用):application.yml配置文件
刪除 application.properties 配置文件中的內容。在 resources 下創建一個名為 application.yml 的配置文件,在該文件中書寫端口號的配置項,格式如下:
server:#端口號port: 8888#項目名,如果不設定,默認是 /servlet:context-path: /demo注意: 在:后,數據前一定要加空格。
而在 yml 配置文件中也是有提示功能的,我們也可以在該文件中書寫 port ,然后 idea 就會提示并書寫成上面的格式
啟動服務,可以在控制臺看到綁定的端口號是 81
- 方法三(不建議):application.yaml配置文件
刪除 application.yml 配置文件和 application.properties 配置文件內容,然后在 resources 下創建名為 application.yaml 的配置文件,配置內容和后綴名為 yml 的配置文件中的內容相同,只是使用了不同的后綴名而已
application.yaml 配置文件內容如下:
server:port: 83啟動服務,在控制臺可以看到綁定的端口號
注意:在配置文件中輸入port,如果沒有提示,可以使用以下方式解決
- 點擊 File 選中 Project Structure
- 彈出如下窗口,按圖中標記紅框進行選擇
- 通過上述操作,會彈出如下窗口
- 點擊上圖的 + 號,彈出選擇該模塊的配置文件
- 通過上述幾步后,就可以看到如下界面。properties 類型的配合文件有一個,ymal 類型的配置文件有兩個
2.1.3 三種配置文件的優先級
結論:優先級properties>yml>yaml
在三種配合文件中分別配置不同的端口號,啟動服務查看綁定的端口號。用這種方式就可以看到哪個配置文件的優先級更高一些
application.properties 文件內容如下:
server.port=80application.yml 文件內容如下:
server:port: 81application.yaml 文件內容如下:
server:port: 82啟動服務,在控制臺可以看到使用的端口號是 80。說明 application.properties 的優先級最高
注釋掉 application.properties 配置文件內容。再次啟動服務,在控制臺可以看到使用的端口號是 81,說明 application.yml 配置文件為第二優先級。
從上述的驗證結果可以確定三種配置文件的優先級是:
application.properties > application.yml > application.yaml
注意:
-  SpringBoot 核心配置文件名為 application 
-  SpringBoot 內置屬性過多,且所有屬性集中在一起修改,在使用時,通過提示鍵+關鍵字修改屬性 例如要設置日志的級別時,可以在配置文件中書寫 logging,就會提示出來。配置內容如下 logging:level:root: info
2.2 yaml配置文件介紹
2.2.1 概述
properties 類型的配合文件之前我們學習過,接下來我們重點學習 yaml 類型的配置文件。
yaml格式擴展名:.yml(主流)或.yaml。
YAML(YAML Ain't Markup Language),一種數據序列化格式。這種格式的配置文件在近些年已經占有主導地位,那么這種配置文件和前期使用的配置文件是有一些優勢的,我們先看之前使用的配置文件。
最開始我們使用的是 xml ,格式如下:
<enterprise><name>itcast</name><age>16</age><tel>4006184000</tel> </enterprise>而 properties 類型的配置文件如下
enterprise.name=itcast enterprise.age=16 enterprise.tel=4006184000yaml 類型的配置文件內容如下
enterprise:name: itcastage: 16tel: 4006184000優點:
-  容易閱讀 yaml 類型的配置文件比 xml 類型的配置文件更容易閱讀,結構更加清晰 
-  容易與腳本語言交互 
-  以數據為核心,重數據輕格式,如下圖數據清爽 yaml 更注重數據,而 xml 更注重格式 
YAML 文件擴展名:
- .yml (主流)
- .yaml
上面兩種后綴名都可以,以后使用更多的還是 yml 的。
2.2.2 語法規則
-  大小寫敏感 
-  屬性層級關系使用多行描述,每行結尾使用冒號結束(這里冒號說的是標簽名后的冒號) 
-  使用縮進表示層級關系,同層級左側對齊,只允許使用空格(不允許使用Tab鍵) 空格的個數并不重要,只要保證同層級的左側對齊即可。 
-  屬性值前面添加空格(屬性名與屬性值之間使用冒號加空格作為分隔) 
-  #表示注釋 
核心規則:數據前面要加空格與冒號隔開
數組數據在數據書寫位置的下方使用減號作為數據開始符號,每行書寫一個數據,減號與數據間空格分隔,例如
enterprise:name: itcastage: 16tel: 4006184000subject:- Java- 前端- 大數據連接符---作用:單文件中可以通過---實現多文件的效果。
#開發 spring:profiles: dev #給開發環境起的名字 server:port: 80 --- #生產 spring:profiles: pro #給生產環境起的名字 server:port: 81 --- #測試 spring:profiles: test #給測試環境起的名字 server:port: 82 ---2.2.3 常用配置、清理控制臺
properties下新建logback.xml:
<?xml version="1.0" encoding="UTF-8"?> <configuration> </configuration> server:port: 80 spring:datasource:type: com.alibaba.druid.pool.DruidDataSourceurl: jdbc:mysql://localhost/ssm_db?serverTimezone=UTCusername: rootpassword: 填密碼driver-class-name: com.mysql.cj.jdbc.Drivermain:banner-mode: off mybatis-plus:global-config:db-config:table-prefix: tbl_ #關閉圖標banner: false #打開日志configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl2.3 yaml配置文件數據讀取
2.3.1 環境準備
新創建一個名為 springboot_03_read_data 的 SpringBoot 工程,目錄結構如下
在 com.itheima.controller 包寫創建名為 BookController 的控制器,內容如下
@RestController @RequestMapping("/books") public class BookController {@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println("id ==> "+id);return "hello , spring boot!";} }在 com.itheima.domain 包下創建一個名為 Enterprise 的實體類等會用來封裝數據,內容如下
public class Enterprise {private String name;private int age;private String tel;private String[] subject;//自己加上setter and getter,別忘了,別忘了,別忘了//toString }在 resources 下創建一個名為 application.yml 的配置文件,里面配置了不同的數據,內容如下
lesson: SpringBootserver:port: 80enterprise:name: itcastage: 16tel: 4006184000subject:- Java- 前端- 大數據2.3.2 三種讀取yaml配置數據的方式
2.3.2.1 使用 @Value注解讀取yaml(適合少量數據)
使用 @Value("表達式") 注解可以從配合文件中讀取數據,注解中用于讀取屬性名引用方式跟Spring里一樣,是:${一級屬性名.二級屬性名……}
這種方法和Spring讀取配置文件很像,不同點是Spring要讀取配置文件,要先在SpringConfig配置類掃描配置文件,例如@PropertySource("classpath:jdbc.properties")
我們可以在 BookController 中使用 @Value 注解讀取配合文件數據,如下
@RestController @RequestMapping("/books") public class BookController {@Value("${lesson}")private String lesson;@Value("${server.port}")private Integer port;@Value("${enterprise.subject[0]}")private String subject_00;@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println(lesson);System.out.println(port);System.out.println(subject_00);return "hello , spring boot!";} }2.3.2.2 自動注入Environment對象讀取yaml(少用,了解)
上面方式讀取到的數據特別零散,SpringBoot 還可以使用 @Autowired 注解注入 Environment 對象的方式讀取數據。這種方式 SpringBoot 會將配置文件中所有的數據封裝到 Environment 對象中,如果需要使用哪個數據只需要通過調用 Environment 對象的 getProperty(String name) 方法獲取。具體代碼如下:
@RestController @RequestMapping("/books") public class BookController {@Autowiredprivate Environment env;@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println(env.getProperty("lesson"));System.out.println(env.getProperty("enterprise.name"));System.out.println(env.getProperty("enterprise.subject[0]"));return "hello , spring boot!";} }注意:這種方式,框架內容大量數據,而在開發中我們很少使用。
2.3.2.3 自定義實體類bean讀取yaml(最常用),@ConfigurationProperties
SpringBoot 還提供了將配置文件中的數據封裝到我們自定義的實體類對象中的方式。具體操作如下:
-  將實體類 bean 的創建交給 Spring 管理。 在類上添加 @Component 注解 
-  使用 @ConfigurationProperties 注解表示加載配置文件 在該注解中也可以使用 prefix 屬性指定只加載指定前綴的數據 
-  在 BookController 中進行注入 
為什么這種方法最常用:
例如配置Mybatis時候,會定義一個實體類bean,加載yaml中的數據庫信息。
具體代碼如下:
Enterprise 實體類內容如下:實體類要有getter,setter,toString好習慣,防止報錯。
@Component //ConfigurationProperties譯為配置屬性,prefix前綴必須設為"enterprise",不加冒號,不能少字母。配置prefix后可以讀取到yaml中前綴為enterprise標簽的所有屬性。 //雖然prefix叫前綴,但它的意思是通過標簽名看成前綴。 @ConfigurationProperties(prefix = "enterprise") public class Enterprise {private String name;private int age;private String tel;private String[] subject;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getTel() {return tel;}public void setTel(String tel) {this.tel = tel;}public String[] getSubject() {return subject;}public void setSubject(String[] subject) {this.subject = subject;}@Overridepublic String toString() {return "Enterprise{" +"name='" + name + '\'' +", age=" + age +", tel='" + tel + '\'' +", subject=" + Arrays.toString(subject) +'}';} }BookController 內容如下:
@RestController @RequestMapping("/books") public class BookController {@Autowiredprivate Enterprise enterprise;@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println(enterprise.getName());System.out.println(enterprise.getAge());System.out.println(enterprise.getSubject());System.out.println(enterprise.getTel());System.out.println(enterprise.getSubject()[0]);return "hello , spring boot!";} }注意:
警告:使用第三種方式,在實體類上有如下警告提示
解決:這個警告提示解決是在 pom.xml 中添加如下依賴即可
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional> </dependency>為了加強管理第三方配置類,這種方式還可以優化:
?步驟①:在引導類上開啟@EnableConfigurationProperties注解,并標注要使用@ConfigurationProperties注解綁定屬性的類
@SpringBootApplication @EnableConfigurationProperties(ServerConfig.class) public class Springboot13ConfigurationApplication { }步驟②:在對應的類上直接使用@ConfigurationProperties進行屬性綁定
@Data @ConfigurationProperties(prefix = "servers") //這里不用加@component了 public class ServerConfig {private String ipAddress;private int port;private long timeout; }注意:
- 開啟了@EnableConfigurationProperties注解后,綁定屬性的ServerConfig類就不能聲明@Component注解,否則會被spring檢測到兩個bean。
當使用@EnableConfigurationProperties注解時,spring會默認將其標注的類定義為bean,因此不能再次聲明@Component注解了。
2.4 多環境配置
以后在工作中,對于開發環境、測試環境、生產環境的配置肯定都不相同,比如我們開發階段會在自己的電腦上安裝 mysql ,連接自己電腦上的 mysql 即可,但是項目開發完畢后要上線就需要該配置,將環境的配置改為線上環境的。
來回的修改配置會很麻煩,而 SpringBoot 給開發者提供了多環境的快捷配置,需要切換環境時只需要改一個配置即可。不同類型的配置文件多環境開發的配置都不相同,接下來對不同類型的配置文件進行說明
2.4.1 yaml文件
在 application.yml 中使用 --- 來分割不同的配置,內容如下
連接符---作用:單文件中可以通過---實現多文件的效果。
配置多個環境并設置啟動環境:
#設置啟用的環境 spring:profiles:active: dev #表示使用的是開發環境的配置--- #開發 spring:profiles: dev server:port: 80 --- #生產 spring:profiles: pro server:port: 81 --- #測試 spring:profiles: test server:port: 82 ---上面配置中 spring.profiles 是用來給不同的配置起名字的。
注意:
在上面配置中給不同配置起名字的 spring.profiles 配置項已經過時。最新用來起名字的配置項是
#開發 spring:config:activate:on-profile: dev2.4.2 properties文件
properties 類型的配置文件配置多環境需要另外定義不同的配置文件
-  application-dev.properties 是開發環境的配置文件。我們在該文件中配置端口號為 80 server.port=80
-  application-test.properties 是測試環境的配置文件。我們在該文件中配置端口號為 81 server.port=81
-  application-pro.properties 是生產環境的配置文件。我們在該文件中配置端口號為 82 server.port=82
SpringBoot 只會默認加載名為 application.properties 的配置文件,所以需要在 application.properties 配置文件中設置啟用哪個配置文件,配置如下:
spring.profiles.active=pro2.4.3 命令行啟動參數設置,修改端口、環境
使用 SpringBoot 開發的程序以后都是打成 jar 包,通過 java -jar xxx.jar 的方式啟動服務的。
命令行jar包切換環境:
注意: 命令行啟動參數都是臨時更改,不影響源代碼。
我們知道 jar 包其實就是一個壓縮包,可以解壓縮,然后修改配置,最后再打成jar包就可以了。這種方式顯然有點麻煩。
而 SpringBoot 提供了在運行 jar 時設置開啟指定的環境的方式,如下
java –jar xxx.jar –-spring.profiles.active=test命令行jar包修改端口:
那么這種方式能不能臨時修改端口號呢?也是可以的,可以通過如下方式
java –jar xxx.jar –-server.port=88命令行jar包同時修改環境和端口:
當然也可以同時設置多個配置,比如即指定啟用哪個環境配置,又臨時指定端口,如下
java –jar springboot.jar –-server.port=88 –-spring.profiles.active=test大家進行測試后就會發現命令行設置的端口號優先級高(也就是使用的是命令行設置的端口號),配置的優先級其實 SpringBoot 官網已經進行了說明 :
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config進入上面網站后會看到如下頁面
如果使用了多種方式配合同一個配置項,優先級高的生效。
2.4.4 maven和springboot多環境開發兼容
Maven和springboot都有profile環境配置,在實際開發中,應該maven為主,springboot為輔。springboot讀取maven多環境配置。
pom.xml
解析resources資源的插件maven-resources-plugin
配置多環境
application.yml
2.5 配置文件分類
2.5.1 概述
有這樣的場景,我們開發完畢后需要測試人員進行測試。
由于測試環境和開發環境的很多配置都不相同,所以測試人員在運行我們的工程時需要臨時修改很多配置,如下
java –jar springboot.jar –-spring.profiles.active=test --server.port=85 --server.servlet.context-path=/heima --server.tomcat.connection-timeout=-1 …… …… …… …… ……針對這種情況,SpringBoot 定義了配置文件不同的放置的位置;而放在不同位置的優先級時不同的。
SpringBoot 中4級配置文件放置位置:
- 1級:classpath:application.yml
- 2級:classpath:config/application.yml
- 3級:file :application.yml
- 4級:file :config/application.yml
說明:
- 級別越高優先級越高,file:config優先級最高
- 一二級classpath是為開發用的,三四級file是為打包后設置通用屬性用的。
- resources下config目錄里放配置文件
- classpath:是類路徑,在resources下,優先級高。
- file:是在包目錄下,這個目錄下創建config文件夾里放配置文件優先級最高。
2.5.1 代碼演示
在這里我們只演示不同級別配置文件放置位置的優先級。
2.5.1.1 環境準備
創建一個名為 springboot_06_config_file 的 SpringBoot 工程,目錄結構如下
在 resources 下創建一個名為 config 的目錄,在該目錄中創建 application.yml 配置文件,而在該配置文件中將端口號設置為 81,內容如下
server:port: 81而在 resources 下創建的 application.yml 配置文件中并將端口號設置為 80,內容如下
server:port: 802.5.1.2 驗證1級和2級的優先級
運行啟動引導類,可以在控制臺看到如下日志信息
通過這個結果可以得出類路徑下的 config 下的配置文件優先于類路徑下的配置文件。
2.5.1.3 驗證2級和4級的優先級
結論:file: config 下的配置文件優先于類路徑下的配置文件。
要驗證4級,按照以下步驟完成
-  將工程打成 jar 包 點擊工程的 package 來打 jar 包 
-  在硬盤上找到 jar 包所在位置 
-  在 jar 包所在位置創建 config 文件夾,在該文件夾下創建 application.yml 配置文件,而在該配合文件中將端口號設置為 82 
-  在命令行使用以下命令運行程序 java -jar springboot_06_config_file-0.0.1-SNAPSHOT.jar運行后日志信息如下 通過這個結果可以得出file: config 下的配置文件優先于類路徑下的配置文件。 
注意:
SpringBoot 2.5.0版本存在一個bug,我們在使用這個版本時,需要在 jar 所在位置的 config 目錄下創建一個任意名稱的文件夾
3,SpringBoot整合junit
3.0 回顧 Spring 整合 junit
回顧 Spring 整合 junit
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class UserServiceTest {@Autowiredprivate BookService bookService;@Testpublic void testSave(){bookService.save();} }使用 @RunWith 注解指定運行器,使用 @ContextConfiguration 注解來指定配置類或者配置文件。
而 SpringBoot 整合 junit 特別簡單,分為以下三步完成
- 在測試類上添加 SpringBootTest 注解
- 使用 @Autowired 注入要測試的資源
- 定義測試方法進行測試
在springboot中,@RunWith不用特別寫,springboot內部自己加上了。@ContextConfiguration加載SpringConfig也不用特別寫了,因為springboot的引導類起到了配置類的作用,這個類會把同位置下所有包掃描一遍,所以@Component的類才能加載成bean,測試類也就不用寫@ContextConfiguration加載SpringConfig了。
3.1 環境準備
創建一個名為 springboot_07_test 的 SpringBoot 工程,工程目錄結構如下
在 com.itheima.service 下創建 BookService 接口,內容如下
public interface BookService {public void save(); }在 com.itheima.service.impl 包寫創建一個 BookServiceImpl 類,使其實現 BookService 接口,內容如下
@Service public class BookServiceImpl implements BookService {@Overridepublic void save() {System.out.println("book service is running ...");} }3.2 編寫測試類,@SpringBootTest
實際上,整合很簡單,只有一步,包都不用再導, 直接給引導類同包下的測試類注解@SpringBootTest
在 test/java 下創建 com.itheima 包,在該包下創建測試類,將 BookService 注入到該測試類中
@SpringBootTest class Springboot07TestApplicationTests {@Autowiredprivate BookService bookService;@Testpublic void save() {bookService.save();} }注意:這里的引導類所在包必須是測試類所在包及其子包。
例如:
- 引導類所在包是 com.itheima
- 測試類所在包是 com.itheima
如果不滿足這個要求的話,就需要在使用 @SpringBootTest 注解時,使用 classes 屬性指定引導類的字節碼對象。如 @SpringBootTest(classes = Springboot07TestApplication.class)
4,SpringBoot整合mybatis
4.1 回顧Spring整合Mybatis
Spring 整合 Mybatis 需要定義很多配置類
-  SpringConfig 配置類 -  導入 JdbcConfig 配置類 
-  導入 MybatisConfig 配置類 @Configuration @ComponentScan("com.itheima") @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MyBatisConfig.class}) public class SpringConfig { }
 
-  
-  JdbcConfig 配置類 -  定義數據源(加載properties配置項:driver、url、username、password) public class JdbcConfig {@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String userName;@Value("${jdbc.password}")private String password;@Beanpublic DataSource getDataSource(){DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;} }
 
-  
-  MybatisConfig 配置類 -  定義 SqlSessionFactoryBean 
-  定義映射配置 public class MybatisConfig {@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setTypeAliasesPackage("package1.pojo");return factoryBean;}@Beanpublic MapperScannerConfigurer mapperScannerConfigurer(){MapperScannerConfigurer msc=new MapperScannerConfigurer();msc.setBasePackage("package1.dao");return msc;} }
 
-  
4.2 SpringBoot整合mybatis
兩個關鍵步驟:@Mapper和yml配置數據源
- 在dao接口@Mapper或引導類@MapperScan,類同于ssm中MybatisConfig的mapper掃描包。
- 導入druid依賴、在application.yml中配置數據源dataSource。
4.2.1 創建模塊
- 創建新模塊,選擇 Spring Initializr,并配置模塊相關基礎信息
-  選擇當前模塊需要使用的技術集(MyBatis、MySQL)。如果需要寫controller層則再添加Web里的Spring Web,或者在pom.xml導入依賴spring-boot-starter-web 
4.2.2 定義實體類
在 com.itheima.domain 包下定義實體類 Book,內容如下
public class Book {private Integer id;private String name;private String type;private String description;//自己生成setter and getter,別忘了,別忘了,別忘了,別忘了,別忘了,別忘了,//toString }4.2.3 定義dao接口
在 com.itheima.dao 包下定義 BookDao 接口,內容如下
或者可以在引導類掃描@MapperScan
//@Repository //BookDao是接口無實現類,不定義成bean也能在Service自動注入 @Mapper public interface BookDao {@Select("select * from tbl_book where id = #{id}")public Book getById(Integer id); }4.2.4 定義測試類
在 test/java 下定義包 com.itheima ,在該包下測試類,內容如下
@SpringBootTest class Springboot08MybatisApplicationTests {@Autowiredprivate BookDao bookDao;@Testvoid testGetById() {Book book = bookDao.getById(1);System.out.println(book);} }4.2.5 編寫配置
我們代碼中并沒有指定連接哪兒個數據庫,用戶名是什么,密碼是什么。所以這部分需要在 SpringBoot 的配置文件中進行配合。
?application.yml?
spring:datasource:#mysql6以后必須driver-class-name中間加cj,url設置時區,否則會報錯driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTCusername: rootpassword: rootcom.mysql.jdbc.Driver與com.mysql.cj.jdbc.Driver的區別:
- JDBC連接Mysql5需用com.mysql.jdbc.Driver
- JDBC連接Mysql6需用com.mysql.cj.jdbc.Driver,同時url需要指定時區serverTimezone。
- 設定時區時,serverTimezone=UTC比中國時間早8個小時,若在中國,可設置serverTimezone=Asia/Shanghai
4.2.6 測試
運行測試方法,我們會看到如下錯誤信息
錯誤信息顯示在 Spring 容器中沒有 BookDao 類型的 bean。為什么會出現這種情況呢?
原因是 Mybatis 會掃描接口并創建接口的代碼對象交給 Spring 管理,但是現在并沒有告訴 Mybatis 哪個是 dao 接口。而我們要解決這個問題需要在BookDao 接口上使用 @Mapper。
BookDao 接口加上@Mapper注解或者引導類加@MapperScan:
@Mapper //替代MybatisConfig里的MapperScannerConfigurer方法,也就是Mybatis核心配置文件的<mappers>標簽里的掃描mapper包 public interface BookDao {@Select("select * from tbl_book where id = #{id}")public Book getById(Integer id); }注意:
SpringBoot 版本低于2.4.3(不含),Mysql驅動版本大于8.0時,需要在url連接串中配置時區 jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC,或在MySQL數據庫端配置時區解決此問題
4.2.6.5 配置內置數據源、運行引導類
application.yml
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_dbusername: rootpassword: root此時運行引導類,項目就已經能跑起來了,不過實際開發中更多的是使用druid數據源。
4.2.7 使用Druid數據源
現在我們并沒有指定數據源,SpringBoot 有默認的數據源,我們也可以指定使用 Druid 數據源,按照以下步驟實現
-  導入 Druid 依賴 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version> </dependency>
-  在 application.yml 配置文件配置 可以通過 spring.datasource.type 來配置使用什么數據源。配置文件內容可以改進為 spring:datasource: #druid建議driver設成com.mysql.cj.jdbc.Driverdriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_dbusername: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSource
如果spring-boot-starter-parent版本是2.4.3 以前,在url后面加上?serverTimezone=UTC,否則會報錯:
spring:datasource: #druid建議driver設成com.mysql.cj.jdbc.Driverdriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTCusername: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSource4.3 案例,整合ssm的書籍增刪改查項目
SpringBoot 到這就已經學習完畢,接下來我們將學習 SSM 時做的三大框架整合的案例用 SpringBoot 來實現一下。我們完成這個案例基本是將之前做的拷貝過來,修改成 SpringBoot 的即可,主要從以下幾部分完成
pom.xml
配置起步依賴,必要的資源坐標(druid)
application.yml
設置數據源、端口等
配置類
全部刪除
dao
設置@Mapper
測試類
頁面
放置在resources目錄下的static目錄中
4.3.1 創建工程
創建 SpringBoot 工程,在創建工程時需要勾選 web、mysql、mybatis,工程目錄結構如下
由于我們工程中使用到了 Druid ,所以需要導入 Druid 的坐標
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version> </dependency>4.3.2 代碼拷貝,@Mapper
將上一節整合ssm的項目, springmvc_11_page 工程中的 java 代碼及測試代碼連同包拷貝到 springboot_09_ssm 工程,按照下圖進行拷貝
需要修改的內容如下:
-  Springmvc_11_page 中 config 包下的是配置類,而 SpringBoot 工程不需要這些配置類,所以這些可以直接刪除 
-  dao 包下的接口上在拷貝到 springboot_09-ssm 工程中需要在接口中添加 @Mapper 注解 
-  BookServiceTest 測試類需要加@SpringBootTest注解,改成 SpringBoot 整合 junit 的 @SpringBootTest public class BookServiceTest {@Autowiredprivate BookService bookService;@Testpublic void testGetById(){Book book = bookService.getById(2);System.out.println(book);}@Testpublic void testGetAll(){List<Book> all = bookService.getAll();System.out.println(all);} }
另外還需要修改配置文件。
controller包下攔截器interceptor失效,因為以前需要SpringMvcConfig實現WebMvcConfigurer 接口;
因為沒有了ServletConfig,springmvc也就不會攔截資源,也就不用放行靜態資源了
SpringMvcConfig回顧:
@Configuration //package1.config主要為了掃描項目攔截器類、ServletContainersInitConfig類 @ComponentScan({"package1.controller","package1.config"}) @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInterception projectInterception;//添加攔截器,配置本地資源映射路徑,在訪問A(虛擬的)的時候,需要到B(實際的)的位置去訪問。@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInterception).addPathPatterns("/books","/books/*");//如果只攔截/books,發送http://localhost/books/100后會發現攔截器沒有被執行//registry.addInterceptor(projectInterceptor).addPathPatterns("/books");}//添加資源處理器@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");} }4.3.3 配置文件
在 application.yml 配置文件中需要配置如下內容
- 服務的端口號
- 連接數據庫的信息
- 數據源
4.3.4 靜態資源
在 SpringBoot 程序中是沒有 webapp 目錄的,那么在 SpringBoot 程序中靜態資源需要放在什么位置呢?
靜態資源需要放在 resources 下的 static 下,如下圖所示
另外配置一個index.html,實現直接http://localhost/即可訪問books列表:
然后運行引導類,先輸入http://localhost/books測試后端,再用postman測試所有功能,完成。
4.4 SpringBoot整合MyBatis-Plus回顧
具體整合看下面文章的入門案例:
MyBatisPlus基礎_vincewm的博客-CSDN博客
步驟①:導入對應的starter
<!--mybatis和mysql依賴勾選自動生成--> <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version> </dependency> <dependencies><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency> </dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>關于這個坐標,此處要說明一點,之前我們看的starter都是spring-boot-starter-???,也就是說都是下面的格式
Spring-boot-start-***而MyBatis與MyBatisPlus這兩個坐標的名字書寫比較特殊,是第三方技術名稱在前,boot和starter在后。
springboot依賴命名規范:
| 官方提供 | spring-boot-starter-技術名稱 | spring-boot-starter-web spring-boot-starter-test | 
| 第三方提供 | 第三方技術名稱-spring-boot-starter | mybatis-spring-boot-starter druid-spring-boot-starter | 
| 第三方提供 | 第三方技術名稱-boot-starter(第三方技術名稱過長,簡化命名) | mybatis-plus-boot-starter | 
溫馨提示
創建項目時勾選里是沒有mybatisplus的,因為SpringBoot官網還未收錄此坐標。
步驟②:配置數據源相關信息
#2.配置相關信息 spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_dbusername: rootpassword: root步驟3:映射接口(Dao)
@Mapper public interface BookDao extends BaseMapper<Book> { }核心在于Dao接口繼承了一個BaseMapper的接口,這個接口中幫助開發者預定了若干個常用的API接口,簡化了通用API接口的開發工作。
下面就可以寫一個測試類進行測試了,此處省略。
溫馨提示
目前數據庫的表名定義規則是tbl_模塊名稱,為了能和實體類相對應,需要實體類注解@TableName("表名"),或者配置application.yml文件,添加如下配置即可,設置所有表名的通用前綴名。
//注解了lombok的@Data會自動生成getter,setter,toString方法 @Data //一般數據庫表名tbl_user,這里注解@TableName("tbl_user"),就可以對應上表名,畢竟mp的語句里沒有指定表名,都是在數據庫中搜索和首字母小的的實體類名對應的表的。 @TableName("user") public class User {//設置主鍵自增策略為auto,mp默認自增策略是ASSIGN_ID,分布式、雪花算法。自增策略也可以在yml中全局配置。@TableId(type = IdType.AUTO)private Long id;private String name;//value屬性起別名,select設置該字段是否參與查詢,針對于一些密碼等隱私數據不希望被查出來@TableField(value = "password",select = false)private String password;private Integer age;private String tel;//exist屬性設置是否在數據庫中存在該字段@TableField(exist = false)private String online;//樂觀鎖注解版本,需要搭配樂觀攔截器@Versionprivate Integer version;//邏輯刪除,本質是更新,數據庫內該字段默認是0,通過標記為1來判定刪除。@TableLogicprivate Integer delete; }或者配置yml
mybatis-plus:global-config:db-config:table-prefix: tbl_ #設置所有表的通用前綴名稱為tbl_5、SSMP整合綜合案例,Book增刪改查分頁
主頁面
添加
刪除
修改
分頁
條件查詢
整體案例中需要采用的技術如下:
實體類開發————使用Lombok快速制作實體類
Dao開發————整合MyBatisPlus,制作數據層測試
Service開發————基于MyBatisPlus進行增量開發,制作業務層測試類
Controller開發————基于Restful開發,前后端開發協議制作,使用PostMan測試接口功能
頁面開發————基于VUE+ElementUI制作,前后端聯調,頁面數據處理,頁面消息處理
- 列表
- 新增
- 修改
- 刪除
- 分頁
- 查詢
項目異常處理————異常攔截器、業務和系統異常類
按條件查詢————頁面功能調整、Controller修正功能、Service修正功能
0.模塊創建
對于這個案例如果按照企業開發的形式進行應該制作后臺微服務,前后端分離的開發。
這個對初學的小伙伴要求太高了,咱們簡化一下。后臺做單體服務器,前端不使用前后端分離的制作了。
一個服務器即充當后臺服務調用,又負責前端頁面展示,降低學習的門檻。
模塊構建步驟:
pom.xml
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency> </dependencies>application.yml
server:port: 801.實體類開發,lombok
本案例對應的模塊表結構如下:
-- ---------------------------- -- Table structure for tbl_book -- ---------------------------- DROP TABLE IF EXISTS `tbl_book`; CREATE TABLE `tbl_book` (`id` int(11) NOT NULL AUTO_INCREMENT,`type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ---------------------------- -- Records of tbl_book -- ---------------------------- INSERT INTO `tbl_book` VALUES (1, '計算機理論', 'Spring實戰 第5版', 'Spring入門經典教程,深入理解Spring原理技術內幕'); INSERT INTO `tbl_book` VALUES (2, '計算機理論', 'Spring 5核心原理與30個類手寫實戰', '十年沉淀之作,手寫Spring精華思想'); INSERT INTO `tbl_book` VALUES (3, '計算機理論', 'Spring 5 設計模式', '深入Spring源碼剖析Spring源碼中蘊含的10大設計模式'); INSERT INTO `tbl_book` VALUES (4, '計算機理論', 'Spring MVC+MyBatis開發從入門到項目實戰', '全方位解析面向Web應用的輕量級框架,帶你成為Spring MVC開發高手'); INSERT INTO `tbl_book` VALUES (5, '計算機理論', '輕量級Java Web企業應用實戰', '源碼級剖析Spring框架,適合已掌握Java基礎的讀者'); INSERT INTO `tbl_book` VALUES (6, '計算機理論', 'Java核心技術 卷I 基礎知識(原書第11版)', 'Core Java 第11版,Jolt大獎獲獎作品,針對Java SE9、10、11全面更新'); INSERT INTO `tbl_book` VALUES (7, '計算機理論', '深入理解Java虛擬機', '5個維度全面剖析JVM,大廠面試知識點全覆蓋'); INSERT INTO `tbl_book` VALUES (8, '計算機理論', 'Java編程思想(第4版)', 'Java學習必讀經典,殿堂級著作!贏得了全球程序員的廣泛贊譽'); INSERT INTO `tbl_book` VALUES (9, '計算機理論', '零基礎學Java(全彩版)', '零基礎自學編程的入門圖書,由淺入深,詳解Java語言的編程思想和核心技術'); INSERT INTO `tbl_book` VALUES (10, '市場營銷', '直播就該這么做:主播高效溝通實戰指南', '成長為網紅的秘密都在書中'); INSERT INTO `tbl_book` VALUES (11, '市場營銷', '直播銷講實戰一本通', '和秋葉一起學系列網絡營銷書籍'); INSERT INTO `tbl_book` VALUES (12, '市場營銷', '直播帶貨:淘寶、天貓直播從新手到高手', '一本教你如何玩轉直播的書,10堂課輕松實現帶貨月入3W+');根據上述表結構,制作對應的實體類
實體類
public class Book {private Integer id;private String type;private String name;private String description; }實體類的開發可以自動通過工具手工生成get/set方法,然后覆蓋toString()方法,方便調試,等等。不過這一套操作書寫很繁瑣,有對應的工具可以幫助我們簡化開發,介紹一個小工具,lombok。
Lombok,一個Java類庫,提供了一組注解,簡化POJO實體類開發,SpringBoot目前默認集成了lombok技術,并提供了對應的版本控制,所以只需要提供對應的坐標即可,在pom.xml中添加lombok的坐標。
<dependencies><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency> </dependencies>使用lombok可以通過一個注解@Data完成一個實體類對應的getter,setter,toString,equals,hashCode等操作的快速添加
import lombok.Data; @Data public class Book {private Integer id;private String type;private String name;private String description; }到這里實體類就做好了,是不是比不使用lombok簡化好多,這種工具在Java開發中還有N多,后面遇到了能用的實用開發技術時,在不增加各位小伙伴大量的學習時間的情況下,盡量多給大家介紹一些。
總結
實體類制作
使用lombok簡化開發
- 導入lombok無需指定版本,由SpringBoot提供版本
- @Data注解
2.數據層開發——基礎CRUD
數據層開發本次使用MyBatisPlus技術,數據源使用前面學習的Druid,學都學了都用上。
步驟①:導入MyBatisPlus與Druid對應的starter,當然mysql的驅動不能少
<dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency> </dependencies>?spring-boot-starter-web和spring-boot-starter-test在創建springboot項目時已經勾選創建了:
步驟②:配置druid數據庫連接相關的數據源配置
server:port: 80spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTCusername: rootpassword: root步驟③:使用MyBatisPlus的標準通用接口BaseMapper加速開發,別忘了@Mapper和泛型的指定
@Mapper public interface BookDao extends BaseMapper<Book> { }步驟④:制作測試類測試結果,這個測試類制作是個好習慣,不過在企業開發中往往都為加速開發跳過此步,且行且珍惜吧
package com.itheima.dao;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.itheima.domain.Book; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest public class BookDaoTestCase {@Autowiredprivate BookDao bookDao;@Testvoid testGetById(){System.out.println(bookDao.selectById(1));}@Testvoid testSave(){Book book = new Book();book.setType("測試數據123");book.setName("測試數據123");book.setDescription("測試數據123");bookDao.insert(book);}@Testvoid testUpdate(){Book book = new Book();book.setId(17);book.setType("測試數據abcdefg");book.setName("測試數據123");book.setDescription("測試數據123");bookDao.updateById(book);}@Testvoid testDelete(){bookDao.deleteById(16);}@Testvoid testGetAll(){bookDao.selectList(null);} }配置id生成策略
MyBatisPlus技術默認的主鍵生成策略為雪花算法,生成的主鍵ID長度較大,和目前的數據庫設定規則不相符,需要配置一下使MyBatisPlus使用數據庫的主鍵生成策略。在application.yml中添加對應配置即可,具體如下
server:port: 80spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTCusername: rootpassword: rootmybatis-plus:global-config:db-config:table-prefix: tbl_ #設置表名通用前綴id-type: auto #設置主鍵id字段的生成策略為參照數據庫設定的策略,當前數據庫設置id生成策略為自增清理控制臺沒用日志
yml
mybatis-plus:global-config:banner: false spring:main:banner-mode: offresources下創建logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> </configuration>查看MyBatisPlus運行日志
在進行數據層測試的時候,因為基礎的CRUD操作均由MyBatisPlus給我們提供了,所以就出現了一個局面,開發者不需要書寫SQL語句了,這樣程序運行的時候總有一種感覺,一切的一切都是黑盒的,作為開發者我們啥也不知道就完了。如果程序正常運行還好,如果報錯了,這個時候就很崩潰,你甚至都不知道從何下手,因為傳遞參數、封裝SQL語句這些操作完全不是你開發出來的,所以查看執行期運行的SQL語句就成為當務之急。
SpringBoot整合MyBatisPlus的時候充分考慮到了這點,通過配置的形式就可以查閱執行期SQL語句,配置如下
mybatis-plus:global-config:db-config:table-prefix: tbl_id-type: autoconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl再來看運行結果,此時就顯示了運行期執行SQL的情況。
Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2c9a6717] was not registered for synchronization because synchronization is not active JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6ca30b8a] will not be managed by Spring ==> Preparing: SELECT id,type,name,description FROM tbl_book ==> Parameters: <== Columns: id, type, name, description <== Row: 1, 計算機理論, Spring實戰 第5版, Spring入門經典教程,深入理解Spring原理技術內幕 <== Row: 2, 計算機理論, Spring 5核心原理與30個類手寫實戰, 十年沉淀之作,手寫Spring精華思想 <== Row: 3, 計算機理論, Spring 5 設計模式, 深入Spring源碼剖析Spring源碼中蘊含的10大設計模式 <== Row: 4, 計算機理論, Spring MVC+MyBatis開發從入門到項目實戰, 全方位解析面向Web應用的輕量級框架,帶你成為Spring MVC開發高手 <== Row: 5, 計算機理論, 輕量級Java Web企業應用實戰, 源碼級剖析Spring框架,適合已掌握Java基礎的讀者 <== Row: 6, 計算機理論, Java核心技術 卷I 基礎知識(原書第11版), Core Java 第11版,Jolt大獎獲獎作品,針對Java SE9、10、11全面更新 <== Row: 7, 計算機理論, 深入理解Java虛擬機, 5個維度全面剖析JVM,大廠面試知識點全覆蓋 <== Row: 8, 計算機理論, Java編程思想(第4版), Java學習必讀經典,殿堂級著作!贏得了全球程序員的廣泛贊譽 <== Row: 9, 計算機理論, 零基礎學Java(全彩版), 零基礎自學編程的入門圖書,由淺入深,詳解Java語言的編程思想和核心技術 <== Row: 10, 市場營銷, 直播就該這么做:主播高效溝通實戰指南, 成長為網紅的秘密都在書中 <== Row: 11, 市場營銷, 直播銷講實戰一本通, 和秋葉一起學系列網絡營銷書籍 <== Row: 12, 市場營銷, 直播帶貨:淘寶、天貓直播從新手到高手, 一本教你如何玩轉直播的書,10堂課輕松實現帶貨月入3W+ <== Row: 13, 測試類型, 測試數據, 測試描述數據 <== Row: 14, 測試數據update, 測試數據update, 測試數據update <== Row: 15, -----------------, 測試數據123, 測試數據123 <== Total: 15其中清晰的標注了當前執行的SQL語句是什么,攜帶了什么參數,對應的執行結果是什么,所有信息應有盡有。
此處設置的是日志的顯示形式,當前配置的是控制臺輸出,當然還可以由更多的選擇,根據需求切換即可
總結
手工導入starter坐標(2個),mysql驅動(1個)
配置數據源與MyBatisPlus對應的配置
開發Dao接口(繼承BaseMapper)
制作測試類測試Dao功能是否有效
使用配置方式開啟日志,設置日志輸出方式為標準輸出即可查閱SQL執行日志
3.數據層開發——分頁功能制作
前面僅僅是使用了MyBatisPlus提供的基礎CRUD功能,實際上MyBatisPlus給我們提供了幾乎所有的基礎操作,這一節說一下如何實現數據庫端的分頁操作。
MyBatisPlus提供的分頁操作API如下:
@Test void testGetPage(){IPage page = new Page(2,5);bookDao.selectPage(page, null);System.out.println(page.getCurrent());System.out.println(page.getSize());System.out.println(page.getTotal());System.out.println(page.getPages());System.out.println(page.getRecords()); }其中selectPage方法需要傳入一個封裝分頁數據的對象,可以通過new的形式創建這個對象,當然這個對象也是MyBatisPlus提供的,別選錯包了。創建此對象時需要指定兩個分頁的基本數據
- 當前顯示第幾頁
- 每頁顯示幾條數據
可以通過創建Page對象時利用構造方法初始化這兩個數據。
IPage page = new Page(2,5);將該對象傳入到查詢方法selectPage后,可以得到查詢結果,但是我們會發現當前操作查詢結果返回值仍然是一個IPage對象,這又是怎么回事?
IPage page = bookDao.selectPage(page, null);原來這個IPage對象中封裝了若干個數據,而查詢的結果作為IPage對象封裝的一個數據存在的,可以理解為查詢結果得到后,又塞到了這個IPage對象中,其實還是為了高度的封裝,一個IPage描述了分頁所有的信息。下面5個操作就是IPage對象中封裝的所有信息了。
@Test void testGetPage(){IPage page = new Page(2,5);bookDao.selectPage(page, null);System.out.println(page.getCurrent()); //當前頁碼值System.out.println(page.getSize()); //每頁顯示數System.out.println(page.getTotal()); //數據總量System.out.println(page.getPages()); //總頁數System.out.println(page.getRecords()); //詳細數據 }到這里就知道這些數據如何獲取了,但是當你去執行這個操作時,你會發現并不像我們分析的這樣,實際上這個分頁功能當前是無效的。為什么這樣呢?這個要源于MyBatisPlus的內部機制。
對于MySQL的分頁操作使用limit關鍵字進行,而并不是所有的數據庫都使用limit關鍵字實現的,這個時候MyBatisPlus為了制作的兼容性強,將分頁操作設置為基礎查詢操作的升級版,你可以理解為IPhone6與IPhone6S-PLUS的關系。
基礎操作中有查詢全部的功能,而在這個基礎上只需要升級一下(PLUS)就可以得到分頁操作。所以MyBatisPlus將分頁操作做成了一個開關,你用分頁功能就把開關開啟,不用就不需要開啟這個開關。而我們現在沒有開啟這個開關,所以分頁操作是沒有的。這個開關是通過MyBatisPlus的攔截器的形式存在的,其中的原理這里不分析了,有興趣的小伙伴可以學習MyBatisPlus這門課程進行詳細解讀。具體設置方式如下:
定義MyBatisPlus攔截器并將其設置為Spring管控的bean
@Configuration public class MPConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;} }上述代碼第一行是創建MyBatisPlus的攔截器棧,這個時候攔截器棧中沒有具體的攔截器,第二行是初始化了分頁攔截器,并添加到攔截器棧中。如果后期開發其他功能,需要添加全新的攔截器,按照第二行的格式繼續add進去新的攔截器就可以了。
總結
4.數據層開發——條件查詢功能制作
除了分頁功能,MyBatisPlus還提供有強大的條件查詢功能。以往我們寫條件查詢要自己動態拼寫復雜的SQL語句,現在簡單了,MyBatisPlus將這些操作都制作成API接口,調用一個又一個的方法就可以實現各種條件的拼裝。這里給大家普及一下基本格式,詳細的操作還是到MyBatisPlus的課程中查閱吧。
下面的操作就是執行一個模糊匹配對應的操作,由like條件書寫變為了like方法的調用。
@Test void testGetBy(){QueryWrapper<Book> qw = new QueryWrapper<>();qw.like("name","Spring");bookDao.selectList(qw); }其中第一句QueryWrapper對象是一個用于封裝查詢條件的對象,該對象可以動態使用API調用的方法添加條件,最終轉化成對應的SQL語句。第二句就是一個條件了,需要什么條件,使用QueryWapper對象直接調用對應操作即可。比如做大于小于關系,就可以使用lt或gt方法,等于使用eq方法,等等,此處不做更多的解釋了。
這組API使用還是比較簡單的,但是關于屬性字段名的書寫存在著安全隱患,比如查詢字段name,當前是以字符串的形態書寫的,萬一寫錯,編譯器還沒有辦法發現,只能將問題拋到運行器通過異常堆棧告訴開發者,不太友好。
MyBatisPlus針對字段檢查進行了功能升級,全面支持Lambda表達式,就有了下面這組API。由QueryWrapper對象升級為LambdaQueryWrapper對象,這下就避免了上述問題的出現。
@Test void testGetBy2(){String name = "1";LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();lqw.like(Book::getName,name);bookDao.selectList(lqw); }為了便于開發者動態拼寫SQL,防止將null數據作為條件使用,MyBatisPlus還提供了動態拼裝SQL的快捷書寫方式。
@Test void testGetBy2(){String name = "1";LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();//if(name != null) lqw.like(Book::getName,name); //方式一:JAVA代碼控制lqw.like(name != null,Book::getName,name); //方式二:API接口提供控制開關bookDao.selectList(lqw); }其實就是個格式,沒有區別。關于MyBatisPlus的基礎操作就說到這里吧,如果這一塊知識不太熟悉的小伙伴建議還是完整的學習一下MyBatisPlus的知識吧,這里只是蜻蜓點水的用了幾個操作而已。
MyBatisPlus基礎_vincewm的博客-CSDN博客
總結
使用QueryWrapper對象封裝查詢條件
推薦使用LambdaQueryWrapper對象
所有查詢操作封裝成方法調用
查詢條件支持動態條件拼裝
5.業務層開發
業務層是組織業務邏輯功能,并根據業務需求,對數據持久層發起調用。目標是為了組織出符合需求的業務邏輯功能,至于調不調用數據層還真不好說,有需求就調用,沒有需求就不調用。
區分數據層和業務層:
業務層的方法名定義一定要與業務有關,例如登錄操作
login(String username,String password);而數據層的方法名定義一定與業務無關,是一定,不是可能,也不是有可能,例如根據用戶名密碼查詢
selectByUserNameAndPassword(String username,String password);我們在開發的時候是可以根據完成的工作不同劃分成不同職能的開發團隊的。比如一個哥們制作數據層,他就可以不知道業務是什么樣子,拿到的需求文檔要求可能是這樣的
接口:傳入用戶名與密碼字段,查詢出對應結果,結果是單條數據 接口:傳入ID字段,查詢出對應結果,結果是單條數據 接口:傳入離職字段,查詢出對應結果,結果是多條數據但是進行業務功能開發的哥們,拿到的需求文檔要求差別就很大
接口:傳入用戶名與密碼字段,對用戶名字段做長度校驗,4-15位,對密碼字段做長度校驗,8到24位,對密碼字段做特殊字符校驗,不允許存在空格,查詢結果為對象。如果為null,返回BusinessException,封裝消息碼INFO_LOGON_USERNAME_PASSWORD_ERROR你比較一下,能是一回事嗎?差別太大了,所以說業務層方法定義與數據層方法定義差異化很大,只不過有些入門級的開發者手懶或者沒有使用過公司相關的ISO標準化文檔而已。
代碼實現:
業務層接口:
public interface BookService {Boolean save(Book book);Boolean update(Book book);Boolean delete(Integer id);Book getById(Integer id);List<Book> getAll();IPage<Book> getPage(int currentPage,int pageSize); }業務層實現類如下,轉調數據層即可:
@Service public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Overridepublic Boolean save(Book book) {return bookDao.insert(book) > 0;}@Overridepublic Boolean update(Book book) {return bookDao.updateById(book) > 0;}@Overridepublic Boolean delete(Integer id) {return bookDao.deleteById(id) > 0;}@Overridepublic Book getById(Integer id) {return bookDao.selectById(id);}@Overridepublic List<Book> getAll() {return bookDao.selectList(null);}@Overridepublic IPage<Book> getPage(int currentPage, int pageSize) {IPage page = new Page(currentPage,pageSize);bookDao.selectPage(page,null);return page;} }別忘了對業務層接口進行測試,測試類如下:
@SpringBootTest public class BookServiceTest {@Autowiredprivate IBookService bookService;@Testvoid testGetById(){System.out.println(bookService.getById(4));}@Testvoid testSave(){Book book = new Book();book.setType("測試數據123");book.setName("測試數據123");book.setDescription("測試數據123");bookService.save(book);}@Testvoid testUpdate(){Book book = new Book();book.setId(17);book.setType("-----------------");book.setName("測試數據123");book.setDescription("測試數據123");bookService.updateById(book);}@Testvoid testDelete(){bookService.removeById(18);}@Testvoid testGetAll(){bookService.list();}@Testvoid testGetPage(){IPage<Book> page = new Page<Book>(2,5);bookService.page(page);System.out.println(page.getCurrent());System.out.println(page.getSize());System.out.println(page.getTotal());System.out.println(page.getPages());System.out.println(page.getRecords());}}總結
業務層快速開發(慎用)
其實MyBatisPlus技術不僅提供了數據層快速開發方案,業務層MyBatisPlus也給了一個通用接口,個人觀點不推薦使用,湊合能用吧,其實就是一個封裝+繼承的思想,代碼給出,實際開發慎用。
業務層接口快速開發
public interface IBookService extends IService<Book> {//添加非通用操作API接口 }業務層接口實現類快速開發,關注繼承的類需要傳入兩個泛型,一個是數據層接口,另一個是實體類。
@Service public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {@Autowiredprivate BookDao bookDao;//添加非通用操作API }如果感覺MyBatisPlus提供的功能不足以支撐你的使用需要(其實是一定不能支撐的,因為需求不可能是通用的),在原始接口基礎上接著定義新的API接口就行了,此處不再說太多了,就是自定義自己的操作了,但是不要和已有的API接口名沖突即可。
總結
6.表現層開發
終于做到表現層了,做了這么多都是基礎工作。其實你現在回頭看看,哪里還有什么SpringBoot的影子?前面1,2步就搞完了。繼續完成表現層制作吧,咱們表現層的開發使用基于Restful的表現層接口開發,功能測試通過Postman工具進行。
表現層接口如下:
@RestController @RequestMapping("/books") public class BookController2 {@Autowiredprivate IBookService bookService;@GetMappingpublic List<Book> getAll(){return bookService.list();}@PostMappingpublic Boolean save(@RequestBody Book book){return bookService.save(book);}@PutMappingpublic Boolean update(@RequestBody Book book){return bookService.modify(book);}@DeleteMapping("{id}")public Boolean delete(@PathVariable Integer id){return bookService.delete(id);}@GetMapping("{id}")public Book getById(@PathVariable Integer id){return bookService.getById(id);}//當前頁碼和每頁數量由前端傳@GetMapping("{currentPage}/{pageSize}")public IPage<Book> getPage(@PathVariable int currentPage,@PathVariable int pageSize){return bookService.getPage(currentPage,pageSize);} }在使用Postman測試時關注提交類型,對應上即可,不然就會報405的錯誤碼了。
普通GET請求
PUT請求傳遞json數據,后臺實用@RequestBody接收數據
GET請求傳遞路徑變量,后臺實用@PathVariable接收數據
總結
基于Restful制作表現層接口
- 新增:POST
- 刪除:DELETE
- 修改:PUT
- 查詢:GET
接收參數
- 實體數據:@RequestBody
- 路徑變量:@PathVariable
7.表現層消息一致性處理
目前我們通過Postman測試后業務層接口功能是通的,但是這樣的結果給到前端開發者會出現一個小問題。不同的操作結果所展示的數據格式差異化嚴重。
增刪改操作結果
true查詢單個數據操作結果
{"id": 1,"type": "計算機理論","name": "Spring實戰 第5版","description": "Spring入門經典教程" }查詢全部數據操作結果
[{"id": 1,"type": "計算機理論","name": "Spring實戰 第5版","description": "Spring入門經典教程"},{"id": 2,"type": "計算機理論","name": "Spring 5核心原理與30個類手寫實戰","description": "十年沉淀之作"} ]每種不同操作返回的數據格式都不一樣,而且還不知道以后還會有什么格式,這樣的結果讓前端人員看了是很容易讓人崩潰的,必須將所有操作的操作結果數據格式統一起來,需要設計表現層返回結果的模型類,用于后端與前端進行數據格式統一,也稱為前后端數據協議
@Data public class R {//完整形態應該把flag改integer型code,加上String的錯誤信息msg,再創建一個code類定義所有成功失敗的碼,private Boolean flag;private Object data; }其中flag用于標識操作是否成功,data用于封裝操作數據,現在的數據格式就變了
{"flag": true,"data":{"id": 1,"type": "計算機理論","name": "Spring實戰 第5版","description": "Spring入門經典教程"} }表現層開發格式也需要轉換一下
結果這么一折騰,全格式統一,現在后端發送給前端的數據格式就統一了,免去了不少前端解析數據的煩惱。
總結
設計統一的返回值結果類型便于前端開發讀取數據
返回值結果類型可以根據需求自行設定,沒有固定格式
返回值結果模型類用于后端與前端進行數據格式統一,也稱為前后端數據協議
8.前后端聯通性測試
后端的表現層接口開發完畢,就可以進行前端的開發了。
將前端人員開發的頁面保存到lresources目錄下的static目錄中,建議執行maven的clean生命周期,避免緩存的問題出現。
在進行具體的功能開發之前,先做聯通性的測試,通過頁面發送異步提交(axios),這一步調試通過后再進行進一步的功能開發。
//列表 getAll() {axios.get("/books").then((res)=>{console.log(res.data);}); },只要后臺代碼能夠正常工作,前端能夠在日志中接收到數據,就證明前后端是通的,也就可以進行下一步的功能開發了。
總結
9.頁面基礎功能開發
F-1.列表功能(非分頁版)
列表功能主要操作就是加載完數據,將數據展示到頁面上,此處要利用VUE的數據模型綁定,發送請求得到數據,然后頁面上讀取指定數據即可。
頁面數據模型定義
data:{dataList: [], //當前頁要展示的列表數據... },異步請求獲取數據
//列表 getAll() {axios.get("/books").then((res)=>{this.dataList = res.data.data;}); },這樣在頁面加載時就可以獲取到數據,并且由VUE將數據展示到頁面上了。
總結:
F-2.添加功能
添加功能用于收集數據的表單是通過一個彈窗展示的,因此在添加操作前首先要進行彈窗的展示,添加后隱藏彈窗即可。因為這個彈窗一直存在,因此當頁面加載時首先設置這個彈窗為不可顯示狀態,需要展示,切換狀態即可。
默認狀態
data:{dialogFormVisible: false, //添加表單是否可見... },切換為顯示狀態
//彈出添加窗口 handleCreate() {this.dialogFormVisible = true; },由于每次添加數據都是使用同一個彈窗錄入數據,所以每次操作的痕跡將在下一次操作時展示出來,需要在每次操作之前清理掉上次操作的痕跡。
定義清理數據操作
//重置表單 resetForm() {this.formData = {}; },切換彈窗狀態時清理數據
//彈出添加窗口 handleCreate() {this.dialogFormVisible = true;this.resetForm(); },至此準備工作完成,下面就要調用后臺完成添加操作了。
添加操作
//添加 handleAdd () {//發送異步請求axios.post("/books",this.formData).then((res)=>{//如果操作成功,關閉彈層,顯示數據if(res.data.flag){this.dialogFormVisible = false;this.$message.success("添加成功");}else {this.$message.error("添加失敗");}}).finally(()=>{this.getAll();}); },將要保存的數據傳遞到后臺,通過post請求的第二個參數傳遞json數據到后臺
根據返回的操作結果決定下一步操作
- 如何是true就關閉添加窗口,顯示添加成功的消息
- 如果是false保留添加窗口,顯示添加失敗的消息
無論添加是否成功,頁面均進行刷新,動態加載數據(對getAll操作發起調用)
取消添加操作
//取消 cancel(){this.dialogFormVisible = false;this.$message.info("操作取消"); },總結
F-3.刪除功能
模仿添加操作制作刪除功能,差別之處在于刪除操作僅傳遞一個待刪除的數據id到后臺即可。
刪除操作
// 刪除 handleDelete(row) {axios.delete("/books/"+row.id).then((res)=>{if(res.data.flag){this.$message.success("刪除成功");}else{this.$message.error("刪除失敗");}}).finally(()=>{this.getAll();}); },刪除操作提示信息
// 刪除 handleDelete(row) {//1.彈出提示框this.$confirm("此操作永久刪除當前數據,是否繼續?","提示",{type:'info'}).then(()=>{//2.做刪除業務axios.delete("/books/"+row.id).then((res)=>{if(res.data.flag){this.$message.success("刪除成功");}else{this.$message.error("刪除失敗");}}).finally(()=>{this.getAll();});}).catch(()=>{//3.取消刪除this.$message.info("取消刪除操作");}); },總結
F-4.修改功能
修改功能可以說是列表功能、刪除功能與添加功能的合體。幾個相似點如下:
頁面也需要有一個彈窗用來加載修改的數據,這一點與添加相同,都是要彈窗
彈出窗口中要加載待修改的數據,而數據需要通過查詢得到,這一點與查詢全部相同,都是要查數據
查詢操作需要將要修改的數據id發送到后臺,這一點與刪除相同,都是傳遞id到后臺
查詢得到數據后需要展示到彈窗中,這一點與查詢全部相同,都是要通過數據模型綁定展示數據
修改數據時需要將被修改的數據傳遞到后臺,這一點與添加相同,都是要傳遞數據
所以整體上來看,修改功能就是前面幾個功能的大合體
查詢并展示數據
修改操作
//修改 handleEdit() {axios.put("/books",this.formData).then((res)=>{//如果操作成功,關閉彈層并刷新頁面if(res.data.flag){this.dialogFormVisible4Edit = false;this.$message.success("修改成功");}else {this.$message.error("修改失敗,請重試");}}).finally(()=>{this.getAll();}); },總結
10.業務消息一致性處理
目前的功能制作基本上達成了正常使用的情況,什么叫正常使用呢?也就是這個程序不出BUG,如果我們搞一個BUG出來,你會發現程序馬上崩潰掉。比如后臺手工拋出一個異常,看看前端接收到的數據什么樣子。
{"timestamp": "2021-09-15T03:27:31.038+00:00","status": 500,"error": "Internal Server Error","path": "/books" }面對這種情況,前端的同學又不會了,這又是什么格式?怎么和之前的格式不一樣?
{"flag": true,"data":{"id": 1,"type": "計算機理論","name": "Spring實戰 第5版","description": "Spring入門經典教程"} }看來不僅要對正確的操作數據格式做處理,還要對錯誤的操作數據格式做同樣的格式處理。
首先在當前的數據結果中添加消息字段,用來兼容后臺出現的操作消息。
@Data public class R{//完整形態是flag換Integer型的狀態碼codeprivate Boolean flag;private Object data;private String msg; //用于封裝消息 }后臺代碼也要根據情況做處理,當前是模擬的錯誤。
@PostMapping public R save(@RequestBody Book book) throws IOException {Boolean flag = bookService.insert(book);return new R(flag , flag ? "添加成功^_^" : "添加失敗-_-!"); }然后在表現層做統一的異常處理,使用SpringMVC提供的異常處理器做統一的異常處理。
@RestControllerAdvice public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class)public R doOtherException(Exception ex){//記錄日志//發送消息給運維//發送郵件給開發人員,ex對象發送給開發人員ex.printStackTrace();return new R(false,null,"系統錯誤,請稍后再試!");} }頁面上得到數據后,先判定是否有后臺傳遞過來的消息,標志就是當前操作是否成功,如果返回操作結果false,就讀取后臺傳遞的消息。
//添加 handleAdd () {//發送ajax請求axios.post("/books",this.formData).then((res)=>{//如果操作成功,關閉彈層,顯示數據if(res.data.flag){this.dialogFormVisible = false;this.$message.success("添加成功");}else {this.$message.error(res.data.msg); //消息來自于后臺傳遞過來,而非固定內容}}).finally(()=>{this.getAll();}); },總結
11.頁面功能開發
F-5.分頁功能
分頁功能的制作用于替換前面的查詢全部,其中要使用到elementUI提供的分頁組件。
<!--分頁組件--> <div class="pagination-container"><el-paginationclass="pagiantion"@current-change="handleCurrentChange":current-page="pagination.currentPage":page-size="pagination.pageSize"layout="total, prev, pager, next, jumper":total="pagination.total"></el-pagination> </div>為了配合分頁組件,封裝分頁對應的數據模型。
data:{pagination: { //分頁相關模型數據currentPage: 1, //當前頁碼pageSize:10, //每頁顯示的記錄數total:0, //總記錄數} },修改查詢全部功能為分頁查詢,通過路徑變量傳遞頁碼信息參數。
getAll() {axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {}); },后臺提供對應的分頁功能。
@GetMapping("/{currentPage}/{pageSize}") public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){IPage<Book> pageBook = bookService.getPage(currentPage, pageSize);return new R(null != pageBook ,pageBook); }頁面根據分頁操作結果讀取對應數據,并進行數據模型綁定。
getAll() {axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {this.pagination.total = res.data.data.total;this.pagination.currentPage = res.data.data.current;this.pagination.pagesize = res.data.data.size;this.dataList = res.data.data.records;}); },對切換頁碼操作設置調用當前分頁操作。
//切換頁碼 handleCurrentChange(currentPage) {this.pagination.currentPage = currentPage;this.getAll(); },總結
F-6.刪除功能維護
由于使用了分頁功能,當最后一頁只有一條數據時,刪除操作就會出現BUG,最后一頁無數據但是獨立展示,對分頁查詢功能進行后臺功能維護,如果當前頁碼值大于最大頁碼值,重新執行查詢。其實這個問題解決方案很多,這里給出比較簡單的一種處理方案。
@GetMapping("{currentPage}/{pageSize}") public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){IPage<Book> page = bookService.getPage(currentPage, pageSize);//如果當前頁碼值大于了總頁碼值,那么重新執行查詢操作,使用最大頁碼值作為當前頁碼值if( currentPage > page.getPages()){page = bookService.getPage((int)page.getPages(), pageSize);}return new R(true, page); }F-7.條件查詢功能
最后一個功能來做條件查詢,其實條件查詢可以理解為分頁查詢的時候除了攜帶分頁數據再多帶幾個數據的查詢。這些多帶的數據就是查詢條件。比較一下不帶條件的分頁查詢與帶條件的分頁查詢差別之處,這個功能就好做了
-  頁面封裝的數據:帶不帶條件影響的僅僅是一次性傳遞到后臺的數據總量,由傳遞2個分頁相關數據轉換成2個分頁數據加若干個條件 
-  后臺查詢功能:查詢時由不帶條件,轉換成帶條件,反正不帶條件的時候查詢條件對象使用的是null,現在換成具體條件,差別不大 
-  查詢結果:不管帶不帶條件,出來的數據只是有數量上的差別,其他都差別,這個可以忽略 經過上述分析,看來需要在頁面發送請求的格式方面做一定的修改,后臺的調用數據層操作時發送修改,其他沒有區別。 頁面發送請求時,兩個分頁數據仍然使用路徑變量,其他條件采用動態拼裝url參數的形式傳遞。 頁面封裝查詢條件字段 pagination: { //分頁相關模型數據currentPage: 1, //當前頁碼pageSize:10, //每頁顯示的記錄數total:0, //總記錄數name: "",type: "",description: "" },頁面添加查詢條件字段對應的數據模型綁定名稱 <div class="filter-container"><el-input placeholder="圖書類別" v-model="pagination.type" class="filter-item"/><el-input placeholder="圖書名稱" v-model="pagination.name" class="filter-item"/><el-input placeholder="圖書描述" v-model="pagination.description" class="filter-item"/><el-button @click="getAll()" class="dalfBut">查詢</el-button><el-button type="primary" class="butT" @click="handleCreate()">新建</el-button> </div>將查詢條件組織成url參數,添加到請求url地址中,這里可以借助其他類庫快速開發,當前使用手工形式拼接,降低學習要求 getAll() {//1.獲取查詢條件,拼接查詢條件param = "?name="+this.pagination.name;param += "&type="+this.pagination.type;param += "&description="+this.pagination.description;console.log("-----------------"+ param);axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res) => {this.dataList = res.data.data.records;}); },后臺代碼中定義實體類封查詢條件 @GetMapping("{currentPage}/{pageSize}") public R getAll(@PathVariable int currentPage,@PathVariable int pageSize,Book book) {System.out.println("參數=====>"+book);IPage<Book> pageBook = bookService.getPage(currentPage,pageSize);return new R(null != pageBook ,pageBook); }對應業務層接口與實現類進行修正 public interface IBookService extends IService<Book> {IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook); } @Service public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {public IPage<Book> getPage(Integer currentPage,Integer pageSize,Book queryBook){IPage page = new Page(currentPage,pageSize);LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();lqw.like(Strings.isNotEmpty(queryBook.getName()),Book::getName,queryBook.getName());lqw.like(Strings.isNotEmpty(queryBook.getType()),Book::getType,queryBook.getType());lqw.like(Strings.isNotEmpty(queryBook.getDescription()),Book::getDescription,queryBook.getDescription());return bookDao.selectPage(page,lqw);} }頁面回顯數據 getAll() {//1.獲取查詢條件,拼接查詢條件param = "?name="+this.pagination.name;param += "&type="+this.pagination.type;param += "&description="+this.pagination.description;console.log("-----------------"+ param);axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res) => {this.pagination.total = res.data.data.total;this.pagination.currentPage = res.data.data.current;this.pagination.pagesize = res.data.data.size;this.dataList = res.data.data.records;}); },
總結
總結
以上是生活随笔為你收集整理的【Java笔记+踩坑】SpringBoot——基础的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: “云计算”技术首次引入呼叫中心领域
- 下一篇: 使用ThinkPad T61有感
