我创建了一个非常简单的“测试”控制器,它在会话中保持一个计数器来打印一个请求处理程序被调用的次数。
@Controller
@SessionAttributes("counter")
public class MyController {
@ModelAttribute("counter")
public Counter addCounter(){
System.out.println("Counter added to model");
return new Counter();
}
@RequestMapping("printCounter")
@ResponseBody
public String printCounter(Model model){
Counter counter = (Counter)model.asMap().get("counter");
int currVal = counter.getValue();
System.out.println("Current value: " + currVal);
counter.increment();
return "hello-view";
}
}
每件事都运行正常,但当我尝试在响应中使用@ResponseBody时,它会失败并出现以下错误:
java.lang.IllegalStateException: Cannot create a session after the response has been committed
我找到了几个解决方法。我知道错误发生是因为Spring在尝试将计数器添加到会话时已经刷新了响应。我不知道的是为什么春天这样做。
由于这个问题已经存在了很长时间,我想它已经完成了提议。
有没有人知道以这种方式实施它的动机是什么?
如果方法返回正文内容,为什么我们可以在会话中存储数据但是如果它返回一个视图名称呢?
提前致谢。
答案 0 :(得分:3)
@SessionAttribute
不是SpringFramework中设计最好的概念(另请参阅另一个post)。
当您转发到视图时,Spring会在调用视图之前一直处理会话属性:在控制器方法返回时,没有任何内容写入请求。但是当您使用@ResponseBody
时,方法的返回值将直接写入响应,并立即提交响应。因此,Spring可能为时已晚,无法创建会话来保存模型属性。好吧,它本来可以设计成没有必要的。但因为你总是可以通过向控制器方法提供一个HttpSession
参数来急切地创建一个会话,我想Spring的人认为这已经足够了。