springMVC源码分析--FlashMap和FlashMapManager重定向数据保存

来源:互联网 发布:知柏地黄丸一般吃多久 编辑:程序博客网 时间:2024/04/29 20:59

在上一篇博客 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中获取flashMapFlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);//将falshMap保存到session中void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);}
两个实现方法都在AbstractFlashMapManager抽象方法中:

saveOutputFlashMap方法实现如下

@Overridepublic 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中,为了防止不同重定向请求的数据相互影响,这边有锁进行处理控制。
@Overrideprotected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response) {WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (!flashMaps.isEmpty() ? flashMaps : null));}

retrieveAndUpdate获取FlashMap的实现如下:

@Overridepublic 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方法

@Overrideprotected 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);}@Overridepublic 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();}}@Overridepublic 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));}@Overridepublic int hashCode() {int result = super.hashCode();result = 31 * result + ObjectUtils.nullSafeHashCode(this.targetRequestPath);result = 31 * result + this.targetRequestParams.hashCode();return result;}@Overridepublic String toString() {return "FlashMap [attributes=" + super.toString() + ", targetRequestPath=" +this.targetRequestPath + ", targetRequestParams=" + this.targetRequestParams + "]";}}



1 0
原创粉丝点击