目錄

Day 28 - MVC 架構模式 - Controller-Service-Dao 三層式架構

古古

2024/07/28


哈囉大家好,我是古古。

在上兩篇文章中,我們有介紹了 Spring JDBC 中的兩個核心用法 update()query(),因此大家就可以透過這兩個方法,在 Spring Boot 中執行想要執行的 SQL 語法了。

而在介紹完 Spring JDBC 的核心用法之後,接著這篇文章要介紹的,是軟體工程中一個很重要的概念,即是「MVC 架構模式」,所以我們就開始吧!

什麼是軟體工程? #

在介紹什麼是「MVC 架構模式」之前,我們可以先來看一下,「軟體工程」到底是個什麼樣的概念。

所謂的軟體工程,即是「在面對一個大型的系統時,工程師們要如何分工合作,一起去解決問題?」,在這句話裡面有兩個重點,分別是「大型的系統」和「如何分工合作」。

所以簡單的說的話,當你今天要寫的是一個超過一兩千行的程式,並且在你們的團隊中,是由好幾位工程師一起分工合作來開發,在這種情況下,就會開始需要去注重「軟體工程」了。

補充:當然小型的系統也可以注重軟體工程,不過效益相對不會那麼大。另外也因為在實際的工作中,都是會由許多工程師共同合作、一起合力開發某個大型的功能的,因此掌握好軟體工程的概念可以說是非常重要!

什麼是 MVC 架構模式? #

大概了解了軟體工程的概念之後,我們可以接著來介紹「MVC 架構模式」的概念是什麼,在了解了MVC 架構模式的概念之後,我們會再來介紹,要如何在 Spring Boot 中去套用 MVC 架構模式的概念。

所謂的「MVC 架構模式」,他是軟體工程中的一種軟體架構,而 MVC 架構模式的用途,就是將一個系統,去拆分成「Model、View、Controller」三個部分,並且讓每一個部分都各自負責不同的功能。

因此在 MVC 架構模式中,各個部分的功能如下:

Model #

在 MVC 架構模式中,Model 負責的是「實作商業邏輯,並且處理數據」。

由於 Model 是負責商業邏輯的實作,所以我們都會將核心的商業邏輯,寫在 Model 這個部分裡面。

也因為 Model 同時要負責處理數據,因此 Model 也會需要去跟資料庫做溝通,將這些數據的改動給儲存起來。

Controller #

在 MVC 架構模式中,Controller 負責的是「轉發 Http request」。

所以簡單來說,當 Controller 收到來自前端的 Http request 之後,Controller 就會負責將這些 reque轉發給 Model,讓 Model 去處理後續的操作。

View #

在 MVC 架構模式中,View 負責的是「使用 Html 的模板去呈現數據」。

不過因為近幾年提倡「前後端分離」的關係,所以版面設計就都會交給前端去處理,因此後端就不需要處理 Html 的版面部分了,只需要改成回傳 JSON 格式的數據給前端即可。

也因為後端不需要處理 Html 的部分(會交由前端處理),因此 View 在現今的後端架構中,相對來說就沒有那麼重要了。

小結 #

所以在這裡先簡單小結一下的話,MVC 架構模式是軟體工程中的一種架構,會將系統拆分成「Model、View、Controller」三個部分,並且讓每一個部分都各自負責不同的功能。

不過雖然 MVC 架構模式會將程式拆分成三個部分,但是他實際上並不會去修改程式,MVC 架構模式只是將我們所寫的程式分類一下而已,可能你今天寫的這段程式是屬於 Model 部分、又或是你今天所寫的程式是屬於 Controller 部分,僅此而已,MVC 架構模式並不會添加什麼新功能到你的程式裡面。

所以當大家以後看到 MVC 架構模式時,就不用太緊張,他只是試圖要將我們所寫的程式進行分類,這樣在開發大型的系統時,才能更好的進行管理和維護。

補充:MVC 架構模式之所以被稱為是 MVC,原因就是取自於 Model-View-Controller 這三種分類的第一個字母的縮寫,所以才簡稱為 MVC 架構模式。

MVC 架構模式的優點 #

當我們使用了 MVC 架構模式,將後端程式區分成 Model-View-Controller 這三個部分之後,可以得到以下幾個好處:

  • 職責分離,更容易維護程式
  • 使程式結構更直覺,有利於團隊分工
  • 可重複使用寫好的程式

也因為使用 MVC 架構模式的好處非常多,因此在現今的 Spring Boot 開發中,基本上統統都是按照這個模式來開發程式,因此了解 MVC 架構模式的概念可以說是非常重要!我們日常的開發基本上都會按照這個模式進行開發。

Controller-Service-Dao 三層式架構 #

了解了 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 層 #

首先 Controller 層的用途,是負責去「接收前端傳過來的 Http request,並且去驗證請求參數」。

所以像是我們在 Spring MVC 中所介紹的那些註解,如 @RequestMapping@RequestParam…等等,只要是和「前端」進行溝通的部分,就都會放在 Controller 層裡面。

Service 層 #

而當 Controller 層接收到前端傳過來的 Http request、並且對其進行驗證之後,這時候 Controller 就會去 call Service層,讓 Service 負責去接手後續的處理。

而 Service 層的用途,主要是負責「商業邏輯的處理」,所以主要的核心商業邏輯,通常都會放在 Service 層裡面來實作。

Dao 層 #

而在 Service 層實作核心的商業邏輯時,多多少少都會需要去操作資料庫,因此這時 Service 層就會去 call Dao 層,使用 Dao 層去和資料庫進行溝通。

因此 Dao 層所負責的功能,就是「專門去和資料庫進行溝通的」,所以像是我們在 Spring JDBC 中所介紹的所有用法,只要是和「資料庫」溝通的部分,就都會放在 Dao 層裡面來實作。

補充:Dao 層為 Data access object 的縮寫。

小結 #

所以在套用 Controller-Service-Dao 三層式架構的設計之後,我們就可以將 Spring Boot 中的程式,依照不同的功能,把他放在不同的層級中來管理。

因此我們之後就可以透過 Controller-Service-Dao 的三層式架構,更好的去管理和維護 Spring Boot 的程式了!

實際使用 Controller-Service-Dao 三層式架構 #

了解了 Controller-Serivce-Dao 的三層式架構的概念之後,接著我們也可以來看一下,要如何把我們在上一篇文章中所實作的 StudentController,將他拆分為 Controller、Service、Dao 這三層,進而形成 Controller-Service-Dao 的三層式架構。

在使用 Controller-Service-Dao 三層式架構之前… #

在以前沒有 Controller-Service-Dao 三層式架構的概念時,我們所寫出來的 Spring Boot 程式,會將「取得前端參數的 @GetMapping …等功能」以及「和資料庫溝通的 namedParameterJdbcTemplate 功能」,全部放在同一個 class 中實作。

這樣子雖然同樣可以完成功能,但是在後續的管理和維護上,就會比較吃力。

使用 Controller-Service-Dao 三層式架構之後! #

而當我們將上面的程式,改成是使用 Controller-Service-Dao 的三層式架構來改寫的話,就可以改成下面這種寫法:

當我們套用了 Controller-Service-Dao 的三層式架構之後,就會將原本的程式,拆分成「三個 class」來負責。

Controller 層:StudentController #

首先第一個 class 是 StudentController,因為這個 class 的名字是以 Controller 做為結尾,因此他是代表 Controller 層,負責去和「前端」溝通。

在 StudentController 裡面,我們只保留 @GetMapping@PathVariable 的部分,也就是使用 Spring MVC 的功能,去和前端溝通,取得前端傳過來的參數 studentId。

並且在取得 studentId 這個參數的值之後,StudentController 就會去 call StudentService 的 getById() 方法,後續交由 Service 層來處理。

Service 層:StudentService #

第二個 class 則是 StudentService,因為這個 class 的名字是以 Service 做為結尾,因此他是代表 Service 層,負責進行商業邏輯的處理。

在 StudentService 裡面,我們新增了一個 getById() 的方法,而這個方法的用途,就是「根據 student 的 id,去查詢這一筆 student 的數據出來」。

因為目前這個例子比較簡單,所以我們沒有太複雜的商業邏輯要實作,所以此處只需要去資料庫中,查詢這一筆 student 的數據出來就可以了。不過因為 Service 層不可以直接和資料庫溝通,因此在 StudentService 這裡,需要再去 call StudentDao 的 getById() 方法,後續交由 Dao 層去和資料庫溝通。

Dao 層:StudentDao #

最後第三個 class 則是 StudentDao,因為這個 class 的名字是以 Dao 做為結尾,因此他是代表 Dao 層,負責和「資料庫」溝通。

也因為 StudentDao 是 Dao 層,負責處理和資料庫的溝通,因此我們在這裡就可以使用 Spring JDBC 的功能(即是使用 namedParameterJdbcTemplate 的 query() 方法),從資料庫中查詢 student 的數據出來。

小結 #

所以透過上面這樣子的改寫,我們就將原本的 class 拆分成了三個 class,分別透過 StudentController、StudentService、StudentDao 這三個 class,各自去完成 Controller 層、Service 層、以及 Dao 層的功能。

因此後續在維護上,假設我們想要修改「查詢的 SQL 語法」的話,那我們就只要去修改 StudentDao 中的程式即可(因為是由 Dao 層管理和資料庫的溝通)。

又或是如果我們想要修改的是「前端的請求參數」,那我們就只要去修改 StudentController 中的程式即可(因為是由 Controller 層管理和前端的溝通)。

所以透過 Controller-Service-Dao 的三層式架構,我們就可以將 Spring Boot 程式變得更好管理,以利後續的維護了。

使用 Controller-Service-Dao 三層式架構的注意事項 #

在使用 Controller-Service-Dao 的三層式架構時,有幾個注意事項會需要遵守:

注意事項一:透過 Class 名字結尾,表示這是哪一層 #

像是在上面的例子中,StudentController class 因為是以 Controller 做為結尾,因此在默契上,我們就會將他視為 Controller 層。

又或是 StudentService 這個 class,因為他是以 Service 做為結尾,所以我們就會將他視為 Service 層。

因此大家之後在使用 Controller-Service-Dao 的三層式架構時,就可以透過這個 class 名字的結尾,快速的知道這個 class 是屬於哪一層,進而知道他所負責的功能是「和前端溝通」、「處理商業邏輯」、還是「和資料庫溝通」了。

注意事項二:將 Controller、Service、Dao,全部變成 Bean #

在實作上,我們通常會將 Controller、Service、Dao 這些 class,全部變成是由 Spring 容器所管理的 Bean,並且在後續想要使用他們的時候,再透過 @Autowired 的方式,去注入想要使用的 Bean 進來。

舉例來說,我們就可以在 StudentController 裡面,使用 @Autowired 去注入 StudentService 進來,這樣子就可以在 StudentController 中去 call StudentService 的方法來使用了。

同樣的道理,假設 StudentService 想要使用 StudentDao 的話,那就一樣是可以使用 @Autowired 去注入 StudentDao,因此後續就可以在 StudentService 中使用 StudentDao 中的方法,進而去取得資料庫中的數據了。

所以到這邊大家也可以發現,其實我們在 Day 5~Day 10 所介紹的 Spring IoC 的部分,全部都是為了這裡在鋪陳啊啊!!!

為了要能夠在 Spring Boot 中運用 Controller-Service-Dao 的三層式架構,所以我們必須要先有 Bean 的概念,了解如何創建 Bean、以及 Bean 之間是怎麼注入的,這樣子後續在實作時,才知道要如何在 StudentService 中,去注入一個 StudentDao 進來。

因此想要掌握 Spring Boot 中的 Controller-Service-Dao 的用法的話,先決條件就是先了解 Bean 的相關操作!如果對 Bean 不熟悉的話,常常就會被 @Autowired 的各種注入給搞混,這樣反而會不利於大家的開發。

所以在掌握 Controller-Service-Dao 的三層式架構之前,建議大家一定要了解 Bean 的概念會比較好!

補充:如果對於 Bean 的相關註解 @Component@Autowired …等不太熟悉的話,也可以回頭查看 Day 5~Day 10 的介紹。

注意事項三:不能在 Controller 中直接使用 Dao #

在 Controller-Service-Dao 的三層式架構中,每一層的分層是很明確的,而其中就有一項潛規則,即是「Controller 層不能直接使用 Dao 層的 class」。

所以簡單來說,Controller 就一定只能去 call Service,再讓 Service 去 call Dao,絕對不能讓 Controller 直接去 call Dao 就對了。

注意事項四:Dao 層只能執行 SQL 語法,不能添加商業邏輯 #

在 Controller-Service-Dao 的三層式架構中,因為 Dao 層的功能是負責「和資料庫溝通」,所以在 Dao class 裡面,只能夠去執行 SQL 語法,去和資料庫中的數據互動,但是 「不能」 在 Dao 層裡面添加商業邏輯的程式。

舉例來說,在取得資料庫的數據之後,如果想要進行排序、或是進行篩選之類的動作,就得回到 Service 層再進行處理(因為 Service 層是負責商業處理)。

因此在 Controller-Service-Dao 的三層式架構裡面,就會盡量保持 Dao 層僅僅是執行 SQL 語法(或是 ORM 的語法),讓他負責和資料庫溝通的部分就好,而至於複雜的商業邏輯處理,就要回到 Service 層再進行。

小結 #

所以在實作 Controller-Service-Dao 的三層式架構時,除了要將原本的程式拆分成三個 class,分別由 StudentController、StudentService、StudentDao 來負責不同的部分之外,在使用上,也要遵守以下四個注意事項:

  • 透過 Class 名字結尾,表示這是哪一層
  • 將 Controller、Service、Dao,全部變成 Bean
  • 不能在 Contoller 層中直接使用 Dao 層
  • Dao 層只能執行 SQL 語法,不能添加商業邏輯

只要遵守這些注意事項,就能夠實作出一個符合規範的 Controller-Service-Dao 三層式架構了!

總結 #

這篇文章我們先介紹了軟體工程的概念,接著介紹了 MVC 架構模式,以及如何將「MVC 架構模式」轉化成 Spring Boot 中的「Controller-Service-Dao 三層式架構」。

而在 Controller-Service-Dao 的三層式架構中,我們也詳細介紹了 Controller-Service-Dao 三層式架構的用法,並且比較了使用三層式架構的前後差別,最後也補充了實作的注意事項,因此大家後續就可以透過這些用法,在你的 Spring Boot 程式中運用 Controller-Service-Dao 的三層式架構了!

那麼到這篇文章為止,我們就介紹完 Spring Boot 的基本用法,分別是:

  • Day 1 ~ Day 4:Spring Boot 簡介、環境安裝
  • Day 5 ~ Day 10:Spring IoC(Bean 的用法)
  • Day 11 ~ Day 12:Spring AOP
  • Day 13 ~ Day 23:Spring MVC(和前端溝通)
  • Day 24 ~ Day 28:Spring JDBC(和資料庫溝通)

因此學習到這裡,大家就已經具備 Spring Boot 開發的基礎能力了!讚!!所以現在大家其實已經有足夠的能力,能夠去搭建一個簡易的後端系統了。

所以下一篇文章,我們就會來進行一個實戰演練,總和前面所學習到的所有內容,練習去實作一個圖書館的管理系統出來,那我們就下一篇文章見啦!

補充:本文是擷取自我開設的線上課程 Java 工程師必備!Spring Boot 零基礎入門 的內容,如果你想了解更多的 Spring Boot 的用法,歡迎參考課程簡介 (輸入折扣碼「HH202504KU」即可享 85 折優惠)。