星空网 > 软件开发 > Java

【译】理解Spring MVC Model Attribute 和 Session Attribute

作为一名 Java Web 应用开发者,你已经快速学习了 request(HttpServletRequest)和 session(HttpSession)作用域。在设计和构建 Java Web 应用时,理解这些作用域,如何将数据与对象和这些作用域交互是十分重要的。【在 StackOverflow 上有一篇文章可以帮助你快速了解 request 和 session 作用域】

SPRING MVC 作用域

当我开始用 Spring MVC 编写 Web 应用时,我发现 Spring model 和 session attribute 有一点神秘,尤其当它们与我熟知的 HTTP request 和 session 作用域交互时。一个 Spring model 元素可以从我的 session 或者 request 中找到吗?如果是这样的话,我该如何控制?在这篇文章中,我希望讲解清楚 Spring MVC 的 model 与 session 是如何工作的。

SPRING 的 @MODELATTRIBUTE

有几种方法将数据或对象添加到 Spring 的 model 中。一般来说,数据或对象是通过 controller 层的一个注解添加进 Spring 的 model 中。在下面的例子中,使用 @ModelAttribute 添加一个名为 MyCommandBean 的实例给 key 值为『myRequestObject』的 model。

 1 public class MyController { 2  3   @ModelAttribute("myRequestObject") 4   public MyCommandBean addStuffToRequestScope() { 5     System.out.println("Inside of addStuffToRequestScope"); 6     MyCommandBean bean = new MyCommandBean("Hello World",42); 7     return bean; 8   } 9 10   @RequestMapping("/dosomething")11   public String requestHandlingMethod(Model model, HttpServletRequest request) {12     System.out.println("Inside of dosomething handler method");13 14     System.out.println("--- Model data ---");15     Map modelMap = model.asMap();16     for (Object modelKey : modelMap.keySet()) {17       Object modelValue = modelMap.get(modelKey);18       System.out.println(modelKey + " -- " + modelValue);19     }20 21     System.out.println("=== Request data ===");22     java.util.Enumeration reqEnum = request.getAttributeNames();23     while (reqEnum.hasMoreElements()) {24       String s = reqEnum.nextElement();25       System.out.println(s);26       System.out.println("==" + request.getAttribute(s));27     }28 29     return "nextpage";30   }31 32     // ... the rest of the controller33 }

在一个到达的 request 中,任何被 @ModelAttribute 注解的方法都会在 controller handler method 之前调用(就像上面例子中的 requestHandlingMethod 一样)。这些方**赶在 handler method 执行之前将数据添加进一个 java.util.Map,然后加入 Spring model 中。可以用一个示例操作展示出来。我创建了两个 JSP 页面:index.jsp 和 nextpage.jsp。index.jsp 上的一个链接用于向 MyController 中的 requestHandlingMethod() 应用触发器发送一个 request。上面的代码中,requestHandlingMethod() 将『nextpage』作为下个视图的逻辑名返回,其在这个例子中会处理为 nextpage.jsp。

【译】理解Spring MVC Model Attribute 和 Session Attribute

当这个小小的网址被修改为这种形式后,controller 的 System.out.println 展现了 @ModelAttribute 方法是如何在 handler method 之前执行的。同时也展现了 MyCommandBean 创建和加入 Spring model,并在 handler method 中可用的过程。

 1 Inside of addStuffToRequestScope 2 Inside of dosomething handler method 3 --- Model data --- 4 myRequestObject -- MyCommandBean [someString=Hello World, someNumber=42] 5 === Request data === 6 org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE 7 ==WebApplicationContext for namespace 'dispatcher-servlet': startup date [Sun Oct 13 21:40:56 CDT 2013]; root of context hierarchy 8 org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER 9 ==org.springframework.web.servlet.theme.FixedThemeResolver@204af48c10 org.springframework.web.servlet.DispatcherServlet.CONTEXT11 ==WebApplicationContext for namespace 'dispatcher-servlet': startup date [Sun Oct 13 21:40:56 CDT 2013]; root of context hierarchy12 org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping13 ==dosomething.request14 org.springframework.web.servlet.HandlerMapping.bestMatchingPattern15 ==/dosomething.*16 org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER17 ==org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@18fd23e4



现在问题变为了『Spring model 的数据存储在哪里?』是存储在标准 Java request 作用域中么?答案是 —— 对的。。。就最终而言的话。就像你从上面的输出中读到的,MyCommandBean 在 model 中,但当 handler method 执行时还不在 request 对象中。的确,handler method 执行之后,下个视图(本例中为 nextpage.jsp)显示之前为止,Spring 都没有将 model 数据作为 attribute 加入 request 中。

【译】理解Spring MVC Model Attribute 和 Session Attribute

也可以通过输出存储在 index.jsp 与 nextpage.jsp 的 HttpServletRequest 中的 attribute 展现出来。我在两个页面中都布置了一个 JSP 代码块(如下面所示),用以展现 HttpServletRequest 的 attribute。

 1 <HR /> 2 <H3>REQUEST SCOPE (KEY==VALUES)</H3> 3 <% 4   JAVA.UTIL.ENUMERATION<STRING> REQENUM = REQUEST.GETATTRIBUTENAMES(); 5   WHILE (REQENUM.HASMOREELEMENTS()) { 6     STRING S = REQENUM.NEXTELEMENT(); 7     OUT.PRINT(S); 8     OUT.PRINTLN("==" + REQUEST.GETATTRIBUTE(S)); 9 %><BR />10 <%11   }12 %>



当应用启动,index.jsp 加载完毕,你可以看到在 request 作用域中没有 attribute。

【译】理解Spring MVC Model Attribute 和 Session Attribute

在本例中,当『do something』被点击时执行 MyController 的 handler method,然后会跳转并展示 nextpage.jsp。而 nextpage.jsp 中已经编写了相同的 JSP 代码块,同样提供了 request 作用域中的 attribute。瞧,当 nextpage.jsp 渲染后,显示出在 controller 中创建的 MyCommandBean model 被加进 HttpServletRequest 作用域中了!Spring model attribute 的键值『myRequestObject』被复制后用作 request attribute 的键值。

【译】理解Spring MVC Model Attribute 和 Session Attribute

所以下一个视图呈现之前,Spring model 数据已经在 handler method 执行之前(或者之间)被拷贝给了 HttpServletRequest。

使用 SPRING MODEL 与 REQUEST 的原因

你或许想知道为什么 Spring 使用 model attribute。为何不直接把数据加到 request 对象里?我在 Rod Johnson 等人的书籍《Professional Java Development with the Spring Framework》中找到了答案。这本书关于 Spring API 的部分有一点过时(基于 Spring 2.0 编写),但是我发现该书提供了一些对于 Spring 引擎运行的扩展解释。下面是书中 model 元素部分的引用:

直接将元素加入 HttpServletRequest(像 request attributes 一样)看起来就像在服务同样的目标。这样做的理由是当看到我们为 MVC 框架设置的 requirements 时,能够更明确。它应尽可能与视图无关,这意味着我们可以合并视图技术,并不受 HttpServletRequest 的束缚。

SPRING 的 @SESSIONATTRIBUTES

所以现在你知道了 Spring 如何管理 model 数据,与如何连接标准的 Http request attribute 数据。那么关于 Spring 的 session 数据呢?

Spring 的 @SessionAttribute 在 controller 中用来指定哪一个 model attributes 需要存储到 session。事实上,Spring 文档声明了 @SessionAttributes 注解『列举需要显式地存储 session 或一些交互用的存储空间内的 model attributes 名称。』另外说一下,『一些交互存储空间』表明了 Spring MVC 试图保持与技术无关联的设计思想。

事实上,@SessionAttributes 允许你做的就是告诉 Spring 哪一个 model attributes 将在视图展现之前一同拷贝给 HttpSession。关于这一点同样可以用一个简短的代码来展示。

在 index.jsp 和 nextpage.jsp 中,我添加了额外的 JSP 代码块,使其显示 HttpSession attributes。

 1 <H3>SESSION SCOPE (KEY==VALUES)</H3> 2 <% 3  JAVA.UTIL.ENUMERATION<STRING> SESSENUM = REQUEST.GETSESSION() 4   .GETATTRIBUTENAMES(); 5  WHILE (SESSENUM.HASMOREELEMENTS()) { 6   STRING S = SESSENUM.NEXTELEMENT(); 7   OUT.PRINT(S); 8   OUT.PRINTLN("==" + REQUEST.GETSESSION().GETATTRIBUTE(S)); 9 %><BR />10 <%11  }12 %>



我使用 @SessionAttributes 注解 MyController,使其将同一个 model attributes(myRequestObject)放入 Spring session 中。

1 @CONTROLLER2 @SESSIONATTRIBUTES("MYREQUESTOBJECT")3 PUBLIC CLASS MYCONTROLLER {4  ...5 }



另外在 controller 的 handler method 中添加代码显示 HttpSession 中的 attributes(就像显示 HttpServletRequest 中的 attributes 一样)。

 1 @SUPPRESSWARNINGS("RAWTYPES") 2 @REQUESTMAPPING("/DOSOMETHING") 3 PUBLIC STRING REQUESTHANDLINGMETHOD(MODEL MODEL, HTTPSERVLETREQUEST REQUEST, HTTPSESSION SESSION) { 4  SYSTEM.OUT.PRINTLN("INSIDE OF DOSOMETHING HANDLER METHOD"); 5  6  SYSTEM.OUT.PRINTLN("--- MODEL DATA ---"); 7  MAP MODELMAP = MODEL.ASMAP(); 8  FOR (OBJECT MODELKEY : MODELMAP.KEYSET()) { 9   OBJECT MODELVALUE = MODELMAP.GET(MODELKEY);10   SYSTEM.OUT.PRINTLN(MODELKEY + " -- " + MODELVALUE);11  }12 13  SYSTEM.OUT.PRINTLN("=== REQUEST DATA ===");14  JAVA.UTIL.ENUMERATION<STRING> REQENUM = REQUEST.GETATTRIBUTENAMES();15  WHILE (REQENUM.HASMOREELEMENTS()) {16   STRING S = REQENUM.NEXTELEMENT();17   SYSTEM.OUT.PRINTLN(S);18   SYSTEM.OUT.PRINTLN("==" + REQUEST.GETATTRIBUTE(S));19  }20 21  SYSTEM.OUT.PRINTLN("*** SESSION DATA ***");22  ENUMERATION<STRING> E = SESSION.GETATTRIBUTENAMES();23  WHILE (E.HASMOREELEMENTS()){24   STRING S = E.NEXTELEMENT();25   SYSTEM.OUT.PRINTLN(S);26   SYSTEM.OUT.PRINTLN("**" + SESSION.GETATTRIBUTE(S));27  }28 29  RETURN "NEXTPAGE";30 }



现在,我们可以看见加上 @SessionAttributes 注解后,Spring MVC 处理一个 HTTP 请求之前、之间和之后的 session 对象情况。下面显示了结果。首先,当 index.jsp 显示时(请求被 Spring MVC 发送和处理之前),我们可以看见 HttpServletRequest 和 HttpSession 都没有 attribute 数据。

【译】理解Spring MVC Model Attribute 和 Session Attribute

handler method 执行时(requestHandlingMethod),你可以看见 MyCommandBean 被添加进 Spring model attributes,但是还没有加入 HttpServletRequest 或 HttpSession 作用域。

【译】理解Spring MVC Model Attribute 和 Session Attribute

但是 handler method 执行后和 nextpage.jsp 显示时,你可以看见 model attribute 数据(MyCommandBean)已经作为一个 attribute 被复制给了 HttpServletRequest 和 HttpSession(拥有相同的 attribute key)。

【译】理解Spring MVC Model Attribute 和 Session Attribute

控制 SESSION ATTRIBUTES

现在你已经理解了 Spring model 和 session attribute 数据如何添加进 HttpServletRequest 与 HttpSession。或许又开始关心怎么管理 Spring session 中的数据。Spring 提供了一个方法移除 Spring session attributes,同时也会从 HttpSession 中移除(不需要删除整个 HttpSession)。简单地将一个 Spring SessionStatus 对象作为参数加入一个 controller handler method 中。在此方法中,使用 SessionStatus 对象结束这个 Spring session。

1 @REQUESTMAPPING("/ENDSESSION")2 PUBLIC STRING NEXTHANDLINGMETHOD2(SESSIONSTATUS STATUS){3  STATUS.SETCOMPLETE();4  RETURN "LASTPAGE";5 }

总结

希望这篇文章能够帮助你理解 Spring model 和 session attributes。这并不神奇,仅仅是一个理解 HttpSession 和 HttpServletRequest 如何存储 Spring model 和 session attributes 的问题。我已经将展示用的代码放在了 Intertech Web site 上。如果你对继续探索与理解 Spring model 和 session 感兴趣,尽管从这里下载吧。

如果你对深入学习 Spring(或任何一种 Java 技术)感兴趣,可以考虑马上注册,成为 Intertech 的一员。在这里学到更多与注册。


原文链接: Intertech
首发于 importnew,译文链接: http://www.importnew.com/16782.html




原标题:【译】理解Spring MVC Model Attribute 和 Session Attribute

关键词:Spring

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流