MVC的概念其實最先能夠追溯到好久好久之前,並非WEB開發過程當中所獨創,可是,MVC也適合WEB上的開發,並真正的在WEB開發領域普遍應用。MVC的第一個字母M是Model,承載着View層和Controller之間的數據傳輸,是數據傳輸的載體,經過Model層,解偶了View層和Controller層。 解偶View層和Controller層並不表明View層和Controller層之間沒有關係,而是下降複雜度。java
爲了便於理解Model層在開發中所起的做用,先拿一個最簡單的用戶錄入來舉個例子。假設要從表單中錄入用戶時須要填寫用戶名和年齡,表單提交後,服務器端的Servlet須要拿到表單內填寫的內容(這裏用ServletRequest來獲得數據是爲了說明MVC框架中M層所起到的做用),爲了獲得請求的數據,Servlet的代碼大至這樣寫程序員
Java代碼 服務器
public class TestServlet extends HttpServlet 框架
protected void doPost(ServletRequest request, ServletResponse response) throws IOException { jsp
User user = new User(); 函數
user.setName(request.getParameter("name")); this
user.setAge(Integer.parseInt(request.getParameter("age").toString())); 編碼
//省略業務處理代碼 ... spa
} orm
}
分析這幾行代碼,主要乾了四件事情
建立User對象
獲得Request的參數,
轉換age參數類型,
調用User對象的setter方法,爲User對象賦予相關的值
通過這四個步驟,一個具備業務含義的User對象被建立,做爲業務層Bean相關代碼的輸入條件。從這幾行代碼裏能夠看出,Request中的數據轉換成具備業務含義的對象,中間經歷了四個「必要而繁瑣」的步驟。若是程序員每天寫這樣的代碼,豈不是要瘋掉?還好,雖然代碼只能一行行的寫,可是思想倒是能夠昇華的。觀察一下這四個步驟,其實每一個步驟都不復雜,若是寫一段代碼能自動建立業務對象,而且自動裝配這個對象中各屬性的值,那豈不是能省不少時間和精力,讓程序員解放出來。
想法能夠萬能,代碼不可萬能,在要解放程序員的時間與精力以前,對這個業務類User和表單中的參數做一些約定,以便實現自動的裝配框架。約定以下:
User類必須有一個不包含任何參數的默認構造函數
User類中的屬性名字和表單中的輸入控件的名稱同樣
User類中的各屬性必須有默認的getter、setter方法
那框架代碼要實現什麼功能呢?以這個例子來講,框架要自動的建立User對象,拿到Request中的參數值,轉換類型後,賦給User對象相對應的屬性。
有了上面的三條協定後,再有Java一個很是很是重要的功能--反射,的鼎力相助,上面的自動裝配的功能能夠得以實現。一個比較直觀的流程是先掃瞄類中的屬性,遍歷全部的屬性,經過屬性名生成setter方法的函數名,經過反射的方法調用這些setter方法,setter方法的參數則經過從Request中獲得,並轉換成須要的類型,這裏的類型轉換也是須要經過反射機制來完成(目前這個流程還只能轉換java數據中的基本類型,對於複合類型的Bean,爲了描述這個流程,暫時不展開論述)。
如今假設框架已經能自動的裝配User對象,編寫服務端代碼時, 就再也不關心如何從Request中取參數了, 只需按照前面的三個約定編寫User類。可是事情尚未結束,既然自動裝配了User對象,那前面示例的Servlet代碼是否是能夠變成這樣?
Java代碼
public class TestServlet extends HttpServlet
private User user;
protected void doPost(ServletResponse response) throws IOException {
//省略業務處理代碼 ...
}
public void setUser(User user) {
this.user = user;
}
}
這樣的代碼看起來倒是有些奇怪,爲何doPost方法聲明中只有一個ServletResponse參數,而沒有ServletRequest參數?由於有框架的自動裝配User對象,對於代碼的編寫者而言,就根本不須要關心ServletRequest這個對象 。
如今進行更大膽的一步假設,且約定全部的Servlet的執行會把Request,Response運送(forward)到一個JSP頁面,那麼,服務端代碼編寫時,也再也不須要考慮Response對象了,除了前面所說的User類外,再加上一個,這個Servlet的doPost方法執行完後,要把Request,Response運送到那個頁面,假如用show_user.jsp這個頁面顯示被輸入的用戶信息。這個時候,回頭再審視一下剛剛作出的假設,會天然的得出下面的結論,能夠編寫一個與Request、Response無關的類,只關注User類如何編寫,返回一個表明要forward的JSP頁面,User對象的裝配工做,以及forward自己的這個代碼調用均可以交給框架去統一的管理,那真正要編寫的服務端代碼能夠象是這樣的 。
Java代碼
public class TestAction {
private User user;
public void setUser(User user){
this.user = user;
}
public String execute(ModelVehicle modelVehicle) {
//業務代碼實現
.... .... ....
modelVehicle.add("user", user);
return "show_user.jsp";
}
}
是否是很像Spring MVC的controller類?爲了不和MVC術語中的Controller這個詞衝突,仍然叫它Action吧。這個類已經徹底和Request,Response無關,當它被框架激活執行的時候,它首選須要框架爲它準備好User對象,而且調用setUser方法,賦予TestServlet對象user這個屬性,而後execute方法被執行,執行了真正的業務邏輯,同時,把須要在show_user.jsp頁面上顯示的數據放到ModelVehicle對象中去,TestAction這個對象執行完execute方法後,須要委託框架把ModelVehicle對象中的數據forward到show_user.jsp這個頁面上。
注意,這裏有兩個很是重要的約定,就是Action類必須有
Java代碼
public String execute(ModelVehicle modelVehicle)
這個方法的聲明,須要顯示到頁面上的數據,按照約定,須在execute執行過程當中放到ModelVehicle對象中去。爲了編寫的方便,能夠繼承一個聲明瞭此方法的抽象類。
基於這樣的服務端代碼編寫方式,須要框架再提供什麼功能呢?這裏就引出MVC框架中C須要關注的事情:
保證一個URI請求優先被框架先攔截,框架能根據這個URI知道哪一個Action類會被建立,
Action類的execute方法被執行,須要把ModelVehicle中的數據一併forward到Action類execute方法返回的JSP頁面。
由於這裏仍是重點介紹Model層的事,Controller層的事會在後面繼續介紹,其實,Controller是MVC框架中一個樞紐,須要花點篇幅去探討。
從探討Model層的過程當中,咱們發如今Action類中向JSP頁面輸出數據時,也是採用了Model方式。可是這個Model在處理起來相對簡單的多,JSP 2.0規範中的JSTL標籤庫很容易的將Request中的屬性在頁面上顯示出來,並且還能作一些簡單的運算。所以,MVC框架中Model層的主要關注點是如何把請求的數據自動裝配成Action所須要的bean,除此外,框架Model層還能夠提供複合bean自動裝配、輸入校驗、本地化及國際化、字符集編碼轉換、多重輸出等功能。可是一切的起點是Model層的java bean編寫遵守了這三個基本的約定:
必須有一個不包含任何參數的默認構造函數
屬性名字和表單中的輸入控件的名稱同樣
各屬性必須有默認的getter、setter方法
正是有了這三個約定,讓MVC框架Model層實現變得簡單,一個好的約定讓軟件開發變得簡單,是否是?