Spring MVC 是什麼?深入解析打造高效能網頁應用的必備框架

Spring MVC 是什麼?

您是不是在網路上搜尋「Spring MVC 是什麼」的時候,覺得看了很多文章,但還是有點霧煞煞?別擔心!身為一個長年與 Java 網頁開發打交道的工程師,我完全明白那種感覺。今天,我就要用最淺顯易懂,又兼具專業深度的方式,帶您徹底搞懂 Spring MVC,讓您在開發網頁應用時,能更得心應手!

簡單來說,**Spring MVC 是一個基於 Java 的網頁應用框架,它是 Spring 框架家族裡專門用來處理網頁請求和響應的重要一員。** 它的設計核心是遵循「Model-View-Controller」(模型-視圖-控制器)的設計模式,這聽起來有點學術,但其實它就是把一個網頁應用的不同職責,分得清清楚楚,讓程式碼更乾淨、更好維護、也更容易擴展。

當我們在瀏覽網頁時,背後其實發生了很多事情。從您點擊連結、提交表單,到伺服器接收請求、處理邏輯、生成回應,最後再將畫面顯示在您的螢幕上,這整個流程,Spring MVC 就是扮演著協調者和執行者的角色。它讓整個過程變得更有條理,也更有效率。

如果您曾經開發過網頁應用,可能會接觸過 Servlet API、JSP 等技術。Spring MVC 就是在這些基礎之上,提供了更強大、更方便的功能,並且將複雜的流程進行了高度的抽象和封裝。您可以把它想像成一個升級版的工具箱,裡面有各種好用的工具,讓您能更快、更輕鬆地建造出功能強大又美觀的網頁應用。

我自己的經驗是,剛開始接觸 Spring MVC 的時候,會覺得它有點複雜,但一旦您掌握了它的核心概念,你會發現它真的是一個非常棒的工具。它不僅僅是寫程式碼,更是一種思考和架構的模式,能夠幫助我們寫出更高品質的軟體。

Spring MVC 的核心概念:MVC 模式

要理解 Spring MVC,就不能不提它所遵循的 **Model-View-Controller (MVC)** 設計模式。這是一個非常經典且廣泛應用的軟體架構模式,特別是在使用者介面開發領域。MVC 將一個應用程式的組成部分,劃分為三個相互獨立但又協同工作的單元:

  • Model (模型):

    模型代表應用程式的資料和業務邏輯。它負責處理資料的儲存、擷取、更新和刪除,以及應用程式的核心計算和處理。模型獨立於使用者介面,這意味著您可以改變模型的實現,而不需要影響視圖。例如,在一個購物車應用中,模型可能包含商品資訊、購物車的總價計算邏輯,以及與資料庫的互動。

  • View (視圖):

    視圖負責呈現使用者介面,也就是使用者在瀏覽器上看到的畫面。它從模型中獲取資料,並將其以適當的格式顯示給使用者。視圖通常是靜態的 HTML 頁面,或使用 JSP、Thymeleaf 等模板引擎動態生成。視圖不應該包含任何業務邏輯,它只負責「顯示」資料。

  • Controller (控制器):

    控制器是模型和視圖之間的橋樑。它接收使用者的輸入(例如,點擊按鈕、提交表單),然後根據這些輸入與模型互動,更新模型狀態或從模型中獲取資料。接著,控制器會選擇合適的視圖來呈現結果,並將資料傳遞給視圖。控制器負責協調整個流程,是處理使用者請求的核心。

MVC 模式的優點非常顯著:

  • 高內聚、低耦合: 各個組件職責分明,修改其中一個組件對其他組件的影響最小。
  • 易於維護和擴展: 清晰的架構使得程式碼更容易理解、除錯和修改。
  • 提高開發效率: 不同開發者可以同時負責不同的組件(例如,前端負責 View,後端負責 Model 和 Controller),縮短開發週期。
  • 促進程式碼重用: 模型中的業務邏輯可以被多個視圖重用。

Spring MVC 的運作流程

了解了 MVC 模式後,我們就可以更深入地探討 Spring MVC 在處理網頁請求時的具體流程。這個流程是 Spring MVC 能夠高效運作的關鍵。

想像一下,當您在瀏覽器中輸入網址,按下 Enter 鍵,這個請求是如何被 Spring MVC 處理的呢?我們可以將其拆解成幾個關鍵步驟:

  1. 使用者發送請求 (User Sends Request):

    使用者在瀏覽器中輸入 URL,或點擊連結、提交表單,就發送了一個 HTTP 請求到伺服器。

  2. Servlet 容器接收請求 (Servlet Container Receives Request):

    這個請求首先由 Servlet 容器(例如 Tomcat)接收。

  3. DispatcherServlet 處理請求 (DispatcherServlet Handles Request):

    Spring MVC 的核心組件是 `DispatcherServlet`,它就像是應用程式的「前端控制器」。`DispatcherServlet` 會接收所有來自 Servlet 容器的請求,並負責將請求分派給後續的處理程序。

    在我看來,`DispatcherServlet` 的存在,大大簡化了我們編寫 Servlet 的工作。原本我們可能需要寫很多 `if-else` 語句來判斷不同的請求路徑,但 `DispatcherServlet` 統一接手,讓我們的程式碼更加整潔。

  4. HandlerMapping 尋找處理程序 (HandlerMapping Finds Handler):

    `DispatcherServlet` 會查詢 `HandlerMapping`,`HandlerMapping` 的任務是根據請求的 URL,尋找對應的 Controller 方法(也就是處理該請求的「處理程序」)。Spring MVC 提供了多種 `HandlerMapping` 的實現,最常用的是基於註解(Annotation)的配置。

  5. Controller 處理請求 (Controller Processes Request):

    一旦找到了對應的 Controller 方法,`DispatcherServlet` 就會將請求轉交給該 Controller 方法執行。Controller 會處理業務邏輯,例如從資料庫讀取資料、進行計算等。

  6. Model 準備資料 (Model Prepares Data):

    Controller 在處理請求的過程中,可能會與 Model 層進行互動,獲取或修改資料。這些資料最終會被封裝成一個 Model 物件,準備傳遞給 View。

  7. ViewResolver 選擇視圖 (ViewResolver Selects View):

    Controller 處理完畢後,會返回一個邏輯檢視名稱 (Logical View Name),這個名稱並不是實際的 HTML 檔案。`DispatcherServlet` 會將這個邏輯名稱交給 `ViewResolver`。`ViewResolver` 的作用是根據這個邏輯名稱,去查找對應的實際 View 資源(例如,一個 JSP 檔案或一個 Thymeleaf 模板)。

  8. View 渲染畫面 (View Renders View):

    找到實際的 View 後,`DispatcherServlet` 會將 Model 資料傳遞給 View。View 接著會利用這些資料,生成最終的 HTML 響應。

  9. DispatcherServlet 返回響應 (DispatcherServlet Returns Response):

    最後,`DispatcherServlet` 會將渲染好的 HTML 響應回傳給 Servlet 容器,Servlet 容器再將響應發送回使用者瀏覽器。

Spring MVC 的核心組件

`DispatcherServlet` 雖然是核心,但它並不是孤軍奮戰。Spring MVC 擁有許多重要的組件,它們各司其職,共同協作,才得以實現強大的功能。以下是一些您需要了解的核心組件:

1. DispatcherServlet

如前所述,它是 Spring MVC 的前端控制器,負責協調整個請求處理流程。它是一個 Servlet,您需要在 `web.xml` 或 Java 配置中進行配置。

2. HandlerMapping

負責根據請求的 URI 找到最合適的 Controller 處理程序。常見的有:

  • `RequestMappingHandlerMapping`: 基於 `@RequestMapping` 註解。
  • `SimpleUrlHandlerMapping`: 基於 URL 模式的配置。

3. Controller

處理使用者請求的組件。在 Spring MVC 中,Controller 通常是一個 POJO (Plain Old Java Object),並透過註解(如 `@Controller`、`@RequestMapping`)來標示。

4. ModelAndView

一個物件,它同時包含 Model 資料和 View 的名稱。Controller 方法可以返回 `ModelAndView` 物件,讓 `DispatcherServlet` 知道要顯示哪個 View,以及需要傳遞哪些資料。

5. ViewResolver

負責將 Controller 返回的邏輯檢視名稱,解析成實際的 View 物件。常見的 `ViewResolver` 有:

  • `InternalResourceViewResolver`: 用於解析 JSP 檔案。
  • `ThymeleafViewResolver`: 用於解析 Thymeleaf 模板。

6. View

代表使用者介面。它從 Model 中獲取資料,並將其渲染成使用者可見的形式(通常是 HTML)。Spring MVC 支援多種 View 技術,如 JSP、Thymeleaf、FreeMarker 等。

7. LocaleResolver

負責解析請求的地區設置(Locale),用於實現國際化(i18n)。

8. ThemeResolver

負責解析應用程式的主題(Theme),用於實現網站的風格切換。

9. HandlerExceptionResolver

負責處理 Controller 處理請求過程中發生的異常,並選擇合適的 View 來顯示錯誤資訊。

10. RequestToViewNameTranslator

將請求轉換成一個邏輯檢視名稱。

Spring MVC 的優勢與好處

那麼,為什麼這麼多開發者選擇 Spring MVC?它究竟有哪些獨特的優勢呢?

  • 靈活性高

    Spring MVC 提供了高度的靈活性,您可以自由選擇如何配置組件,以及使用哪些 View 技術。您可以選擇基於 XML 的配置,也可以選擇更現代化的 Java 配置或註解驅動的配置。

  • 與 Spring 生態系統無縫整合

    作為 Spring 框架的一部分,Spring MVC 可以輕鬆地與 Spring 的其他模組(如 Spring Data、Spring Security、Spring AOP 等)整合,構建出功能強大且完善的應用程式。這意味著您不必重新發明輪子,可以利用現有的成熟解決方案。

  • 強大的註解支援

    透過 `@Controller`、`@RequestMapping`、`@RequestParam`、`@ResponseBody` 等註解,Spring MVC 大大簡化了程式碼編寫,讓開發者能夠更專注於業務邏輯,而不是繁瑣的配置。這讓開發效率提升了好幾倍!

  • 內建的型別轉換與驗證

    Spring MVC 內建了強大的資料型別轉換機制,能夠自動將 HTTP 請求中的字串參數轉換成 Controller 方法所需的 Java 型別(例如,字串轉換成 Integer、Date 等)。同時,它也支援 JSR 303(Bean Validation)標準,方便進行輸入資料驗證。

  • 優秀的國際化 (i18n) 和主題 (Theming) 支援

    如果您需要開發多語言的網站,Spring MVC 提供了完善的國際化支援。您可以輕鬆地管理不同語言的資源檔。同樣,對於需要改變網站風格(例如,暗色模式、亮色模式)的需求,主題支援也能派上用場。

  • 測試友好

    Spring MVC 的設計使得單元測試和整合測試變得相對容易。您可以隔離測試 Controller、Model 或 View,而無需啟動整個 Web 伺服器。

  • 豐富的 View 技術支援

    Spring MVC 不僅限於 JSP,它還支援 Thymeleaf、FreeMarker、Velocity 等多種模板引擎,讓您可以根據專案需求選擇最適合的 View 技術。

Spring MVC 的實戰應用:一個簡單的例子

理論講了這麼多,我們來看看一個簡單的實戰例子,讓您對 Spring MVC 的運作有更具體的感受。

假設我們要建立一個簡單的「問候」網頁,使用者輸入名字,按下按鈕後,網頁會顯示「哈囉,[使用者名字]!」

1. Controller 程式碼

我們首先需要一個 Controller 來處理請求。

java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {

@GetMapping(“/greet”) // 處理 /greet 這個 GET 請求
public String greet(@RequestParam(name=”name”, required=false, defaultValue=”訪客”) String userName, Model model) {
// @RequestParam 用於獲取請求參數 name
// required=false 表示這個參數不是必須的
// defaultValue=”訪客” 設定預設值,如果沒有傳 name 參數,就用「訪客」

model.addAttribute(“greetingMessage”, “哈囉,” + userName + “!”); // 將訊息加入 Model

return “greetingView”; // 返回邏輯檢視名稱
}
}

在這個 Controller 中:

  • `@Controller` 標示這個類別是一個 Spring MVC Controller。
  • `@GetMapping(“/greet”)` 告訴 Spring,這個方法專門處理 HTTP GET 方法,並且 URI 是 `/greet`。
  • `@RequestParam` 註解用來綁定請求參數 `name` 到方法的 `userName` 變數。
  • `Model model` 參數是一個物件,我們可以用 `model.addAttribute()` 將資料加入,準備傳遞給 View。
  • `return “greetingView”;` 表示處理完後,要轉發到一個名為 `greetingView` 的 View。

2. View 檔案 (例如,`src/main/webapp/WEB-INF/views/greetingView.jsp`)

接下來,我們需要一個 View 來顯示結果。這裡我們使用 JSP 作為例子。

jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>



${greetingMessage}

點我看看換另一個名字

在這個 JSP 檔案中:

  • `${greetingMessage}` 是一個 JSTL 標籤,它會從 Model 中取出名為 `greetingMessage` 的屬性值,並顯示出來。
  • 我們還提供了一個連結,可以點擊來測試輸入不同的名字。

3. 配置 (例如,`src/main/webapp/WEB-INF/spring-servlet.xml`)

您需要配置 `DispatcherServlet`,並告訴它如何找到 Controller 和 View。這通常在一個 XML 檔案中完成(或使用 Java Config)。

xml





在這個配置中:

  • `` 會告訴 Spring 去掃描指定的套件,找出標示為 `@Controller` 的類別。
  • `` 配置了 `InternalResourceViewResolver`,讓它知道 View 檔案在哪裡,以及它們的副檔名是什麼。
  • `` 啟用了一些重要的 MVC 功能,例如處理 `@RequestMapping` 等註解。

當您部署這個應用並訪問 `http://your-server/context-path/greet` 時,您就會看到「哈囉,訪客!」;如果您訪問 `http://your-server/context-path/greet?name=張三`,您就會看到「哈囉,張三!」

Spring MVC 常見問題與解答

Q1: Spring MVC 和 Struts 有什麼不同?

Spring MVC 和 Struts (尤其是 Struts 1 和 Struts 2) 都是基於 Java 的 Web 框架,但它們在設計理念和架構上有顯著差異。

  • 架構設計:Spring MVC 的設計更加靈活,它完全基於 POJO (Plain Old Java Object),對 Servlet API 的依賴較小。而 Struts 1 則大量依賴 Servlet API,並且使用了 Action 類別,而 Struts 2 則引入了 Interceptor 機制。
  • 依賴性:Spring MVC 是 Spring 框架的一部分,與 Spring 生態系統緊密結合,可以輕鬆利用 Spring 的其他模組(如 Spring IoC、AOP)。Struts 則是一個獨立的框架,雖然也可以與 Spring 整合,但整合程度不如 Spring MVC。
  • 配置方式:Spring MVC 提供了 XML 配置、Java 配置和註解驅動等多種配置方式,可以滿足不同開發者的偏好。Struts 則主要依賴 XML 配置。
  • 型別轉換與驗證:Spring MVC 內建了強大的型別轉換和 JSR 303 驗證支援,非常方便。Struts 2 也提供了類似的功能,但 Spring MVC 的整合度更高。
  • 學習曲線:對於已經熟悉 Spring 框架的開發者來說,Spring MVC 的學習曲線較為平緩。而 Struts 的概念相對獨立,需要額外學習。

總體而言,Spring MVC 在現代 Java Web 開發中更受歡迎,因其靈活性、與 Spring 生態的無縫整合以及優秀的開發者體驗。

Q2: `@Controller` 和 `@RestController` 有什麼區別?

這是 Spring MVC 中一個非常重要的區別,尤其是在開發 RESTful API 時。

  • `@Controller`:

    這個註解表示該類別是一個 Controller,用於處理 Web 請求。當 Controller 方法返回一個 String 時,Spring MVC 會將這個 String 視為一個 **邏輯檢視名稱 (Logical View Name)**,然後透過 `ViewResolver` 去查找對應的 View (例如 JSP、Thymeleaf 模板),最終渲染成 HTML 響應回傳給客戶端。它主要用於傳統的伺服器端渲染應用。

  • `@RestController`:

    這是一個組合註解,它相當於同時加上了 `@Controller` 和 `@ResponseBody`。

    • `@Controller`: 保持了該類別作為 Controller 的角色。
    • `@ResponseBody`: 這個註解是關鍵。它告訴 Spring,方法返回的物件 **不應該被解釋為邏輯檢視名稱**,而是應該直接序列化(通常是轉換成 JSON 或 XML)後作為 HTTP 響應的正文 (Response Body) 回傳給客戶端。

    因此,`@RestController` 主要用於開發 RESTful Web 服務,其方法返回的通常是資料物件,而不是 HTML 頁面。

簡單來說:

  • 用 `@Controller` 如果你想返回一個 HTML 頁面。
  • 用 `@RestController` 如果你想返回 JSON、XML 等資料格式。

Q3: 如何處理 HTTP 請求中的參數?

Spring MVC 提供了多種方式來處理 HTTP 請求中的參數,使其非常靈活和方便。

  • `@RequestParam`:

    用於獲取請求參數 (Query String 或 Form Data)。例如:`@RequestParam(“userId”) String id` 可以將請求參數 `userId` 的值賦給 `id` 變數。您可以設定 `required=false` 來使其成為可選參數,並設定 `defaultValue` 來提供預設值。

  • `@PathVariable`:

    用於獲取 URL 路徑中的變數。例如,如果您的 URL 模式是 `/users/{userId}`,您可以這樣獲取:`@PathVariable(“userId”) String userId`。這對於構建 RESTful API 非常有用。

  • `@RequestBody`:

    用於接收請求體 (Request Body) 中的資料,通常用於接收 JSON 或 XML 格式的資料。Spring MVC 會自動將請求體反序列化成您指定的 Java 物件。例如:`@RequestBody User user`。

  • `@ModelAttribute`:

    可以有兩種用途:

    • 在 Controller 方法參數中使用:Spring MVC 會嘗試將請求中的所有參數自動綁定到指定的物件(通常是 POJO)的屬性上。
    • 在方法上使用,並返回一個物件:這個物件會被添加到 Model 中,用於在 View 中顯示。

這些註解的使用,讓開發者能夠精準地從各種來源獲取所需的請求資料。

Q4: Spring MVC 如何處理檔案上傳?

檔案上傳是網頁應用中常見的功能。Spring MVC 提供了 `MultipartFile` 介面來簡化檔案上傳的處理。

首先,您需要在專案中引入 `commons-fileupload` 和 `commons-io` 依賴(如果您使用的是 Maven 或 Gradle,則添加相應的依賴即可)。

然後,在您的 JSP 頁面中,表單的 `method` 屬性必須是 `POST`,並且 `enctype` 屬性必須是 `multipart/form-data`。

在 Controller 中,您可以在方法參數中加入 `MultipartFile` 類型的參數:

java
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.stereotype.Controller;

@Controller
public class FileUploadController {

@PostMapping(“/upload”)
public String handleFileUpload(@RequestParam(“file”) MultipartFile file) {
if (file.isEmpty()) {
return “redirect:/upload-error”; // 處理空檔案
}

try {
// 這裡可以寫入檔案到伺服器
// 例如:
// byte[] bytes = file.getBytes();
// Path path = Paths.get(“/path/to/save/” + file.getOriginalFilename());
// Files.write(path, bytes);

System.out.println(“Successfully uploaded: ” + file.getOriginalFilename());
return “redirect:/upload-success”; // 成功後跳轉
} catch (Exception e) {
e.printStackTrace();
return “redirect:/upload-error”; // 處理上傳錯誤
}
}
}

`MultipartFile` 物件提供了豐富的方法,例如 `getOriginalFilename()` 獲取原始檔名,`getBytes()` 獲取檔案內容,`getSize()` 獲取檔案大小等。

Spring MVC 的檔案處理功能,讓原本複雜的檔案上傳變得相對直觀和易於管理。

結語

透過以上的介紹,相信您對「Spring MVC 是什麼」已經有了更深入、更全面的理解。它不僅僅是一個框架,更是一種將複雜網頁應用程式結構化的有力工具。從 MVC 設計模式的清晰分工,到 `DispatcherServlet` 的協調處理,再到各種靈活的組件和註解支援,Spring MVC 讓開發者能夠更專注於業務邏輯,更高效地構建出健壯、可維護且功能豐富的網頁應用。

無論您是剛入門 Java Web 開發的新手,還是經驗豐富的資深工程師,掌握 Spring MVC 都將為您的開發技能帶來顯著的提升。希望這篇文章能幫助您更自信地擁抱 Spring MVC,並在您的專案中發揮它的強大威力!

spring mvc是什麼