深入理解springMVC中的Model和Session屬性
作為一個(gè)javaweb應(yīng)用的開發(fā)者,你快速學(xué)習(xí)了request(HttpRequest)和Session(HttpSession)的范圍,理解這些范圍并且在這些范圍內(nèi)數(shù)據(jù)和對(duì)象是如何是進(jìn)出的對(duì)設(shè)計(jì)和構(gòu)建web應(yīng)用是非常關(guān)鍵的。
springMVC的范圍
當(dāng)我用springMVC寫web應(yīng)用的時(shí)候,我發(fā)現(xiàn)spring model和session有一點(diǎn)神秘—特別是與http reques、和session范圍關(guān)聯(lián)起來這些我都已經(jīng)了解了。
spring的model元素會(huì)在我的session或者request中找到嗎,如果是這樣,我怎么控制這個(gè)過程呢,在這篇文章中我希望能夠解密springMVC的model和session是如何工作的。
spring的@MODELATTRIBUTE
這里有好幾種向spring的Model添加數(shù)據(jù)的方式。數(shù)據(jù)或者對(duì)象通常通過在controller上的注釋方法添加到spring中的model中去。
下邊這個(gè)例子中,@ModelAttribute用來將MyCommandBean的實(shí)例以key值為myRequestObject添加到model中去
@Controller public class MyController { @ModelAttribute("myRequestObject") public MyCommandBean addStuffToRequestScope() { System.out.println("Inside of addStuffToRequestScope"); MyCommandBean bean = new MyCommandBean("Hello World",42); return bean; } @RequestMapping("/dosomething") public String requestHandlingMethod(Model model, HttpServletRequest request) { System.out.println("Inside of dosomething handler method"); System.out.println("--- Model data ---"); Map modelMap = model.asMap(); for (Object modelKey : modelMap.keySet()) { Object modelValue = modelMap.get(modelKey); System.out.println(modelKey + " -- " + modelValue); } System.out.println("=== Request data ==="); java.util.Enumeration reqEnum = request.getAttributeNames(); while (reqEnum.hasMoreElements()) { String s = reqEnum.nextElement(); System.out.println(s); System.out.println("==" + request.getAttribute(s)); } return "nextpage"; } // ... the rest of the controller }
在一個(gè)請(qǐng)求的request中,任何使用@ModelAttribute注解的方法會(huì)在controller的handler方法(像上邊例子匯總的requestHandlingMethod 方法)之前被調(diào)用。
在這些handler方法執(zhí)行前,這些方法把數(shù)據(jù)增加到j(luò)ava.util.map中最終添加到spring Model中去。這可以通過一個(gè)簡單的實(shí)驗(yàn)證明,我創(chuàng)建了兩個(gè)jsp頁面:index.jsp和nextpage.jsp。
index.jsp中的鏈接用來發(fā)送request到web應(yīng)用中來觸發(fā)Mycontroller中的requestHandlingMethod()方法。requestHandlingMethod()方法返回“nextpage”作為下一個(gè)視圖邏輯上的名字,在這個(gè)例子中我們解析為nextpage.jsp。
當(dāng)這個(gè)小的web站點(diǎn)用這種方式執(zhí)行的時(shí)候,controller里邊的System.out.println方法表明了@ModelAttribute方法是如何在handler方法之前運(yùn)行的。
它同樣也展示了這個(gè)MyCommandBean被創(chuàng)建和添加到springModel中去的過程。
Inside of addStuffToRequestScope Inside of dosomething handler method --- Model data --- myRequestObject -- MyCommandBean [someString=Hello World, someNumber=42] === Request data === org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE ==WebApplicationContext for namespace 'dispatcher-servlet': startup date [Sun Oct 13 21:40:56 CDT 2013]; root of context hierarchy org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER ==org.springframework.web.servlet.theme.FixedThemeResolver@204af48c org.springframework.web.servlet.DispatcherServlet.CONTEXT ==WebApplicationContext for namespace 'dispatcher-servlet': startup date [Sun Oct 13 21:40:56 CDT 2013]; root of context hierarchy org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping ==dosomething.request org.springframework.web.servlet.HandlerMapping.bestMatchingPattern ==/dosomething.* org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER ==org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@18fd23e4
現(xiàn)在的問題是“springModel數(shù)據(jù)存儲(chǔ)在哪?”它存儲(chǔ)在標(biāo)準(zhǔn)的java request范圍中嗎?答案是“是的”,從上邊的輸出可以看出,當(dāng)handler方法執(zhí)行的時(shí)候MyCommandBean是在model中,但是沒有在request對(duì)象中。
確實(shí),spring不會(huì)把model數(shù)據(jù)作為request的屬性,直到執(zhí)行handler方法之后和下一個(gè)視圖之前(在這個(gè)例子中是nextpage.jsp)
這也可以通過打印存儲(chǔ)在index.jsp和nextpage.jsp中的HttpServletRequest中的數(shù)據(jù)展示出來,這兩個(gè)頁面我都使用jsp來展示HttpServletRequest的屬性
Request Scope (key==values) <% java.util.Enumeration<String> reqEnum = request.getAttributeNames(); while (reqEnum.hasMoreElements()) { String s = reqEnum.nextElement(); out.print(s); out.println("==" + request.getAttribute(s)); %><br /> <% } %>
當(dāng)應(yīng)用打開并且index.jsp展現(xiàn)的時(shí)候,你可以看到在Request范圍內(nèi)沒有屬性
do something Request Scope(key==values)
在這個(gè)例子中,當(dāng)“do something”連接被點(diǎn)擊的時(shí)候觸發(fā)了MyController的handler方法執(zhí)行,繼而導(dǎo)致nextpage.jsp被執(zhí)行,考慮到這是同樣的jsp內(nèi)容,再次提出不免有些啰嗦。當(dāng)nextpage.jsp提出的時(shí)候,表明model的MyCommandBean在controller里被創(chuàng)建,并已經(jīng)被加到HttpServletRequest范圍中去了。這個(gè)spring model的屬性key已經(jīng)被復(fù)制,并且當(dāng)做Request屬性的key。
所以spring model數(shù)據(jù)的創(chuàng)建要早于handler方法的執(zhí)行,在下一個(gè)視圖加載前就已經(jīng)被復(fù)制到HttpServletRequest中去了。
spring Model和Request后邊的原因
你可能會(huì)疑惑為什么spring使用model屬性,為什么不直接將數(shù)據(jù)加到Request對(duì)象中去呢,在Rod Johnson的書中我找到了這個(gè)問題的答案。下邊就是來自這本書的關(guān)于model元素的文本。
直接給HttpServletRequest(或者Request屬性)增加元素看起來實(shí)現(xiàn)了相同的目的,做這件事的原因很明確,當(dāng)我們查看我們?yōu)镸VC框架設(shè)置的要求的時(shí)候,應(yīng)該盡可能使視圖無關(guān)的,意味著視圖技術(shù)不和HttpServletRequest綁定。
Spring的@SESSIONATTRIBUTE
現(xiàn)在你知道spring的model數(shù)據(jù)是如何管理的并且是如何和Httprequset屬性關(guān)聯(lián)的,那么spring的session數(shù)據(jù)呢?
spring的@SessionAttributes在controller上使用指定model屬性應(yīng)該存儲(chǔ)在Session中。實(shí)際上,精確的講spring開發(fā)文檔已經(jīng)表明了@SessionAttributes注解“列出了應(yīng)該存儲(chǔ)在Session中或者對(duì)話存儲(chǔ)中model屬性的名字”。
實(shí)際上,@SessionAttribute允許你做的是在加載視圖之前,告訴spring你的哪一個(gè)model Attributes將會(huì)被復(fù)制到httpSession中去。
Session Scope (key==values) <% java.util.Enumeration<String> sessEnum = request.getSession() .getAttributeNames(); while (sessEnum.hasMoreElements()) { String s = sessEnum.nextElement(); out.print(s); out.println("==" + request.getSession().getAttribute(s)); %><br /> <% } %>
我在MyController中用@SessionAttributes做注解,來把同樣的model屬性加到spring Session中去。
@Controller @SessionAttributes("myRequestObject") public class MyController { ... }
我同樣也在handler方法中增加了代碼來展示什么屬性在httpSession中
@SuppressWarnings("rawtypes") @RequestMapping("/dosomething") public String requestHandlingMethod(Model model, HttpServletRequest request, HttpSession session) { System.out.println("Inside of dosomething handler method"); System.out.println("--- Model data ---"); Map modelMap = model.asMap(); for (Object modelKey : modelMap.keySet()) { Object modelValue = modelMap.get(modelKey); System.out.println(modelKey + " -- " + modelValue); } System.out.println("=== Request data ==="); java.util.Enumeration<String> reqEnum = request.getAttributeNames(); while (reqEnum.hasMoreElements()) { String s = reqEnum.nextElement(); System.out.println(s); System.out.println("==" + request.getAttribute(s)); } System.out.println("*** Session data ***"); Enumeration<String> e = session.getAttributeNames(); while (e.hasMoreElements()){ String s = e.nextElement(); System.out.println(s); System.out.println("**" + session.getAttribute(s)); } return "nextpage"; }
現(xiàn)在,當(dāng)我們使用@SessionAttributes注解后我們可以看到什么在session對(duì)象中,包括springMVC處理一個(gè)http 請(qǐng)求的前中后的過程里。結(jié)果如下,首先是index.jsp展示,我們可以看到在HttpServletRequest和httpSession中都沒有屬性數(shù)據(jù)。
do something Request Scope(key == values) Session Scope(key == values)
在handler方法執(zhí)行過程中(HttpServletRequest),你可以看到MyCommandBean被加入到spring model屬性中去,但是沒有在HttpServletRequest和HttpSession范圍中。
但是在handler方法執(zhí)行之后并且nextpage.jsp被加載,你可以看到model的屬性數(shù)據(jù)確實(shí)被作為屬性復(fù)制到HttpServletRequest和httpSession中。
控制對(duì)話屬性
現(xiàn)在你已經(jīng)對(duì)spring model和Session屬性數(shù)據(jù)是如何加載到HttpServletReq。uest和httpSession有很好的理解了。但你依舊對(duì)管理spring Session中的數(shù)據(jù)心生疑惑。spring提供了移除spring Session屬性的方式,也可以在HttpSession中移除。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring boot集成swagger2生成接口文檔的全過程
這篇文章主要給大家介紹了關(guān)于Spring boot集成swagger2生成接口文檔的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Spring Data JPA 復(fù)雜/多條件組合分頁查詢
本文主要介紹了Spring Data JPA 復(fù)雜/多條件組合分頁查詢的相關(guān)資料。具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-04-04Spring?@Cacheable指定失效時(shí)間實(shí)例
這篇文章主要介紹了Spring?@Cacheable指定失效時(shí)間實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12SpringBoot中使用Redisson的實(shí)現(xiàn)示例
Redission是一個(gè)強(qiáng)大的Java庫,用于構(gòu)建和管理分布式系統(tǒng)中的緩存和任務(wù)調(diào)度,本文主要介紹了SpringBoot中使用Redisson的實(shí)現(xiàn)示例,感興趣的可以了解一下2023-12-12Java項(xiàng)目中獲取路徑的絕對(duì)路徑問題和相對(duì)路徑問題
這篇文章主要介紹了如何Java項(xiàng)目中獲取文件地址,在 Java 項(xiàng)目中我們經(jīng)常會(huì)讀取配置文件,但是文件的路徑在獲取時(shí)我們是怎么得到的?下面我們就一起進(jìn)入文章學(xué)習(xí)該內(nèi)容吧,需要的朋友可以參考下2022-02-02