spring mvc重定向方法
一.不带参数,直接重定向到另一个地址:
返回String直接跳转,如:
@RequestMapping(value = "/filehandle") public String upload(){
return "redirect:/upload.jsp";
}
或者使用使用ModelAndView跳转
@RequestMapping(value = "/filehandle") public ModelAndView upload(){
return new ModelAndView("redirect:/toList");
}
二.带参数重定向
1.手动拼接url
@RequestMapping(value = "/filehandle") public String upload(){ return "redirect:/test.jsp?a=2&b=fdf&c=flase&d=123"; }
jsp上用以下两种方式接收
${param.a}
<%=request.getParameter("a") %>
缺点:
a.参数都会被当成String,强制转换类型会报错
b.因为用get方式,中文中可能会乱码
2.用RedirectAttributes.addAttribute 传参
@RequestMapping(value = "/test") public String upload(RedirectAttributes attr,Model model){ attr.addAttribute("a",2); attr.addAttribute("b","镇耿"); attr.addAttribute("c",false); return "redirect:/test.jsp"; }
不能用Model.addAttribute,因为jsp接不到
jsp接收的方式跟上一个一样
实际上,这个方法实质上跟方法1是一样的,只是这个方法会自动拼接url,跳转之后的地址是一样的,所以缺点也跟方法1一样.
3.用RedirectAttributes.addFlashAttribute 传参(这个是重点,重定向action的地址带自定义类型的参数的话用这个,直接重定向jsp的话用下一个)
RedirectAttributes.addFlashAttribute 是 Spring MVC 3.1之后才有的,并且要在 spring-servlet.xml 文件中加入 mvc:annotation-driven。
<mvc:annotation-driven />
java:
@RequestMapping(value = "/test") public String upload(RedirectAttributes attr){ TestBean b=new TestBean(); b.setA("3"); b.setB("峰峰ff"); attr.addFlashAttribute("t",b); return "redirect:/test2"; } @RequestMapping(value = "/test2") public String upload2(){ return "test"; }
如果"/test2"里面需要对addFlashAttribute里的值处理可以在"/test2"里用以下几种方法接
第一种
@RequestMapping(value ="/test2") public String upload2(@ModelAttribute("t") TestBean c) { System.out.println(c.getA()); System.out.println(c.getB()); c.setB("fFdf发的");
return "test"; }
可以不用保存,直接更改,jsp接到的是改后的值
第二种在"/test2"处理flashattribute的值:
// model.asMap().put("t", d); System.out.println("t:"+model.asMap().get("t")); TestBean t= (TestBean) model.asMap().get("t"); t.setB("dsd发扥扥分");
这两种方法处理过的值在刷新的时候不会消失,而从"test"接过来的值会消失(如上面,t.b的值在刷新的时候不会消失,而t.a会)
第三种:
System.out.println("Fetch Flash Attributes By using RequestContextUtils"); Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(request); if (flashMap != null) { TestBean t=(TestBean)flashMap.get("t"); System.out.println("t.b:"+t.getB()); t.setB("发扥周"); }
这种方法修改过的值在第二次刷新的值会消失
jsp用以下方式接
${t.b }
<%=request.getAttribute("t") %>
addFlashAttribute 默认存放在session里,重定向后取值就会立马删除,所以不会占用session很多空间,但仍然有其他问题.
注意:RedirectAttributes.addAttribute和RedirectAttributes.addFlashAttribute最好不要一起用,尤其是两者添加到key和bean里属性的名字不要重复,会导致 FlashAttribute里面的值错乱
这方法不能直接重定向到jsp,直接到jsp的话在jsp取不到值,需要重定向到映射上
原因:
addFlashAttribute方法默认存在session里面,名字是"org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS",
直接跳到jsp的话,存进的变量t的位置不会变,还在session里面的"org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS"里面,值是"[FlashMap [attributes={t=com.cib.xj.poi.TestBean@5f615e1c}, targetRequestPath=/xj.query/test.jsp, targetRequestParams={}]]",
jsp直接用${t.a}是取不到t的,因为t是springmvc封装的那个变量里面,session里根本没有"t"这个变量名.可以在jsp用下面的方法取到变量t(类型java.util.concurrent.CopyOnWriteArrayList好像需要在jsp引入,不然会无法编译jsp)
<% CopyOnWriteArrayList m=(CopyOnWriteArrayList )session.getAttribute("org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS"); if(m!=null){ for(int i=0;i<m.size();i++){ FlashMap fm =(FlashMap )m.get(i); TestBean t=(TestBean)fm.get("t"); out.print("java:t:a:"+t.getA()+"<br/>"); out.print("java:t:b:"+t.getB()+"<br/>"); } } %>
但addFlashAttribute直接重定向jsp的话,即使在jsp用上面的方法取到变量,session里那个变量也不会自动删除.每运行一次就会往session那个变量增加一个值,前面的仍然保留着,需要自己手动删除,不然session会越占越大.既然需要自己手动删除,还不如自己用自定义的变量名直接放进session,在jsp取完值后删掉,这样取值更好取(即下面的方法4).
而跳转到另一个映射上的话(此映射是get方式请求的,因为重定向redirect是用get方式请求的),第二个映射接收的时候会把flashAttribute里面的变量放到Model里面并把session里的那个变量删除(从上面 "第二种在"/test2"处理flashattribute的值:" 的例子可以看出变量t存进了Model),然后第二个映射正常以"forward"方式返回到jsp的时候,在Model里面的变量t就自然存到了jsp的request范围内,即jsp的request里面存在变量"t",此时用${t.a}自然可以取到值.相对应,直接跳jsp的话不管是request还是session里面都不存在名字叫"t"的变量,所以直接跳jsp的话用${t.a}是取不到值的.
找到原因的方法:
我在jsp上面直接把request和session里面的所有变量都遍历打印出来了,才发现了flashAttribute存进去的变量是叫"org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS",而不是直接用存进flashAttribute的变量的名字.在尝试取那个变量的值的时候先用Map取,但报了"java.util.concurrent.CopyOnWriteArrayList"不能转换到"java.util.Map"的异常,然后发现这个类是ArrayList,就按照正常的List遍历出它所有的值了.
4.值放session里,跳转后从session取值再将值删除.(如果是要直接重定向jsp还要带自定义类型的参数的话,要用这个)
@RequestMapping(value = "/test") public String upload(HttpSession session){ TestBean b=new TestBean(); b.setA("3"); b.setB("峰峰ff"); session.setAttribute("u",b ); return "redirect:/test.jsp"; // return "redirect:/test2"; }
jsp接(最好取完就删了,毕竟取完就没用了,免得session越占越大)
session.u=<%=session.getAttribute("u") %><br/> sessionScope.u.a=${sessionScope.u.a}<br/> u.a=${u.a }<br/>
<% session.removeAttribute("u"); %>