# 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
## Web MVC簡介
### 1.1、Web開發中的請求-響應模型:

在Web世界里,具體步驟如下:
1、? Web瀏覽器(如IE)發起請求,如訪問[http://sishuok.com](http://sishuok.com/)
2、? Web服務器(如Tomcat)接收請求,處理請求(比如用戶新增,則將把用戶保存一下),最后產生響應(一般為html)。
3、web服務器處理完成后,返回內容給web客戶端(一般就是我們的瀏覽器),客戶端對接收的內容進行處理(如web瀏覽器將會對接收到的html內容進行渲染以展示給客戶)。
**因此,在Web世界里:**
都是Web客戶端發起請求,Web服務器接收、處理并產生響應。
一般Web服務器是不能主動通知Web客戶端更新內容。雖然現在有些技術如服務器推(如Comet)、還有現在的HTML5 websocket可以實現Web服務器主動通知Web客戶端。
到此我們了解了在web開發時的請求/響應模型,接下來我們看一下標準的MVC模型是什么。
### 1.2、標準MVC模型概述
**MVC模型:**是一種架構型的模式,本身不引入新功能,只是幫助我們將開發的結構組織的更加合理,使展示與模型分離、流程控制邏輯、業務邏輯調用與展示邏輯分離。如圖1-2

圖1-2
**首先讓我們了解下MVC(Model-View-Controller)三元組的概念:**
**Model(模型):**數據模型,提供要展示的數據,因此包含數據和行為,可以認為是領域模型或JavaBean組件(包含數據和行為),不過現在一般都分離開來:Value Object(數據) 和 服務層(行為)。也就是模型提供了模型數據查詢和模型數據的狀態更新等功能,包括數據和業務。
**View(視圖):**負責進行模型的展示,一般就是我們見到的用戶界面,客戶想看到的東西。
**Controller(控制器):**接收用戶請求,委托給模型進行處理(狀態改變),處理完畢后把返回的模型數據返回給視圖,由視圖負責展示。 也就是說控制器做了個調度員的工作,。
從圖1-1我們還看到,在標準的MVC中模型能主動推數據給視圖進行更新(觀察者設計模式,在模型上注冊視圖,當模型更新時自動更新視圖),但在Web開發中模型是無法主動推給視圖(無法主動更新用戶界面),因為在Web開發是請求-響應模型。
那接下來我們看一下在Web里MVC是什么樣子,我們稱其為 Web MVC 來區別標準的MVC。
### 1.3、Web MVC概述
模型-視圖-控制器概念和標準MVC概念一樣,請參考1.2,我們再看一下Web MVC標準架構,如圖1-3:
?
如圖1-3
在Web MVC模式下,模型無法主動推數據給視圖,如果用戶想要視圖更新,需要再發送一次請求(即請求-響應模型)。
概念差不多了,我們接下來了解下Web端開發的發展歷程,和使用代碼來演示一下Web MVC是如何實現的,還有為什么要使用MVC這個模式呢?
### 1.4、Web端開發發展歷程
此處我們只是簡單的敘述比較核心的歷程,如圖1-4

圖1-4
**1.4.1、CGI**:(Common Gateway Interface)公共網關接口,一種在web服務端使用的腳本技術,使用C或Perl語言編寫,用于接收web用戶請求并處理,最后動態產生響應給用戶,但每次請求將產生一個進程,重量級。
**1.4.2、Servlet**:一種JavaEE web組件技術,是一種在服務器端執行的web組件,用于接收web用戶請求并處理,最后動態產生響應給用戶。但每次請求只產生一個線程(而且有線程池),輕量級。而且能利用許多JavaEE技術(如JDBC等)。本質就是在里面 輸出 html流。但表現邏輯、控制邏輯、業務邏輯調用混雜。如圖1-5????
?
圖1-5
如圖1-5,這種做法是絕對不可取的,控制邏輯、表現代碼、業務邏輯對象調用混雜在一起,最大的問題是直接在里面輸出Html,這樣前端開發人員無法進行頁面風格等的設計與修改,即使修改也是很麻煩,因此實際項目這種做法不可取。
**1.4.3、JSP:**(Java Server Page):一種在服務器端執行的web組件,是一種運行在標準的HTML頁面中嵌入腳本語言(現在只支持Java)的模板頁面技術。本質就是在html代碼中嵌入。JSP最終還是會被編譯為Servlet,只不過比純Servlet開發頁面更簡單、方便。但表現邏輯、控制邏輯、業務邏輯調用還是混雜。如圖1-6

圖1-6
如圖1-6,這種做法也是絕對不可取的,控制邏輯、表現代碼、業務邏輯對象調用混雜在一起,但比直接在servlet里輸出html要好一點,前端開發人員可以進行簡單的頁面風格等的設計與修改(但如果嵌入的java腳本太多也是很難修改的),因此實際項目這種做法不可取。

JSP本質還是Servlet,最終在運行時會生成一個Servlet(如tomcat,將在tomcat\work\Catalina\web應用名\org\apache\jsp下生成),但這種使得寫html簡單點,但仍是控制邏輯、表現代碼、業務邏輯對象調用混雜在一起。
**1.4.4、Model1:**可以認為是JSP的增強版,可以認為是jsp+javabean如圖1-7
特點:使用<jsp:useBean>標準動作,自動將請求參數封裝為JavaBean組件;還必須使用java腳本執行控制邏輯。

圖1-7
此處我們可以看出,使用<jsp:useBean>標準動作可以簡化javabean的獲取/創建,及將請求參數封裝到javabean,再看一下Model1架構,如圖1-8。

圖1-8 Model1架構
Model1架構中,JSP負責控制邏輯、表現邏輯、業務對象(javabean)的調用,只是比純JSP簡化了獲取請求參數和封裝請求參數。同樣是不好的,在項目中應該嚴禁使用(或最多再demo里使用)。
**1.4.5、Model2:**在JavaEE世界里,它可以認為就是**Web MVC**模型
Model2架構其實可以認為就是我們所說的Web MVC模型,只是控制器采用Servlet、模型采用JavaBean、視圖采用JSP,如圖1-9

圖1-9 Model2架構
具體代碼事例如下:



從Model2架構可以看出,視圖和模型分離了,控制邏輯和展示邏輯分離了。
但我們也看到嚴重的缺點:
1.? 1、控制器:
1.1.1、控制邏輯可能比較復雜,其實我們可以按照規約,如請求參數submitFlag=toAdd,我們其實可以直接調用toAdd方法,來簡化控制邏輯;而且每個模塊基本需要一個控制器,造成控制邏輯可能很復雜;
1.1.2、請求參數到模型的封裝比較麻煩,如果能交給框架來做這件事情,我們可以從中得到解放;
1.1.3、選擇下一個視圖,嚴重依賴Servlet API,這樣很難或基本不可能更換視圖;
1.1.4、給視圖傳輸要展示的模型數據,使用Servlet API,更換視圖技術也要一起更換,很麻煩。
1.2、模型:
1.2.1、此處模型使用JavaBean,可能造成JavaBean組件類很龐大,一般現在項目都是采用三層架構,而不采用JavaBean。

1.3、視圖
1.3.1、現在被綁定在JSP,很難更換視圖,比如Velocity、FreeMarker;比如我要支持Excel、PDF視圖等等。
**1.4.5、服務到工作者:Front Controller + Application Controller + Page Controller + Context**
即,前端控制器+應用控制器+頁面控制器(也有稱其為動作)+上下文,也是Web MVC,只是責任更加明確,詳情請參考《核心J2EE設計模式》和《企業應用架構模式》如圖1-10:

圖1-10
運行流程如下:

職責:
**Front Controller:**前端控制器,負責為表現層提供統一訪問點,從而避免Model2中出現的重復的控制邏輯(由前端控制器統一回調相應的功能方法,如前邊的根據submitFlag=login轉調login方法);并且可以為多個請求提供共用的邏輯(如準備上下文等等),將選擇具體視圖和具體的功能處理(如login里邊封裝請求參數到模型,并調用業務邏輯對象)分離。
**Application Controller:**應用控制器,前端控制器分離選擇具體視圖和具體的功能處理之后,需要有人來管理,應用控制器就是用來選擇具體視圖技術(視圖的管理)和具體的功能處理(頁面控制器/命令對象/動作管理),一種策略設計模式的應用,可以很容易的切換視圖/頁面控制器,相互不產生影響。
**Page Controller(Command):**頁面控制器/動作/處理器:功能處理代碼,收集參數、封裝參數到模型,轉調業務對象處理模型,返回邏輯視圖名交給前端控制器(和具體的視圖技術解耦),由前端控制器委托給應用控制器選擇具體的視圖來展示,可以是命令設計模式的實現。頁面控制器也被稱為處理器或動作。
**Context:**上下文,還記得Model2中為視圖準備要展示的模型數據嗎,我們直接放在request中(Servlet API相關),有了上下文之后,我們就可以將相關數據放置在上下文,從而與協議無關(如Servlet API)的訪問/設置模型數據,一般通過ThreadLocal模式實現。
到此,我們回顧了整個web開發架構的發展歷程,可能不同的web層框架在細節處理方面不同,但的目的是一樣的:
干凈的web表現層:
模型和視圖的分離;
控制器中的控制邏輯與功能處理分離(收集并封裝參數到模型對象、業務對象調用);
控制器中的視圖選擇與具體視圖技術分離。
輕薄的web表現層:
做的事情越少越好,薄薄的,不應該包含無關代碼;
只負責收集并組織參數到模型對象,啟動業務對象的調用;
控制器只返回邏輯視圖名并由相應的應用控制器來選擇具體使用的視圖策略;
盡量少使用框架特定API,保證容易測試。
到此我們了解Web MVC的發展歷程,接下來讓我們了解下Spring MVC到底是什么、架構及來個HelloWorld了解下具體怎么使用吧。
本章具體代碼請參考 springmvc-chapter1工程。
[私塾在線學習網](http://sishuok.com/)原創內容([http://sishuok.com](http://sishuok.com/))
原創內容,轉載請注明私塾在線【[http://sishuok.com/forum/blogPost/list/5050.html](http://sishuok.com/forum/blogPost/list/5050.html#15499)】
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC