領先一步
VMware 提供培訓和認證來加速您的進度。
瞭解更多Spring 2.5 引入了一種編寫註解式 Web MVC 控制器的方法,我們還沒有在這方面寫太多部落格文章... 我將藉此機會向您概述 Spring MVC 目前的真正用途。
Spring MVC 本質上是一個請求分派器框架,具有 Servlet API 變體和 Portlet API 變體。 它在其託管環境(Servlet 或 Portlet)中非常緊密地運行。 將 Spring MVC 視為在 Servlet/Portlet 容器之上提供基礎設施和便利功能:例如,靈活的請求映射、控制器處理和檢視渲染階段之間的分離、資料繫結、補充 JSTL 的基本 JSP 標籤庫等等。 複雜 HTTP 請求處理的建構塊。
Spring MVC 非常靈活:它的核心 DispatcherServlet 不僅可以託管其原生控制器,還可以適應任何種類的動作類型。 它可以託管處理基於 HTTP 的遠端處理協定的純 HttpRequestHandlers:這是 Spring 使用者在定義 HTTP 調用器/Hessian/Burlap 服務匯出器,或 Web 服務的 XFire 匯出器時所利用的。 DispatcherServlet 甚至可以託管任意第三方 Servlet,允許這些 Servlet 由 Spring 環境配置和管理。
讓我們來看一個範例,取自 Spring 發佈版附帶的「imagedb」範例應用程式。(注意:這是「imagedb」的 Spring 2.5 最終版本,與 RC 版本略有不同。)
@Controller public class ImageController { private ImageDatabase imageDatabase; @Autowired public ImageController(ImageDatabase imageDatabase) { this.imageDatabase = imageDatabase; } @RequestMapping("/imageList") public String showImageList(ModelMap model) { model.addAttribute("images", this.imageDatabase.getImages()); return "imageList"; } @RequestMapping("/imageContent") public void streamImageContent(@RequestParam("name") String name, OutputStream outputStream) throws IOException { this.imageDatabase.streamImage(name, outputStream); } @RequestMapping("/imageUpload") public String processImageUpload( @RequestParam("name") String name, @RequestParam("description") String description, @RequestParam("image") MultipartFile image) throws IOException { this.imageDatabase.storeImage(name, image.getInputStream(), (int) image.getSize(), description); return "redirect:imageList"; } @RequestMapping("/clearDatabase") public String clearDatabase() { this.imageDatabase.clearDatabase(); return "redirect:imageList"; } }
這個控制器類別實際上做什麼?它的設計重點是什麼? 讓我們逐步了解...
建構函式標記為 @Autowired 並接受 ImageDatabase 類型的引數。 這是核心 Spring 2.5 功能,即註解驅動的依賴注入:將呼叫此建構函式,傳入 ImageDatabase 類型的 Spring bean,該 bean 是從 Spring ApplicationContext 依類型取得的。 在我們的案例中,這是應用程式服務層中的核心 ImageDatabase 服務。
實際的請求映射透過方法層級的 @RequestMapping 註解來表達。 這些映射中的每一個都繫結到包含 DispatcherServlet 中的特定 HTTP 路徑。 映射路徑也可以從處理器方法名稱推斷出來,在類型層級表達一個常見的映射模式(例如「*.image」) - 重用從優秀的 MultiActionController 已知的 InternalPathMethodNameResolver!
因此,當在類型層級使用 @RequestMapping 時,方法層級的註解將「縮小」特定處理器方法的映射。 @RequestMapping 允許指定 HTTP 請求方法(例如 method = RequestMapping.GET)或特定請求參數(例如 params = "action=save"),所有這些都縮小了特定方法的類型層級映射。 或者,類型層級的 @RequestMapping 也可以與優秀的 Controller 介面實作結合使用 - 例如 SimpleFormController 或 MultiActionController。
「imagedb」範例顯示了幾個基本變體
@RequestMapping("/imageList") public String showImageList(ModelMap model) { model.addAttribute("images", this.imageDatabase.getImages()); return "imageList"; }
對於此處理器方法,要解析的唯一引數是 ModelMap。 ModelMap 是 Spring 2.0 重新設計的 ModelAndView 物件的一部分,封裝了一系列將暴露給檢視的名稱-值屬性對。 上面的程式碼只是呼叫 ImageDatabase 服務來載入 ImageDescriptor 物件的 List,並在屬性名稱「images」下公開它們。 或者,您可以呼叫沒有屬性名稱的 addAttribute 變體,在這種情況下,名稱將從給定的值類型推斷出來(在我們的案例中: 「imageDescriptorList」)。
傳回值是一個字串,只是指示要渲染的檢視的名稱。 本質上,您可以編寫相同的方法,沒有引數且傳回值為 ModelAndView - 但以上通常更容易閱讀,並且避免了對 ModelAndView 物件的依賴。(請注意,ModelMap 是「ui」封裝中的泛型類別,而 ModelAndView 是「web.servlet」封裝中相當特定的類別。)
@RequestMapping("/imageContent") public void streamImageContent(@RequestParam("name") String name, OutputStream outputStream) throws IOException { this.imageDatabase.streamImage(name, outputStream); }
此處理器方法顯示了一個完全不同的用例。 它的目的是將影像內容從資料庫串流到 HTTP 回應。 它直接寫入回應,而不轉發到檢視; 因此,它的傳回類型為 void。 它使用 Spring 2.5 的新 @RequestParam 註解來接收 HTTP 請求參數,形式為方法引數,以及 OutputStream 類型的引數,用於處理回應串流。 影像內容的實際載入再次委派給 ImageDatabase 服務。
或者,您可以使用更傳統的 HttpServletRequest/HttpServletResponse 簽章來實作相同的處理器方法,從而更好地控制精確的 HTTP 處理。 但是,這會引入與 Servlet API 更強的耦合,並且需要付出更多努力才能進行單元測試。
@RequestMapping("/imageContent") public void streamImageContent(HttpServletRequest request, HttpServletResponse response) throws IOException { this.imageDatabase.streamImage(request.getParameter("name"), response.getOutputStream()); }
此類處理器方法的目的應該已經變得明顯:它們是 HTTP 請求世界和服務層世界之間相當簡單的「橋樑」,用於適應請求參數和回應內容。 讓我們看一下影像上傳處理器以獲取進階範例。
@RequestMapping("/imageUpload") public String processImageUpload( @RequestParam("name") String name, @RequestParam("description") String description, @RequestParam("image") MultipartFile image) throws IOException { this.imageDatabase.storeImage(name, image.getInputStream(), (int) image.getSize(), description); return "redirect:imageList"; }
基本目的再次是接受幾個特定的 HTTP 請求參數,執行一些處理,然後傳回檢視的名稱 - 在這種情況下,表示重新導向到「imageList」路徑。 但是,此特定方法會處理多部分檔案上傳,這就是為什麼「image」引數宣告為 MultipartFile 類型。 Spring 的 @RequestParam 處理會自動將其解析為多部分元素,以便處理器方法能夠取得檔案大小並以 InputStream 的形式存取上傳的檔案內容。
如需註解式處理器方法支援的引數類型的完整清單,請參閱 @RequestMapping javadoc。
讓我總結一下 Spring MVC 的目的:僅限於無狀態控制器、基本表單處理和彈性的檢視渲染。 MVC 本質上是 Spring 核心 Web 支援的一個以分派為中心的模組,可以作為許多不同種類用途的執行時間 - 以及在之上建構的更高級別的功能。 在這方面,它類似於 Java EE 5 的 JSF 執行時間,後者也主要作為一個基本的 Web 平台,用於在其之上建構更高級別的功能。
這就是 Spring Web Flow 進入畫面的地方:SWF 是我們更高級別的、面向對話的控制器引擎,對 *MVC 檢視* 和 *JSF 檢視* 都有強大的支援。 我強烈建議查看 SWF 以建構 Web 使用者介面,尤其是在面臨重要的導航和狀態管理需求時。 在 Spring Web Flow 2.0 里程碑中,發生著令人興奮的事情,這與 Spring 2.5 MVC 基礎的發展方向一致 - 同時也透過我們新的 Spring Faces 模組特別關注 JSF。 敬請關注!