SpringMVC @SessionAttributes 使用

@SessionAttributes 只能作用在类上,作用是将指定的Model中的键值对添加至session中,方便在下一次请求中使用。

简单示例

  • 目标是通过 @SessionAttributes 注解将Model中attrName为 "user","age","name" 的值添加至 session 中
 @Controller
@RequestMapping("/testSessionAttribute")
@SessionAttributes(value = {"user","age","name"})
public class TestSessionAttributeController { @ModelAttribute("user")
public User addUser(){
User user = new User();
user.setName("James");
user.setAge(29);
return user;
} @RequestMapping("/testHandler")
public String testHandler(Model model, String age, String name){
16 model.addAttribute("age",age);
17 model.addAttribute("name",name);
System.out.println(age);
System.out.println(name);
return "result";
}
}

对应的jsp代码如下:

 <body>
${sessionScope.user.age}
${sessionScope.user.name}
<br/>
${sessionScope.age}
${sessionScope.name}
</body>

通过实例可以得出一下结论:

  1. 不论是利用@ModelAttribute添加至model的数据,还是手动添加至model的数据,均遵循 @SessionAttributes 的规则

清除@SessionAttributes向session中添加的值

如果需要清除通过@SessionAttribute添加至 session 中的数据,则需要在controller 的 handler method中添加 SessionStatus参数,在方法体中调用SessionStatus#setComplete。

需要注意的是,此时清除的只是该Controller通过@SessionAttribute添加至session的数据(当然,如果不同controller的@SessionAttribute拥有相同的值,则也会清除)

@Controller
@RequestMapping("/testSessionAttribute")
@SessionAttributes(value = {"user","age","name"})
public class TestSessionAttributeController { .......................... @RequestMapping("/removeSessionAttributes")
public String removeSessionAttributes(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "result";
}
}

通过@ModelAttributes和@SessionAttributes共同添加至session中的数据,只会添加一次

在没用使用SessionStatus清除过之前,通过@ModelAttributes和@SessionAttributes共同添加至session中的数据并不会更新,如下例:

 @Controller
@RequestMapping("/testSessionAttribute")
@SessionAttributes(value = {"user","age","name"})
public class TestSessionAttributeController { public static int age = 29;
@ModelAttribute("user")
public User addUser(){
User user = new User();
user.setName("James");
user.setAge(age++);
return user;
} @RequestMapping("/testHandler")
public String testHandler(Model model, String age, String name){
model.addAttribute("age",age);
model.addAttribute("name",name);
System.out.println(age);
System.out.println(name);
return "result";
} }
 <body>
${sessionScope.user.age}
${sessionScope.user.name}
<br/>
${sessionScope.age}
${sessionScope.name}
</body>

第一次请求:http://localhost:8080/testSessionAttribute/testHandler.action?name=James&age=29

结果:

29 James 
29 James

第二次请求:http://localhost:8080/testSessionAttribute/testHandler.action?name=James&age=30

29 James 
30 James

原因是,在org.springframework.web.bind.annotation.support.HandlerMethodInvoker#invokeHandlerMethod中进行了如下操作:

 public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
try {
boolean debug = logger.isDebugEnabled();
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
8 Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
9 if (attrValue != null) {
10 implicitModel.addAttribute(attrName, attrValue);
11 }
}
for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
if (debug) {
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
}
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
20 if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
21 continue;
22 }
ReflectionUtils.makeAccessible(attributeMethodToInvoke);
Object attrValue = attributeMethodToInvoke.invoke(handler, args);
if ("".equals(attrName)) {
Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
}
if (!implicitModel.containsAttribute(attrName)) {
implicitModel.addAttribute(attrName, attrValue);
}
}
Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
if (debug) {
logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
}
ReflectionUtils.makeAccessible(handlerMethodToInvoke);
return handlerMethodToInvoke.invoke(handler, args);
}
catch (IllegalStateException ex) {
// Internal assertion failed (e.g. invalid signature):
// throw exception with full handler method context...
throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
}
catch (InvocationTargetException ex) {
// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
ReflectionUtils.rethrowException(ex.getTargetException());
return null;
}
}

如8-11行所示,在执行被@ModelAttributes注解的方法前,会将上一次通过@SessionAttributes添加至session中的数据添加添加至model中;

第20-22行,在执行被@ModelAttributes注解的方法前,springMVC会判断model中是否已经包含了@ModelAttributes给出的attrName,如果包含,则被@ModelAttributes注解的方法则不再执行

上一篇:mui框架如何实现页面间传值


下一篇:20145122 《Java程序设计》第十周学习总结