賀!此系列文榮獲 2023 iThome 鐵人賽《優選》獎項,正在規劃出書中,感謝大家的支持🙏,同名課程「Java 工程師必備!Spring Boot 零基礎入門」也已在 Hahow 平台上架
哈囉大家好,我是古古
在上兩篇文章中,我們有介紹了 Spring JDBC 的兩個核心用法 update()
和 query()
,因此大家就可以透過這兩個方法,在 Spring Boot 中執行想要執行的 sql 語法了!
而在介紹完 Spring JDBC 的核心用法之後,接著這篇文章要介紹的,是軟體工程中一個很重要的概念,即是「MVC 架構模式」
在介紹什麼是「MVC 架構模式」之前,我們可以先來看一下,「軟體工程」到底是個什麼樣的概念
所謂的軟體工程,即是「在面對一個 大型的系統 時,工程師們要 如何分工合作,一起去解決問題?」,在這句話裡面有兩個重點,分別是「大型的系統」和「如何分工合作」
所以簡單的說的話,當你今天要寫的是一個超過一兩千行的程式,並且你們的團隊中,是有好幾位工程師一起分工合作,在這種情況下,就會開始需要去注重 「軟體工程」
補充:當然小型的系統也可以注重軟體工程,不過效益相對不會那麼大
大概了解了軟體工程的概念之後,我們可以先來看一下「MVC 架構模式」的概念是什麼,然後再接著來介紹,要如何在 Spring Boot 中去套用 MVC 架構模式的概念
所謂的「MVC 架構模式」,他是軟體工程中的一種軟體架構,而 MVC 架構模式的用途,就是將一個系統,去拆分成「Model、View、Controller」三個部分,並且讓每一個部分都各自負責不同的功能
上面這一張圖看起來可能有點抽象,不過其實 MVC 架構模式的概念很簡單,他就只是「想要去把我們所寫的程式分個類」而已
譬如說你今天寫的這段程式,他可能是屬於 Model 的部分,又或是你寫的這段程式,他是被分類到 Controller 的部分,僅此而已,MVC 架構模式並不會添加什麼新功能到你的程式裡面
而 MVC 架構模式之所以被稱為是 MVC,原因就是取自於 Model-View-Controller 這三種分類的第一個字母的縮寫,因此這種架構模式,才被稱為是 MVC 架構模式
在 MVC 架構模式中,Model 所負責的,是「實作業務邏輯,並且處理數據」
也因為 Model 是負責處理數據,因此 Model 會需要去跟資料庫做溝通,將這些數據的改動給儲存起來
因此 Model 算是在 MVC 的架構中,最重要的一個部分,因為他實際上就是負責去處理數據,所以我們都會將核心的業務邏輯,寫在 Model 這個部分裡面
在 MVC 架構模式中,Controller 所負責的,是「轉發 Http request」
所以簡單的說的話,當 Controller 收到來自前端的 Http request 之後,Controller 就會負責將這些 request,去轉發給 Model,讓 Model 去處理後續的操作
在 MVC 架構模式中,View 所負責的,是「使用 Html 的模板去呈現數據」
不過因為近幾年提倡「前後端分離」的關係,所以版面設計就都會交給前端處理,因此在後端這裡,就不需要處理 Html 的版面部分,改成是使用 Json 格式來傳遞數據給前端,因此 View 這部分,相對來說就變得越來越不重要
當我們使用了 MVC 架構模式,將我們所寫的後端程式,去區分成 Model-View-Controller 這三個部分的話,可以得到以下幾個好處:
了解了 MVC 架構模式的運作方式和優點之後,接著我們可以來看一下,要如何在 Spring Boot 中,去套用這個 MVC 架構模式的概念
補充:MVC 架構模式其實是一個比較抽象的概念,具體要怎麼實作,就會依照不同的框架,而有不同寫法
在 Spring Boot 裡面,我們會將 MVC的架構模式,去轉化成是 「Controller-Service-Dao 的三層式架構」 來實作
因此大家以後只要在 Spring Boot 中看到「Controller-Service-Dao」這種三層式架構時,就可以知道他是套用了 MVC 的架構模式在設計了
在 Controller-Service-Dao 的三層式架構中,其實就是將 Spring Boot 程式,去分成了Controller、Service、以及 Dao 這三層來管理,讓每一層都去負責不同的功能
像是在下圖中,就呈現了 Controller、Service、Dao 這三層架構之間的關係,以及他們個別負責的功能
Controller 層的用途,是負責去 「接收前端傳過來的 Http request,並且去驗證請求參數」
所以像是我們在 Spring MVC 中所介紹的那些註解 @RequestMapping
、@RequestParam
...等等,舉凡是和「前端」進行溝通的部分,就通通會放在 Controller 層裡面
而當 Controller 層接收到前端傳過來的 Http request、並且對其驗證之後,這時候Controller 就會去 call Service層,讓 Service 負責去接手後續的處理
Service 層的用途,主要是負責 「商業邏輯的處理」,而 Service 層在處理商業邏輯的過程中,Service 層會再去 call Dao這一層
Dao 這一層所負責的功能,就是 「專門去和資料庫進行溝通的」,所以換句話說的話,Dao 這一層,就會透過 sql 語法,去操作資料庫,進而去查詢/修改資料庫中的數據
因此我們在 Spring JDBC 中所介紹的所有用法,舉凡只要是和「資料庫」溝通的部分,就通通是會放在 Dao 層裡面
補充:Dao 層是 Data access object 的縮寫
所以透過上面的 Controller-Service-Dao 的三層式架構的設計,就可以將 Spring Boot 中的程式,依照不同的功能,為他放在不同的層級中
因此我們之後就可以去透過 Controller-Service-Dao 的三層式架構,更好的去管理和維護 Spring Boot 的程式了!
在我們以前沒有 Controller-Service-Dao 三層式架構的概念時,我們所寫出來的 Spring Boot 程式會是下面這樣的
即是將取得前端參數的 @GetMapping
功能,以及去和資料庫溝通的 namedParameterJdbcTemplate
功能,全部放在同一個 class 中去實作,這樣子雖然同樣可以完成功能,但是在後續的管理和維護上,就會比較吃力
而當我們將上面的程式,改成是使用 Controller-Service-Dao 的三層式架構的話,就可變成下面這樣的寫法
當我們套用了 Controller-Service-Dao 的三層式架構之後,會將上面的程式,去拆分成是「3 個 class」來負責
首先是第一個 class 是 StudentController,因為這個 class 的名字是以 Controller 為結尾,因此他是代表 Controller 層,負責去處理和前端的溝通
在 StudentController 裡面,我們只保留 @GetMapping
和 @PathVariable
的部分,使用 Spring MVC 的功能,去和前端溝通,取得前端傳過來的參數 studentId
而取得到 studentId 這個參數的值之後,StudentController 就會去 call StudentService 的 getById()
方法,後續交由 Service 層來處理
而第二個 class 則是 StudentService,同樣的道理,因為這個 class 的名字是以 Service 做為結尾,因此他是代表 Service 層,負責進行商業邏輯的處理
在 StudentService 裡面,我們新增了一個 getById()
的方法,而這個方法的用途,就是去根據 student 的 id,去查詢這一筆 student 的數據出來
因為目前這個例子比較簡單,所以我們沒有太複雜的商業邏輯要做,只需要去資料庫中,查詢這一筆 student 的數據出來就可以了,因此在 StudentService 這裡,只需要直接去 call StudentDao 的 getById()
方法,後續交由 Dao 層去和資料庫溝通
最後第三個 class 是 StudentDao,同樣的道理,因為這個 class 的名字是以 Dao 做為結尾,因此他是代表 Dao 層,負責處理和資料庫的溝通
也因為 StudentDao 是 Dao 層,負責處理和資料庫的溝通,因此我們在這裡就會直接去透過 namedParameterJdbcTemplate 的寫法,使用 Spring JDBC 的功能,從資料庫中查詢一筆數據出來
所以透過上面這樣子的改寫,我們將原本的程式,由 1 個 class 拆分成 3 個 class,分別透過 StudentController、StudentService、StudentDao 這三個 class,各自去完成 Controller 層、Service 層、以及 Dao 層的功能
因此後續在維護上,假設我們想修改「查詢的 sql 語法」,那我們就只要去修改 StudentDao 中的程式即可(因為是由 Dao 層管理和資料庫的溝通)
又或是我們想要修改的是「前端的請求參數」,那我們就只要去修改 StudentController 中的程式即可(因為是由 Controller 層管理和前端的溝通)
所以透過 Controller-Service-Dao 的三層式架構,就可以讓我們的 Spring Boot 程式更好管理,以利後續的維護了
在使用 Controller-Service-Dao 的三層式架構時,有幾個注意事項需要遵守
像是上面的例子,StudentController 這個 class,因為他是以 Controller 做為結尾,因此在默契上,我們就會將他區分為 Controller 層
又或是 StudentService 這個 class,因為他是以 Service 做為結尾,所以我們就會將他區分為 Service 層
因此大家之後在使用 Controller-Service-Dao 的三層式架構時,就可以透過這個 class 名字的結尾,快速的知道這個 class 是屬於哪一層,進而知道他所負責的功能是「和前端溝通」、「處理商業邏輯」、還是「和資料庫溝通」了
在設計上,我們通常會將 Controller、Service、Dao 這些 class,全部變成是 Spring 容器所管理的 Bean,然後需要使用的時候,就透過 @Autowired
的方式,去注入想要使用的 Bean 進來
譬如說我們會在 StudentController 裡面,使用 @Autowired
去注入 StudentService,這樣就可以在 StudentController 裡面,去 call StudentService 的方法來使用
同樣的道理,假設 StudentService 想要使用 StudentDao 的話,那就一樣是可以使用 @Autowired
去注入 StudentDao,進而就可以使用 StudentDao 中的方法,去取得資料庫中的數據了
所以換句話說的話,其實我們在 Day 5~Day 10 所介紹的 Spring IoC 的部分,就都是為了這裡在鋪陳!!!
為了要能夠在 Spring Boot 中運用 Controller-Service-Dao 的三層式架構,所以我們必須要先有 Bean 的概念,知道如何創建 Bean、以及 Bean 之間是怎麼注入的,這樣子我們真的進到實作時,才能夠知道如何在 StudentService 中,去注入一個 StudentDao 進來
因此想要掌握 Spring Boot 中的 Controller-Service-Dao 的用法的話,先決條件就是先了解 Bean 的相關操作!!得 Bean 者得天下啦!!!
補充:如果對 Bean 的部分不太熟悉,可以查看 Day 5~Day 10 Spring IoC 的相關介紹
在 Controller-Service-Dao 的三層式架構中,各層的分層是很明確的,其中就有一項潛規則,即是「Controller 層不能直接使用 Dao 層」的 class
所以簡單的說的話,Controller 就一定只能去 call Service,再讓 Service 去 call Dao,不能讓 Controller 直接去 call Dao 就對了
因為 Dao 層的功能,是負責去「和資料庫溝通」的,所以在 Dao 這個 class 裡面,只能夠去執行 sql 語法,去存取資料庫中的數據
所以換句話說的話,就是「不能」在 Dao 層裡面添加商業邏輯的程式
所以像是取得資料庫的數據之後,假設想要進行排序、或是篩選之類的動作,就得回到 Service 層再處理(因為 Service 層是負責商業處理)
因此在 Controller-Service-Dao 的三層式架構裡面,就會盡量保持 Dao 是非常單純的和資料庫溝通,一切複雜的商業邏輯處理,就通通回到 Service 層進行
這篇文章先介紹了什麼是軟體工程,接著介紹了什麼是 MVC 架構模式,以及將 MVC 架構模式,轉化成 Spring Boot 中的 Controller-Service-Dao 的三層式架構
同時我們也詳細介紹了 Controller-Service-Dao 三層式架構的用法,比較了使用三層式架構的前後差別,最後也補充了使用 Controller-Service-Dao 三層式架構的注意事項,因此大家後續就可以透過這些用法,在你的 Spring Boot 程式中套用軟體工程的概念了!
那麼到這篇文章為止,我們就完成了所有 Spring Boot 中的基礎介紹,分別是:
因此介紹到這邊,大家就可以結合上述提到的功能,並且套用此篇文章的 Controller-Service-Dao 三層式架構,去搭建出一個簡易的後端系統出來了!
所以下一篇文章,我們就會來做個實戰演練,實際的透過上述的功能,去創建一個圖書館的管理系統出來,那我們就下一篇文章見啦!