SpringMVC中的@SessionAttributes注解【详解】
在默认情况下,当ModelMap中的属性作⽤域是request级别时,也就是说,当本次请求结束后,ModelMap中的属性将销毁。如果希望在多个请求中共享ModelMap中的属性,必须将其属性转存到session中,这样ModelMap的属性才会被跨请求访问;
spring允许我们有选择地指定ModelMap中的哪些属性需要转存到session中,以便下⼀个请求属对应的ModelMap的属性列表中还能访问到这些属性。
注意:这⾥所说的将ModelMap中的属性转存Seesion中,不单单指ModelMap,其实控制器向jsp传值绑定数据的五种⽅式(ModelMap、Model、Session、Map、Request)都可以将其属性转存到Session中,下⾯就直接以ModelMap为例进⾏说明。
SpringMVC为我们提供这样⼀个注解来实现上⾯的场景:
@SessionAttributes:将ModelMap的属性值共享到session中。
1、@SessionAttributes注解:
【重点】:通过@SessionAttributes注解将ModelMap中的属性存⼊到Session中以后:
可以在本次请求对应的jsp页⾯中使⽤Attribute("");和Attribute("");获取到该属性;
还可以通过下次其它请求对应的jsp页⾯中使⽤Attribute("");和ModelMap#get("");获得到该属性;
也可以通过标识的参数中获取。
补充:Attribute("")的scope为request,也就是在当前请求,从控制器到jsp携带的ModelMap对象中获取,⽽Aattribute("")的scope为session,是从Session中去获取属性值。
注意:@SessionAttributes注解只能使⽤在类上,⽤于在多个请求之间传递参数,类似于Session的Attribute,但不完全⼀样,⼀般来说@SessionAttributes设置的参数只⽤于暂时的传递(存⼊sessionAttributeStore),⽽不是长期的保存,长期保存的数据还是要放到Session中。
有两种⽅式将ModelMap中的属性值共享到session中:
1. 使⽤注解的value属性:可以通过属性名指定需要放到会话中的属性;
2. 使⽤注解的types属性:还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
⽅式⼀:通过注解的value属性:
@Controller
@SessionAttributes("user")//将ModelMap中key为user的属性共享到session中
public class DemoController {
@RequestMapping("/hello")
public String hello(ModelMap model){
//向ModelMap中添加key为user和user1的属性
model.addAttribute("user",new User(520,"U love me"));
model.addAttribute("user1",new User("I love U"));
return"result";
}
}
@Controller
public class Demo2Controller {
@RequestMapping(value ="/demo")
public String dmeo(){
return"result";
}
}
在DemoController的hello⽅法中,将key为user和user1的User对象存⼊ModelMap中,在hello请求对应的jsp页⾯可以获得到相应key为user和user1的User对象;同时通过注解@SessionAttributes将key为user的User对象存⼊到Session中。
在Demo2Controller的demo⽅法中,我们并没有向jsp页⾯传⼊任何的值,正是因为在DemoController
中通过注解已将key为user 的属性存⼊到session中,所以在demo请求对应的jsp页⾯中还是可以获得到key为user对应的User对象。
上⾯的例⼦中,我们通过属性名的⽅式,将对应的属性存⼊到session中。
⽅式⼆:通过注解的types属性:
@SessionAttributes(types ={User.class})
@Controller
public class DemoController{
@RequestMapping("/hello")
public String hello(Map<String, Object> map){
map.put("user1",new User(520,"U love me"));
return"hello";
}
}
@Controller
public class Demo2Controller {
@RequestMapping(value ="/demo")
public String dmeo(){
return"result";
}
}
类似的例⼦,这次是通过@SessionAttributes注解的types属性指定了User类型,所以它会将User类型的所有属性值存⼊到Session 中,这样我们再demo请求所对应的jsp页⾯可以正常的获取到key为user1对应的属性值。
补充:这⾥我们仅将⼀个ModelMap的属性放⼊Session中,其实@SessionAttributes注解允许通过字
符串数组的⽅式指定多个属性,例:@SessionAttributes(types = {User.class, String.class}, value={"user1", "user2"}。
@SessionAttributes使⽤后可以调⽤SessionStatus.setComplete来清除,这个⽅法只是清除SessionAttribute⾥的参数,⽽不会应⽤Session中的参数。
@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status){
if(errors.hasErrors){
// ...
status.setComplete();//调⽤SessionStatus.setComplete来清除
// ...
}
}
}
2、@SessionAttribute注解:
Springmvc中有⼀个和@SessionAttributes很像的注解:@SessionAttribute注解标注在⽅法参数上,它的作⽤是获取session中可能预先存⼊的属性值。(我⾃⼰测试该注解并没有什么作⽤,想在当前控制器内获取其它控制器通过@SessionAttributes预先存⼊Session中的值,主要还是需要在当前控制器的类上添加@SessionAttributes注解的⽅式获取,看下⾯测试)
测试1:
在DemoController中通过demo请求将key为user值为User user的属性通过@SessionAttributes(“user”)
存⼊到session中,在demo请求对应的demo.jsp页⾯中可以通过${user}获得key为user对应的属性值,也可以通过${sessionScope.user}获取到该属性值;
@Controller
@SessionAttributes("user")
public class DemoController {
@RequestMapping("demo")
public String demo(Map<String, Object> map){
User user =new User(520,"U love me");
map.put("user", user);
return"result";
}
}
此时,我在Demo2Controller中通过demo2请求的⽅法中,将User user参数标注为@SessionAttribute(“user”),此时在⽅法中并没有获取到Session中的key为user的属性值,在demo2请求对应的jsp页⾯中能${sessionScope.user}属性值,不能通
过${user}获取到对应的属性值,控制台打印:UserId: 0、UserName: null;
结论:说明只在⽅法参数上添加@SessionAttribute注解,在当前⽅法中并不能从session获取到key为user的属性值,也没有将其属性值存⼊到当前控制器的ModelMap中,@SessionAttribute注解没⽣效。
测试2:
DemoController不变,在Demo2Controller类上添加@SessionAttributes(“user”)注解,将参数中的
@SessionAttribute(“user”)注解去掉,然后通过demo2⽅法对应的jsp页⾯中,成功通过${sessionScope.user}和${user}获取到了对应的属性值,控制台打印:UserId: 520,UserName: U love me。
@Controller
@SessionAttributes("user")
public class DemoController {
@RequestMapping("demo")
public String demo(Map<String, Object> map){
User user =new User(520,"U love me");
map.put("user", user);
return"result";
}
}
@Controller
@SessionAttributes("user")
public class Demo2Controller {
@RequestMapping("demo2")
public String demo2(User user){
System.out.println("UserId: "+ Id());
System.out.println("UserName: "+ Desc());
return"result";
}
}
结论:在⽅法参数上添加@SessionAttribute注解并没有什么实际意义,要想在当前控制器中获取Session中的属性值,必须在当前控制器类上添加@SessionAttributes注解才能⽣效。
测试3:
DemoController不变,将Demo2Controller类上将@SessionAttributes("user1")注解的value值改为user1,在demo2请求对应的jsp 页⾯中能${sessionScope.user}属性值,不能通过${user}获取到对应
的属性值,控制台打印:UserId: 0、UserName: null;
@Controller
@SessionAttributes("user1")
public class Demo2Controller {
@RequestMapping("demo2")
public String demo2(User user){
System.out.println("UserId: "+ Id());
System.out.println("UserName: "+ Desc());
return"result";
}
}
结论:要想在当前控制器获取到预先存⼊到Session的属性值,@SessionAttributes注解的value值必须和预先存⼊的值相对应。
测试4:
Demo2Controller和测试3保持不变,将DemoController类上的@SessionAttribute(“user1”)注解上的value值改为user1,将map中put的key也改为user1,保证将key为user1的值存⼊到Session中,结果在demo2对应的jsp页⾯中,成功通
过${sessionScope.user}和${user}获取到了对应的属性值,控制台打印:UserId: 0、UserName: null;
@Controller
@SessionAttributes("user1")
public class DemoController {
@RequestMapping("demo")
public String demo(Map<String, Object> map){
User user =new User(520,"U love me");
map.put("user1", user);
return"result";
}
}
@Controller
@SessionAttributes("user1")
public class Demo2Controller {
@RequestMapping("demo2")
public String demo2(User user){
System.out.println("UserId: "+ Id());
System.out.println("UserName: "+ Desc());
return"result";
}
}
结论:在demo2请求对应的jsp页⾯可以通过${sessionScope.user}和${user}获取到了对应的属性值,说明@SessionAttributes注解已经成功接收到key为user1的属性值,并绑定到demo2请求的ModelMap中传⼊jsp页⾯,但是控制台并打印UserId: 0、UserName: null,说明demo2⽅法并没有接收到该属性值。
测试5:
在测试4的基础上,在Demo2Controller的参数添加@SessionAttribute(“user1”)注解,结果和测试3相同,并没有任何改变;
@Controller
@SessionAttributes("user1")
public class DemoController {
@RequestMapping("demo")
public String demo(Map<String, Object> map){
User user =new User(520,"U love me");
map.put("user1", user);
return"result";
}
}
@Controller
@SessionAttributes("user1")
public class Demo2Controller {
@RequestMapping("demo2")
public String demo2(@SessionAttribute("user1") User user){
System.out.println("UserId: "+ Id());
System.out.println("UserName: "+ Desc());
return"result";
}
}
结论:@SessionAttribute真的⼀点作⽤都没有
测试6:
将DemoController的@SessionAttributes(“user1”)注解value值改为value1,map.put(“user1”,user)的key也改为user1,将Demo2Controller类上的@SessionAttributes注解改为通过types属性接收,结果405报错,提⽰⽆法从session中获取key为user的属性值;
@Controller
@SessionAttributes("user1")
public class DemoController {
@RequestMapping("demo")
public String demo(Map<String, Object> map){
User user =new User(520,"U love me");
map.put("user1", user);
return"result";
}
}
@Controller
@SessionAttributes(types = User.class)
public class Demo2Controller {
@RequestMapping("demo2")
el表达式获取session中的值public String demo2(User user){
System.out.println("UserId: "+ Id());
System.out.println("UserName: "+ Desc());
return"result";
}
}
结论:通过@SessionAttributes注解的types属性接收时,会根据类型的⾸字母⼩写对应的key去Session中获取对应的属性。
测试7:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论