springMVC源码分析--FlashMap和FlashMapManager重定向数据保存
在上一篇博客springMVC源码分析--页面跳转RedirectView(三)中我们看到了在RedirectView跳转时会将跳转之前的请求中的参数保存到fFlashMap中,然后通过FlashManager保存起来。
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws IOException { //创建跳转链接 String targetUrl = createTargetUrl(model, request); targetUrl = updateTargetUrl(targetUrl, model, request, response); //获取原请求所携带的数据 FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request); if (!CollectionUtils.isEmpty(flashMap)) { UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build(); flashMap.setTargetRequestPath(uriComponents.getPath()); flashMap.addTargetRequestParams(uriComponents.getQueryParams()); FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request); if (flashMapManager == null) { throw new IllegalStateException("FlashMapManager not found despite output FlashMap having been set"); } //将数据保存起来,作为跳转之后请求的数据使用 flashMapManager.saveOutputFlashMap(flashMap, request, response); } //重定向操作 sendRedirect(request, response, targetUrl, this.http10Compatible); }
接下来我们分别认识一下FlashMap和FalshMapManager
FlashMapManager是一个接口,定义了保存FlashMap和获取FlashMap的方法。
public interface FlashMapManager { //从session中获取flashMap FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response); //将falshMap保存到session中 void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response); }
两个实现方法都在AbstractFlashMapManager抽象方法中:
saveOutputFlashMap方法实现如下
@Override public final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) { if (CollectionUtils.isEmpty(flashMap)) { return; } String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request); flashMap.setTargetRequestPath(path); if (logger.isDebugEnabled()) { logger.debug("Saving FlashMap=" + flashMap); } flashMap.startExpirationPeriod(getFlashMapTimeout()); Object mutex = getFlashMapsMutex(request); if (mutex != null) { synchronized (mutex) { List<FlashMap> allFlashMaps = retrieveFlashMaps(request); allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<FlashMap>()); allFlashMaps.add(flashMap); //flashMap是在子类SessionFlashManager中 updateFlashMaps(allFlashMaps, request, response); } } else { List<FlashMap> allFlashMaps = retrieveFlashMaps(request); allFlashMaps = (allFlashMaps != null ? allFlashMaps : new LinkedList<FlashMap>()); allFlashMaps.add(flashMap); //flashMap是在子类SessionFlashManager中 updateFlashMaps(allFlashMaps, request, response); } }
updateFlashMaps方法的实现机制就是将数据保存的请求的Session中,这样跳转后的请求可以从Session中获取数据,并且所有的实现都保存在同一个Session中,为了防止不同重定向请求的数据相互影响,这边有锁进行处理控制。
@Override protected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response) { WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (!flashMaps.isEmpty() ? flashMaps : null)); }
retrieveAndUpdate获取FlashMap的实现如下:
@Override public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) { List<FlashMap> allFlashMaps = retrieveFlashMaps(request); ........ }
retrieveFlashMaps中的实现机制就是从Session中获取数据
@Override @SuppressWarnings("unchecked") protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) { HttpSession session = request.getSession(false); return (session != null ? (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null); }
当重定向的请求在浏览器中重定向之后会进入的DispatcherServlet的doService方法
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ........ //从Session中获取保存的FlashMap中的值 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } //将值保存到request中。这样就不需要通过浏览器跳转组装链接来传递参数了 request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); ....... }
FlashMap简单来说就是一个HashMap,用于数据保存。
public final class FlashMap extends HashMap<String, Object> implements Comparable<FlashMap> { private String targetRequestPath; private final MultiValueMap<String, String> targetRequestParams = new LinkedMultiValueMap<String, String>(4); private long expirationTime = -1; public void setTargetRequestPath(String path) { this.targetRequestPath = path; } public String getTargetRequestPath() { return this.targetRequestPath; } public FlashMap addTargetRequestParams(MultiValueMap<String, String> params) { if (params != null) { for (String key : params.keySet()) { for (String value : params.get(key)) { addTargetRequestParam(key, value); } } } return this; } public FlashMap addTargetRequestParam(String name, String value) { if (StringUtils.hasText(name) && StringUtils.hasText(value)) { this.targetRequestParams.add(name, value); } return this; } public MultiValueMap<String, String> getTargetRequestParams() { return this.targetRequestParams; } public void startExpirationPeriod(int timeToLive) { this.expirationTime = System.currentTimeMillis() + timeToLive * 1000; } public void setExpirationTime(long expirationTime) { this.expirationTime = expirationTime; } public long getExpirationTime() { return this.expirationTime; } public boolean isExpired() { return (this.expirationTime != -1 && System.currentTimeMillis() > this.expirationTime); } @Override public int compareTo(FlashMap other) { int thisUrlPath = (this.targetRequestPath != null ? 1 : 0); int otherUrlPath = (other.targetRequestPath != null ? 1 : 0); if (thisUrlPath != otherUrlPath) { return otherUrlPath - thisUrlPath; } else { return other.targetRequestParams.size() - this.targetRequestParams.size(); } } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof FlashMap)) { return false; } FlashMap otherFlashMap = (FlashMap) other; return (super.equals(otherFlashMap) && ObjectUtils.nullSafeEquals(this.targetRequestPath, otherFlashMap.targetRequestPath) && this.targetRequestParams.equals(otherFlashMap.targetRequestParams)); } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + ObjectUtils.nullSafeHashCode(this.targetRequestPath); result = 31 * result + this.targetRequestParams.hashCode(); return result; } @Override public String toString() { return "FlashMap [attributes=" + super.toString() + ", targetRequestPath=" + this.targetRequestPath + ", targetRequestParams=" + this.targetRequestParams + "]"; } }
springMVC源码分析--FlashMap和FlashMapManager重定向数据保存的更多相关文章
- springMVC源码分析--DispatcherServlet请求获取及处理
在之前的博客springMVC源码分析--容器初始化(二)DispatcherServlet中我们介绍过DispatcherServlet,是在容器初始化过程中出现的,我们之前也说过Dispatche ...
- springMVC源码分析--页面跳转RedirectView(三)
之前两篇博客springMVC源码分析--视图View(一)和springMVC源码分析--视图AbstractView和InternalResourceView(二)中我们已经简单的介绍了View相 ...
- SpringMVC源码分析--容器初始化(五)DispatcherServlet
上一篇博客SpringMVC源码分析--容器初始化(四)FrameworkServlet我们已经了解到了SpringMVC容器的初始化,SpringMVC对容器初始化后会进行一系列的其他属性的初始化操 ...
- SpringMVC源码分析6:SpringMVC的视图解析原理
title: SpringMVC源码分析6:SpringMVC的视图解析原理 date: 2018-06-07 11:03:19 tags: - SpringMVC categories: - 后端 ...
- [心得体会]SpringMVC源码分析
1. SpringMVC (1) springmvc 是什么? 前端控制器, 主要控制前端请求分配请求任务到service层获取数据后反馈到springmvc的view层进行包装返回给tomcat, ...
- 8、SpringMVC源码分析(3):分析ModelAndView的形成过程
首先,我们还是从DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throw ...
- 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...
- springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)
之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...
- springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)
在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...
随机推荐
- curl模拟http发送get或post接口测试
一.get请求 curl "http://www.baidu.com" 如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地 curl -i "http:// ...
- 推荐几个精致的web UI框架及常用前端UI框架
1.Aliceui Aliceui是支付宝的样式解决方案,是一套精选的基于 spm 生态圈的样式模块集合,是 Arale 的子集,也是一套模块化的样式命名和组织规范,是写 CSS 的更好方式. git ...
- 淘宝开源编辑器Kissy Editor和简易留言编辑器【转】
原来也写过一篇关于百度Ueditor编辑器的介绍:百度Ueditor编辑器的使用,ASP.NET也可上传图片 最开始是使用CuteEditor控件,需要好几mb的空间,因为刚开始学习ASP.NET的时 ...
- GsonWithoutObject 没有对象(脱离对象) 直接提取【转】
GsonWithoutObject 没有对象(脱离对象) 直接提取 ... gson json GsonWithoutObject 脱离对象, 直接提取 package temp; import to ...
- Study 1 —— HTML5概述
HTML5概述HTML是一种超文本标记语言,主要用于描述超文本中内容的显示方式.标记语言经过浏览器的解释和编译,虽然它本身不能显示在浏览器中,但在浏览器中可以正确显示HTML标记的内容.HTML5是一 ...
- 谈谈你对MVC的理解
MVC 模式 MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式.这种模式用于应用程序的分层开发. Model(模型) - 模型代表一个存取数据的对象或 JAVA ...
- Git撤销&回滚操作
https://blog.csdn.net/ligang2585116/article/details/71094887 开发过程中,你肯定会遇到这样的场景: 场景一: 糟了,我刚把不想要的代码,co ...
- java中import机制(指定import和import *的区别)
转自:https://www.cnblogs.com/dtts/p/4692480.html java中有两种包的导入机制,总结如下: 单类型导入(single-type-import), ...
- 转---python os.exec*()家族函数的用法
execl(file, arg0,arg1,...) 用参数列表arg0, arg1 等等执行文件 execv(file, arglist) 除了使用参数向量列表,其他的和execl()相同 exec ...
- Python分析网页中的<a>标签
soup = BeautifulSoup(html,"html.parser") html=soup.select("table a") for k in ht ...