大家好,前一段时间,对SpringMVC的源码进行了一段时间的学习,虽然并不深入,但是也略有收获,今天和大家分享一些在学习过程中学习到的实用技巧。首先一点就是SpringMVC如何在进行请求重定向时进行数据传递。
写过网站服务的朋友们,肯定都接触过请求重定向和请求转发,由于今天重点并不是分析这两点,所以并不会进行详细的解释,其中区别呢主要是在请求的方式上,简要来说重定向是客户端行为,而转发是服务器行为,在重定向过程中,客户端进行两次请求,但是在请求转发过程中,客户端进行一次请求,但是在服务器上会进行多次请求,
重定向示意图如下:
请求转发示意图如下:
很显然,在重定向过程中,客户端发发起了两次请求,也就是两个request,那么问题就来了,在我们使用SpringMVC时,我们的代码通常是如下:
@Controller
@RequestMapping("/bbb")
public class ChartController extends BaseController {
@RequestMapping("/aaa")
@ResponseBody
public void getDepartFlightStatisticShow(int limit) {
//进行逻辑处理
}
}
我们可以看到,在方法参数中有一个limit参数,这个参数是随着request请求被封装的,也就是说,这个参数从客户端到服务端,是封装在request中的,当进行请求重定向时,就会因为发起不同的请求而在后面的请求中丢失掉,或者也可以理解为,我们想在方法体中进行重定向,并且将方法中的参数进行传递,那么我们封装在request中是不起作用的,那么问题发现了,有没有什么方法解决呢?当然是有的,那就是把参数放在比request更高一级的对象中,没错,就是session。
关于session我们不做过多的介绍,可以简单理解为客户端和服务器的持续性链接,只要session存活,那么客户端就可以和服务器进行会话。那么SpringMVC是怎么将我们想要转发的对象存在session中的呢?如下代码:
@RequestMapping("/test")
public String test(RedirectAttributes attributes) {
attributes.addFlashAttribute("name", "zonglin.zhang");
attributes.addAttribute("language", "Chinese");
return "redirect:/test2";
}
@RequestMapping("/test2")
public void test2(Model model) {
System.out.println(model.asMap().get("name"));
}
我们看到,在我们请求test时,在方法中进行了请求转发,但是在这之前,我们在参数中传递了一个RedirectAttributes类型的参数,并且在参数中设置了两个内容:name和language,在转发后的test2中进行了输出,使用这种方法就可以进行重定向时的数据转发。大家可能有疑问,RedirectAttributes类型的参数是怎样传递的,其实这个参数不需要我们在调用test时进行传递,这是SpringMVC自己给我们提供的参数,但是我们也可以发现不同点,就是
attributes.addFlashAttribute("name", "zonglin.zhang");
attributes.addAttribute("language", "Chinese");
这两行代码,我们可以看到调用的方法并不相同,有什么区别呢?其实在RedirectAttributes中,存在一个Map类型的对象,SpringMVC中的实现是FlashMap,我们调用addFlashAttribute()时就是将对象存在了这个MAP中,但是在调用addAttribute()方法时,我们并没有对参数进行MAP的存储,而是将对象写在了url中,所以在重定向的过程中,我们看到的就是在url上有language参数。
那么说了这么多,SpringMVC中对这个参数是怎么使用的呢?我们需要看一下SpringMVC中最为核心的一个类DispatcherServlet中的doService()方法:
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE,Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
由于篇幅限制,我们只写出我们要讲解的部分代码,有兴趣的朋友可以去参看SpringMVC源码。
我们看到我们在这里为Request设置了三个参数,两个是FlashMap,一个是管理类。作用是什么呢?
比如说我们将表单post提交到了一个请求上去,但是为了避免重复提交,我们将求情redirect到了一个GET请求中,但是很显然,我们希望在GET请求中得到表单信息,按照通常的方式,我们可以将请求写到url中,但是url长度存在限制,就会出现问题,所以我们将数据存储在了FlashMap中,INPUT_FLASH_MAP_ATTRIBUTE参数代表我们要接收的重定向FlashMao,而OUTPUT_FLASH_MAP_ATTRIBUTE代表我们要输出的重定向FalshMap,这样就可以进行数据的重定向转发了。当然实际实现要复杂很多,大家可以自行研究。我的分享就只有这些了,如有不妥之处,还请大家多多指教。