@SessionAttributes 只能做用在類上,做用是將指定的Model中的鍵值對添加至session中,方便在下一次請求中使用。web
1 @Controller 2 @RequestMapping("/testSessionAttribute") 3 @SessionAttributes(value = {"user","age","name"}) 4 public class TestSessionAttributeController { 5 6 @ModelAttribute("user") 7 public User addUser(){ 8 User user = new User(); 9 user.setName("James"); 10 user.setAge(29); 11 return user; 12 } 13 14 @RequestMapping("/testHandler") 15 public String testHandler(Model model, String age, String name){ 16 model.addAttribute("age",age); 17 model.addAttribute("name",name); 18 System.out.println(age); 19 System.out.println(name); 20 return "result"; 21 } 22 }
對應的jsp代碼以下:spring
1 <body> 2 ${sessionScope.user.age} 3 ${sessionScope.user.name} 4 <br/> 5 ${sessionScope.age} 6 ${sessionScope.name} 7 </body>
經過實例能夠得出一下結論:session
若是須要清除經過@SessionAttribute添加至 session 中的數據,則須要在controller 的 handler method中添加 SessionStatus參數,在方法體中調用SessionStatus#setComplete。app
須要注意的是,此時清除的只是該Controller經過@SessionAttribute添加至session的數據(固然,若是不一樣controller的@SessionAttribute擁有相同的值,則也會清除)jsp
@Controller @RequestMapping("/testSessionAttribute") @SessionAttributes(value = {"user","age","name"}) public class TestSessionAttributeController { .......................... @RequestMapping("/removeSessionAttributes") public String removeSessionAttributes(SessionStatus sessionStatus){ sessionStatus.setComplete(); return "result"; } }
在沒用使用SessionStatus清除過以前,經過@ModelAttributes和@SessionAttributes共同添加至session中的數據並不會更新,以下例:this
1 @Controller 2 @RequestMapping("/testSessionAttribute") 3 @SessionAttributes(value = {"user","age","name"}) 4 public class TestSessionAttributeController { 5 6 public static int age = 29; 7 @ModelAttribute("user") 8 public User addUser(){ 9 User user = new User(); 10 user.setName("James"); 11 user.setAge(age++); 12 return user; 13 } 14 15 @RequestMapping("/testHandler") 16 public String testHandler(Model model, String age, String name){ 17 model.addAttribute("age",age); 18 model.addAttribute("name",name); 19 System.out.println(age); 20 System.out.println(name); 21 return "result"; 22 } 23 24 }
1 <body> 2 ${sessionScope.user.age} 3 ${sessionScope.user.name} 4 <br/> 5 ${sessionScope.age} 6 ${sessionScope.name} 7 </body>
第一次請求:http://localhost:8080/testSessionAttribute/testHandler.action?name=James&age=29spa
結果:debug
29 James
29 Jamescode
第二次請求:http://localhost:8080/testSessionAttribute/testHandler.action?name=James&age=30blog
29 James
30 James
緣由是,在org.springframework.web.bind.annotation.support.HandlerMethodInvoker#invokeHandlerMethod中進行了以下操做:
1 public final Object invokeHandlerMethod(Method handlerMethod, Object handler, 2 NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { 3 4 Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); 5 try { 6 boolean debug = logger.isDebugEnabled(); 7 for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { 8 Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); 9 if (attrValue != null) { 10 implicitModel.addAttribute(attrName, attrValue); 11 } 12 } 13 for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { 14 Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); 15 Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); 16 if (debug) { 17 logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); 18 } 19 String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); 20 if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { 21 continue; 22 } 23 ReflectionUtils.makeAccessible(attributeMethodToInvoke); 24 Object attrValue = attributeMethodToInvoke.invoke(handler, args); 25 if ("".equals(attrName)) { 26 Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); 27 attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); 28 } 29 if (!implicitModel.containsAttribute(attrName)) { 30 implicitModel.addAttribute(attrName, attrValue); 31 } 32 } 33 Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); 34 if (debug) { 35 logger.debug("Invoking request handler method: " + handlerMethodToInvoke); 36 } 37 ReflectionUtils.makeAccessible(handlerMethodToInvoke); 38 return handlerMethodToInvoke.invoke(handler, args); 39 } 40 catch (IllegalStateException ex) { 41 // Internal assertion failed (e.g. invalid signature): 42 // throw exception with full handler method context... 43 throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); 44 } 45 catch (InvocationTargetException ex) { 46 // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... 47 ReflectionUtils.rethrowException(ex.getTargetException()); 48 return null; 49 } 50 }
如8-11行所示,在執行被@ModelAttributes註解的方法前,會將上一次經過@SessionAttributes添加至session中的數據添加添加至model中;
第20-22行,在執行被@ModelAttributes註解的方法前,springMVC會判斷model中是否已經包含了@ModelAttributes給出的attrName,若是包含,則被@ModelAttributes註解的方法則再也不執行