深入理解springMVC中的Model和Session屬性
作為一個javaweb應用的開發(fā)者,你快速學習了request(HttpRequest)和Session(HttpSession)的范圍,理解這些范圍并且在這些范圍內(nèi)數(shù)據(jù)和對象是如何是進出的對設計和構建web應用是非常關鍵的。
springMVC的范圍
當我用springMVC寫web應用的時候,我發(fā)現(xiàn)spring model和session有一點神秘—特別是與http reques、和session范圍關聯(lián)起來這些我都已經(jīng)了解了。
spring的model元素會在我的session或者request中找到嗎,如果是這樣,我怎么控制這個過程呢,在這篇文章中我希望能夠解密springMVC的model和session是如何工作的。
spring的@MODELATTRIBUTE
這里有好幾種向spring的Model添加數(shù)據(jù)的方式。數(shù)據(jù)或者對象通常通過在controller上的注釋方法添加到spring中的model中去。
下邊這個例子中,@ModelAttribute用來將MyCommandBean的實例以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 }
在一個請求的request中,任何使用@ModelAttribute注解的方法會在controller的handler方法(像上邊例子匯總的requestHandlingMethod 方法)之前被調(diào)用。
在這些handler方法執(zhí)行前,這些方法把數(shù)據(jù)增加到java.util.map中最終添加到spring Model中去。這可以通過一個簡單的實驗證明,我創(chuàng)建了兩個jsp頁面:index.jsp和nextpage.jsp。
index.jsp中的鏈接用來發(fā)送request到web應用中來觸發(fā)Mycontroller中的requestHandlingMethod()方法。requestHandlingMethod()方法返回“nextpage”作為下一個視圖邏輯上的名字,在這個例子中我們解析為nextpage.jsp。
當這個小的web站點用這種方式執(zhí)行的時候,controller里邊的System.out.println方法表明了@ModelAttribute方法是如何在handler方法之前運行的。
它同樣也展示了這個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ù)存儲在哪?”它存儲在標準的java request范圍中嗎?答案是“是的”,從上邊的輸出可以看出,當handler方法執(zhí)行的時候MyCommandBean是在model中,但是沒有在request對象中。
確實,spring不會把model數(shù)據(jù)作為request的屬性,直到執(zhí)行handler方法之后和下一個視圖之前(在這個例子中是nextpage.jsp)
這也可以通過打印存儲在index.jsp和nextpage.jsp中的HttpServletRequest中的數(shù)據(jù)展示出來,這兩個頁面我都使用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 /> <% } %>
當應用打開并且index.jsp展現(xiàn)的時候,你可以看到在Request范圍內(nèi)沒有屬性
do something Request Scope(key==values)
在這個例子中,當“do something”連接被點擊的時候觸發(fā)了MyController的handler方法執(zhí)行,繼而導致nextpage.jsp被執(zhí)行,考慮到這是同樣的jsp內(nèi)容,再次提出不免有些啰嗦。當nextpage.jsp提出的時候,表明model的MyCommandBean在controller里被創(chuàng)建,并已經(jīng)被加到HttpServletRequest范圍中去了。這個spring model的屬性key已經(jīng)被復制,并且當做Request屬性的key。
所以spring model數(shù)據(jù)的創(chuàng)建要早于handler方法的執(zhí)行,在下一個視圖加載前就已經(jīng)被復制到HttpServletRequest中去了。
spring Model和Request后邊的原因
你可能會疑惑為什么spring使用model屬性,為什么不直接將數(shù)據(jù)加到Request對象中去呢,在Rod Johnson的書中我找到了這個問題的答案。下邊就是來自這本書的關于model元素的文本。
直接給HttpServletRequest(或者Request屬性)增加元素看起來實現(xiàn)了相同的目的,做這件事的原因很明確,當我們查看我們?yōu)镸VC框架設置的要求的時候,應該盡可能使視圖無關的,意味著視圖技術不和HttpServletRequest綁定。
Spring的@SESSIONATTRIBUTE
現(xiàn)在你知道spring的model數(shù)據(jù)是如何管理的并且是如何和Httprequset屬性關聯(lián)的,那么spring的session數(shù)據(jù)呢?
spring的@SessionAttributes在controller上使用指定model屬性應該存儲在Session中。實際上,精確的講spring開發(fā)文檔已經(jīng)表明了@SessionAttributes注解“列出了應該存儲在Session中或者對話存儲中model屬性的名字”。
實際上,@SessionAttribute允許你做的是在加載視圖之前,告訴spring你的哪一個model Attributes將會被復制到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)在,當我們使用@SessionAttributes注解后我們可以看到什么在session對象中,包括springMVC處理一個http 請求的前中后的過程里。結果如下,首先是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ù)確實被作為屬性復制到HttpServletRequest和httpSession中。
控制對話屬性
現(xiàn)在你已經(jīng)對spring model和Session屬性數(shù)據(jù)是如何加載到HttpServletReq。uest和httpSession有很好的理解了。但你依舊對管理spring Session中的數(shù)據(jù)心生疑惑。spring提供了移除spring Session屬性的方式,也可以在HttpSession中移除。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Spring boot集成swagger2生成接口文檔的全過程
這篇文章主要給大家介紹了關于Spring boot集成swagger2生成接口文檔的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Spring boot具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-09-09SpringBoot中使用Redisson的實現(xiàn)示例
Redission是一個強大的Java庫,用于構建和管理分布式系統(tǒng)中的緩存和任務調(diào)度,本文主要介紹了SpringBoot中使用Redisson的實現(xiàn)示例,感興趣的可以了解一下2023-12-12