Spring學(xué)習(xí)筆記二----Web MVC
Posted on 2006-06-24 10:59 柳隨風(fēng) 閱讀(5735) 評(píng)論(1) 編輯 收藏 所屬分類: 開源框架花了兩個(gè)星期學(xué)習(xí) Spring WebMVC , 總體感覺收獲不少,感受比較深的是 Spring 框架的確解決了在 j2EE 開發(fā)中經(jīng)常遇到的問題 , 自己也寫了一個(gè)覆蓋框架主要功能的簡單例子,和大家一起交流、分享一下,如有錯(cuò)誤,歡迎大家多指正。
-、相對(duì)于WebWork的特性
1、? 表單處理功能比較強(qiáng)大,將數(shù)據(jù)初始化、展現(xiàn)、封裝、效驗(yàn)等功能做了分解,代碼功能更加清晰(優(yōu))
舉個(gè)例子,我們要更新一個(gè)產(chǎn)品的信息,一般實(shí)現(xiàn)步驟如下:
a.?????? 根據(jù)主鍵查找到該產(chǎn)品信息,作為 Request 屬性對(duì)象傳遞到編輯頁面
b.?????? 在編輯頁面時(shí)往往還需要其他一些數(shù)據(jù),如每個(gè)產(chǎn)品都有產(chǎn)品類別,因此也會(huì)將相關(guān)數(shù)據(jù)作為 Request 屬性對(duì)象傳遞到編輯頁面
c.?????? 完成對(duì)編輯頁面客戶端效驗(yàn)
d.?????? 編輯頁面提交后,將頁面輸入數(shù)據(jù)封裝成產(chǎn)品對(duì)象,然后效驗(yàn),如果有錯(cuò)誤,需要將此時(shí)的產(chǎn)品對(duì)象再返回到編輯頁面,提示用戶錯(cuò)誤信息。
e.?????? 效驗(yàn)正常后,調(diào)用業(yè)務(wù)邏輯方法處理后,頁面調(diào)轉(zhuǎn)到查詢頁面,注意避免用戶刷新重復(fù)提交,往往我們使用 redirect 方式調(diào)整
而這些功能在
Spring
框架時(shí)如何實(shí)現(xiàn)的,只需要大家繼承于
org.springframework.web.servlet.mvc.SimpleFormController
類,針對(duì)上述步驟,我們需要分別重寫如下方法:
?a、?
protected
?Object?formBackingObject(HttpServletRequest?request)?
throws
?SimpleException
?b、
protected
?Map?referenceData(HttpServletRequest?request,?Object?command,???Errors?errors)?
throws
?SimpleException
????
?d、
protected
?
void
?onBindAndValidate(HttpServletRequest?request,???Object?command,?BindException?errors)?
throws
?SimpleException
?e、
protected
?ModelAndView?onSubmit(HttpServletRequest?request,????????????HttpServletResponse?response,?Object?command,?BindException?errors)
throws
?SimpleException
說明:
?SimpleException 是自定義的異常,我們?cè)趯?shí)際開發(fā)中都會(huì)定義自己的業(yè)務(wù)異常
?Spring 在上述步驟時(shí)基本都有其他的實(shí)現(xiàn)方法,如 d 步驟也可調(diào)用 onBind 帶 BindException 參數(shù)的方法進(jìn)行效驗(yàn), e 步驟就有更多的同名方法實(shí)現(xiàn),我們可以根據(jù)不同的應(yīng)用場景選擇相對(duì)應(yīng)的方法
2、? 容器負(fù)責(zé)截取異常,根據(jù)配置提供相關(guān)異常展現(xiàn)頁面(優(yōu))
目前在 WebWork 中異常直接是由 ServletDispatcher 類捕獲相關(guān)異常,發(fā)送 500 錯(cuò)誤, WebWork 中實(shí)際上還是比較容易實(shí)現(xiàn)該功能,定義一個(gè)攔截器,注意必須配置時(shí)將其配置為第一個(gè)攔截器,在調(diào)用攔截方法中捕獲系統(tǒng)相關(guān)異常,根據(jù)配置調(diào)整到異常錯(cuò)誤處理頁面
我以前在 webwork 實(shí)現(xiàn)都是定義在 Action, 攔截器中捕獲異常,將異常綁定在 ActionError 中,然后跳轉(zhuǎn)到錯(cuò)誤頁面,
3、? 附件上傳功能比較方便(優(yōu))
4、? url 映射是可以采用通配符匹配的形式,更加靈活(優(yōu))
5、? 值對(duì)象數(shù)據(jù)封裝比較麻煩,如果有屬性為整型,頁面值為空串時(shí)無法轉(zhuǎn)換為空指針(缺)
6、? Spring 將上下文環(huán)境對(duì)象作為 Request 屬性對(duì)象傳遞,感覺這一塊比較冗余,沒有必要,除了必要的配置信息需要傳遞,其他沒有必要,不夠精確,在方面 webwork 比較好,它是只將 Action 對(duì)象作為 Request 屬性對(duì)象傳遞(缺)
二、處理請(qǐng)求過程 ???
DispatcherServlet?? 處理請(qǐng)求過程
1 、綁定上下文對(duì)象于 DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE 請(qǐng)求屬性
2 、綁定 locale resolver, 解析本地化信息(沒有忽略該過程)
3 、綁定 theme resolver ,確定使用主題( 沒有忽略該過程)
4 、判斷是否為 multipart, 如果是就解析封裝
5 、查找處理器、執(zhí)行對(duì)應(yīng)的攔截器,獲取視圖模型
6 、根據(jù) view resolver 選擇相對(duì)應(yīng)的視圖
1 - 6 過程中如有異常,可以被 handlerexception resolver 捕獲
表單處理過程:
1、? 判斷是否是提交表單請(qǐng)求,
2、? 如果不是,調(diào)用 showNewForm(request, response, errors) 方法,
2.1 、 如果子類重寫方法調(diào)用 formBackingObject 方法
2.2 、 如果有重寫 referenceData 方法,
2.3 、 如果屬性 bindOnNewForm=true ,系統(tǒng)將 request 對(duì)應(yīng)參數(shù)值綁定到對(duì)應(yīng)的對(duì)象中
2.4 、 最后根據(jù)屬性 formView 跳轉(zhuǎn)到相對(duì)應(yīng)的表單錄入頁面
3 、如果是表單提交請(qǐng)求 ?
3.1 如果不是會(huì)話表單或會(huì)話中有對(duì)應(yīng)表單對(duì)象,
3.1.1 、 系統(tǒng)從會(huì)話中獲取或者調(diào)用調(diào)用 formBackingObject 方法創(chuàng)建數(shù)據(jù)綁定對(duì)象, 根據(jù)頁面輸入值綁定數(shù)據(jù)對(duì)象,中間可能會(huì)產(chǎn)生綁定異常
?3.1.2 、 如子類重寫了 onBind 方法,會(huì)回調(diào)對(duì)應(yīng)的方法,對(duì)應(yīng)綁定異常會(huì)一直傳遞下去
3.1.3 、 如果子類有相對(duì)應(yīng)的效驗(yàn)類,并且需要在綁定時(shí)效驗(yàn),就回調(diào)對(duì)應(yīng)的效驗(yàn)類的效驗(yàn)方法,對(duì)應(yīng)綁定異常會(huì)一直傳遞下去
3.1.4 、 如果子類重寫了 onBindAndValidate 方法,系統(tǒng)會(huì)回調(diào)對(duì)應(yīng)的綁定效驗(yàn)方法
3.1.5 、 ? 如果有異常,調(diào)用 showForm(request, response, errors) ,不是會(huì)話表單,重新獲取輔助數(shù)據(jù),執(zhí)行方法 referenceData 返回表單編輯頁面。
3.1.6 、 如果無異常調(diào)用 onSubmit(request, response, command, errors), 返回成功提交后的頁面
3 . 2 如果是會(huì)話表單并且會(huì)話中沒有該表單對(duì)象,會(huì)根據(jù) formBackingObject 初始化值對(duì)象 , 然后處理過程和 3.1.1 執(zhí)行過程一致。
說明:
步驟
3.1.1
會(huì)回調(diào)一次
formBackingObject
方法,然后再綁定頁面數(shù)據(jù),為何回調(diào)該方法的原因是因?yàn)槲覀冊(cè)陧撁嬷杏行傩圆恍枰@示,如果只通過頁面封裝數(shù)據(jù),哪些不需要顯示的就無法封裝數(shù)據(jù)。因此在使用該方法的時(shí)候特別要注意性能問題,避免在該方法中調(diào)用數(shù)據(jù)庫查詢等等影響性能的方法(我還是使用
hidden
控件,雖然安全性低了一點(diǎn))
個(gè)人認(rèn)為步驟
2.3
位置應(yīng)該
2.1
在前,因?yàn)橥覀冊(cè)趯?shí)際使用中是先根據(jù)頁面?zhèn)鬟f的值來再構(gòu)造對(duì)應(yīng)的值對(duì)象的。并且這樣的話
頁面?zhèn)鬟f的變量會(huì)覆蓋
formBackingObject
值
個(gè)人建議盡可能的不要使用會(huì)話表單
三、開發(fā)注意事項(xiàng)、心得
1、? 自定義攔截器只需實(shí)現(xiàn) org.springframework.web.servlet.HandlerInterceptor 接口
2、? 上傳多個(gè)文件時(shí)注意事項(xiàng):建議采用重寫
?protected ModelAndView onSubmit(HttpServletRequest request,HttpServletResponse response, Object command, BindException errors)?? throws Exception
方法,直接通過 MultiHttpServletRequest getFileMap() 方法,對(duì)應(yīng) map 存儲(chǔ)對(duì)象為 MultipartFile 接口實(shí)現(xiàn)類,建議通過接口訪問,這樣如果通過其他方式處理上傳的,只需要修改配置文件,通過對(duì)應(yīng)的 transferTo 方法處理上傳的文件。
3、? 在 web 環(huán)境中如何獲取應(yīng)用上下文對(duì)象
ApplicationContext acx=(ApplicationContext)req.getAttribute(
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
4、? 在配置 multipart 解析器 配置時(shí) id="multipartResolver"
<bean id="multipartResolver"? class="
org.springframework.web.multipart.commons.CommonsMultipartResolver">
??
??????? <property name="maxUploadSize"><value>10485760</value>
</property>
</bean>
5、? 在配置資源信息 ? 配置時(shí) id= messageSource
<bean id="messageSource" class="
org.springframework.context.support.ResourceBundleMessageSource">
6、?
如果視圖要采用
redirect
方式,配置類似如下
????
??
?<property name="successView">
???
??????????? <value>redirect:/viewpro.action</value>
???? </property>
?
??
7
、
如果要實(shí)現(xiàn)一個(gè)簡單的頁面數(shù)據(jù)綁定功能
?
只需要繼承
BaseCommandController
類,重寫
handleRequestInternal(
HttpServletRequest request, HttpServletResponse response)
throws Exception
方法
?
在該方法中只要?jiǎng)?chuàng)建數(shù)據(jù)綁定對(duì)象,調(diào)用綁定方法,然后封裝在對(duì)應(yīng)的視圖中
8
、標(biāo)簽庫的使用,請(qǐng)參考如下文章:
?http://www-128.ibm.com/developerworks/cn/java/j-jstl0211/index.html
四、簡單例子
?
我的應(yīng)用環(huán)境
????? AppServer? weblogic814
????? 框架版本 ?? Spring ?1.2 RC2
?????
數(shù)據(jù)庫
???? Oracle 9.2.0.1
運(yùn)行例子注意事項(xiàng):
1 、修改 build.properties
lib.src 對(duì)應(yīng)目錄改為你本機(jī) spring 目錄
?????? 2 、執(zhí)行數(shù)據(jù)庫腳本 product.sql, 修改對(duì)應(yīng)的 jdbc.properties 文件
3 、如果使用其他的 AppServer 注意在 lib 中加入相關(guān)數(shù)據(jù)庫的驅(qū)動(dòng),并設(shè)定 Request 請(qǐng)求中數(shù)據(jù)編碼格式為 GBK
4
、如果使用其他數(shù)據(jù)庫,修改
jdbc.properties
、
hibernate
相關(guān)屬性,并且修改
product.hbm.xml
的主鍵生成規(guī)則,本例子是用
sequence
生成。
代碼下載:
http://www.tkk7.com/Files/beauty_beast/springweb_example.rar
? 五、遺留問題
1、? 如何將頁面數(shù)據(jù)和 List,Map 對(duì)象綁定?
2、?
使用標(biāo)準(zhǔn)標(biāo)簽庫時(shí),頁面不能含有中文字符,否則拋出異常、是否標(biāo)簽庫對(duì)字符集有限制?