天天看點

《Spring MVC學習指南(第2版)》——2.3 模型2之Servlet控制器

本節書摘來自異步社群《spring mvc學習指南(第2版)》一書中的第2章,第2.3節,作者:【美】paul deck著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

為了便于對模型2有一個直覺的了解,本節将展示一個簡單模型2應用。實踐中,模型2的應用非常複雜。

示例應用名為appdesign1,其功能設定為輸入一個産品資訊。具體為:使用者填寫産品表單(圖2.2)并送出;示例應用儲存産品并展示一個完成頁面,顯示已儲存的産品資訊(見圖2.3)。

《Spring MVC學習指南(第2版)》——2.3 模型2之Servlet控制器

圖2.2 産品表單

《Spring MVC學習指南(第2版)》——2.3 模型2之Servlet控制器

圖2.3 産品詳細頁

示例應用支援如下兩個action。

(1)展示“添加産品”表單。該action将圖2.2中的輸入表單發送到浏覽器上,其對應的uri應包含字元串input-product。

(2)儲存産品并傳回如圖2.3所示的完成頁面,對應的uri必須包含字元串save-product。

示例應用由如下元件構成:

(1)一個product類,作為product的領域對象。

(2)一個productform類,封裝了html表單的輸入項。

(3)一個controllerservlet類,本示例應用的控制器。

(4)一個saveproductaction類。

(5)兩個jsp頁面(productform.jsp和product detail.jsp)作為視圖。

(6)一個css檔案,定義了兩個jsp頁面的顯示風格。

示例應用目錄結構如圖2.4所示。

《Spring MVC學習指南(第2版)》——2.3 模型2之Servlet控制器

圖2.4 app02a目錄結構

下面詳細介紹示例應用的每個元件。

2.3.1 product類

product執行個體是一個封裝了産品資訊的javabean。product類(見清單2.1)包含3個屬性:productname、description和price。

清單2.1 product類

product類實作了java.io.serializable接口,其執行個體可以安全地将資料儲存到httpsession中。根據serializable的要求,product實作了一個serialversionuid屬性。

2.3.2 productform類

表單類與html表單相映射,是後者在服務端的代表。productform類(見清單 2.2)包含了一個産品的字元串值。productform類看上去同product類相似,這就引出一個問題:productform類是否有存在的必要。

實際上,表單對象會傳遞servletrequest給其他元件,類似validator(本章後面會介紹)。而servletrequest是一個servlet層的對象,不應當暴露給應用的其他層。

另一個原因是,當資料校驗失敗時,表單對象将用于儲存和展示使用者在原始表單上的輸入。2.5節将會詳細介紹應如何處理。

注意:

 

大部分情況下,一個表單類不需要實作serializable接口,因為表單對象很少儲存在httpsession中。

清單2.2 productform類

2.3.3 controllerservlet類

controllerservlet類(見清單2.3)繼承自javax.servlet.http.httpservlet類。其doget和dopost方法最終調用process方法,該方法是整個servlet控制器的核心。

可能有人好奇,為何這個servlet控制器命名為controllerservlet,實際上,這裡遵從了一個約定:所有servlet的類名稱都帶有servlet字尾。

清單2.3 controllerservlet類

ontrollerservlet的process方法處理所有輸入請求。首先是擷取請求uri和action名稱。

在本示例應用中,action值隻會是input-product或save-product。

接着,process方法執行如下步驟。

(1)建立并根據請求參數建構一個表單對象。save-product操作涉及3個屬性:name、description和price。然後建立一個領域對象,并通過表單對象設定相應屬性。

(2)執行針對領域對象的業務邏輯。

(3)轉發請求到視圖(jsp頁面)。

process方法中判斷action的if代碼塊如下:

對于input-product,無需任何操作,而針對save-product,則建立一個productform對象和product對象,并将前者的屬性值複制到後者。這個步驟中,針對空字元串的複制處理将留到稍後的2.5節處理。

再次,process方法執行個體化saveproductaction類,并調用其save方法。

然後,将product對象放入httpservletrequest對象中,以便對應的視圖能通路到。

最後,process方法轉到視圖,如果action是product_input,則轉到productform.jsp頁面,否則轉到productdetails.jsp頁面。

2.3.4 action類

這個應用中隻有一個action類,負責将一個product持久化,例如資料庫。這個action類名為saveproductaction(見清單2.4)。

清單2.4 saveproductaction類

在這個示例中,saveproductaction類的save方法是一個空實作。我們會在本章後續章節中實作它。

2.3.5 視圖

示例應用包含兩個jsp頁面。第一個頁面productform.jsp對應于input-product操作,第二個頁面productdetails.jsp對應于save-product操作。productform.jsp以及productdetails.jsp頁面代碼分别見清單2.5和清單2.6。

清單2.5 productform.jsp

注意

不要用html tabel來布局表單,用css。

價格輸入域的step屬性要求浏覽器允許輸入小數數字。

清單2.6 productdetails.jsp

productform.jsp頁面包含了一個html表單。productdetails.jsp頁面通過表達式語言(el)通路httpservletrequest所包含的product對象。

作為模型2的一個應用,本示例應用可以通過如下幾種方式避免使用者通過浏覽器直接通路jsp頁面。

将jsp頁面都放到web-inf目錄下。web-inf目錄下的任何檔案或子目錄都受保護,無法通過浏覽器直接通路,但控制器依然可以轉發請求到這些頁面。

利用一個servlet filter過濾jsp頁面。

在部署描述符中為jsp頁面增加安全限制。這種方式相對容易些,無需編寫filter代碼。

2.3.6 測試應用

假定示例應用運作在本機的8080端口上,則可以通過如下url通路應用:

<code>http://localhost:8080/appdesign1/input-product</code>

浏覽器将顯示圖2.2的内容。

完成輸入後,表單送出到如下服務端url上:

<code>http://localhost:8080/appdesign1/save-product</code>