在Spring MVC中,假设我使用@SessionAttribute标记来定义SessionAttribute,如下所示:
@SessionAttributes(value = "myModel")
public class MyController{
...
}
假设我忘记在SessionStatus上调用status.setComplete(),如下所示:
@RequestMapping(method = RequestMethod.POST)
public void doSomething(@ModelAttribute("myModel") MyModel model, SessionStatus status){
...
//status.setComplete(); <-- Never gets called
}
模特会永远留在会话中吗?它是否会被清除,或者当用户浏览网站时会话会不断变大和变大?
答案 0 :(得分:22)
关于在控制器退出后是否清除会话属性存在很大争议。
为了澄清一下,我们可以看一下 Spring MVC 3.1.0 RELEASE 源代码。
界面 org.springframework.web.bind.support.SessionAttributeStore 公开以下方法:
void storeAttribute(WebRequest request, String attributeName, Object attributeValue);
Object retrieveAttribute(WebRequest request, String attributeName);
void cleanupAttribute(WebRequest request, String attributeName);
默认实施是 org.springframework.web.bind.support.DefaultSessionAttributeStore
通过在Eclipse中的 cleanupAttribute()上执行“ Open Call Hierarchy ”,我们可以看到该方法由2个不同的流调用:
1) org.springframework.web.method.annotation.ModelFactory
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
}
if (!mavContainer.isRequestHandled()) {
updateBindingResult(request, mavContainer.getModel());
}
}
2) org.springframework.web.bind.annotation.support.HandlerMethodInvoker
public final void updateModelAttributes(Object handler, Map<String, Object> mavModel,
ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception {
if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
this.sessionAttributeStore.cleanupAttribute(webRequest, attrName);
}
}
...
}
很明显,在这两种情况下,只有在调用 this.sessionStatus.isComplete()时才会删除会话属性。
我挖掘了 DefaultSessionAttributeStore 的代码。在引擎盖下,它获得了真正的 HTTP Session 对象来存储属性,因此它们可能被同一会话中的其他控制器访问。
所以不,在干净的POST后不会删除会话属性。
答案 1 :(得分:12)
编辑#2:请注意,这个答案不再正确。请参阅下面的@doanduyhai's answer。
编辑:请注意,这是针对Spring 2.5并且可能,但不一定确保Spring 3.x也是如此。仔细检查文档!
这与@Gandalf所说的一致。
表单控制器为表单请求生命周期建模,从最初查看表单到表单提交。提交表单后,表单控制器的作业完成,它将从会话中删除命令对象。
因此,要将命令对象保留在表单工作流之间的会话中,您需要手动管理会话。在干净的POST之后,该对象将从会话中删除。
简而言之,我相信setComplete()方法只是一种很好的做法,但不一定是必需的。
编辑:我刚看了我的春季书就证实了这一点。我会引用它:
当未使用@SessionAttribute时,a 将创建新的命令对象 每个请求,即使在渲染时也是如此 由于绑定错误再次形成。如果 这个注释已启用, 命令对象将存储在 后续用途的会话,直到 表单成功完成。然后 此命令对象将被清除 来自会议。这通常是 当命令对象是a时使用 需要的持久对象 不同的请求相同 跟踪变化。
基本上就是我上面所说的。它将它存储在会话中,直到您A)调用setComplete()或B)控制器成功完成POST。
答案 2 :(得分:1)
你有什么理由要这么做吗?
来自这个帖子:@SessionAttribute Problem
@SessionAttributes的工作方式与SimpleFormController的sessionForm相同。它将命令(或@SessionAttributes任何对象)放在会话中,持续时间为第一个和最后一个请求(大多数时间是初始GET和最终POST)。之后,这些东西被删除了。