SpringMVC 之 FlashMap,FlashMapManager讲解
首先先讲解 FlashMap,FlashMapManager存在的价值;做过Web开发的人都知道,后端有请求转发和请求重定向两种方式,请求转发的时候Request是同一个,所以可以在转发后拿到转发前的所有信息;但是重定向后 Request是新的,如果需要在重定向前设置一些信息,重定向后获取使用应该怎么办法呢?这就是 FlashMap存在的意义,FlashMap 借助 session 重定向前通过 FlashMapManager将信息放入FlashMap,重定向后 再借助 FlashMapManager 从 session中找到重定向后需要的 FalshMap。下面开始详细讲解:
FlashMap 类中存储了如下三个信息,目标url,参数,过期时间。
@Nullable
private String targetRequestPath;
private final MultiValueMap<String, String> targetRequestParams = new LinkedMultiValueMap<>(4);
private long expirationTime = -1;
FlashMapManager 定义了操作 FlashMap的核心方法
public interface FlashMapManager {
/**
* 本方法是从 session 中获取所有 FlashMap,然后删除过期的 FlashMap;寻找匹配当前请求的 FlashMap ;并将匹配上的 FlashMap 也删除(删除的时候加锁)
* * FlashMap 中有 失效时间,目标请求参数,目标请求路径
* * 该方法用于重定向后 获取 flashMap,从而获取重定向前设置的参数
*/
FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);
//重定向前设置 重定向后需要的参数,目标重定向url
void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
AbstractFlashMapManager 实现了 FlashMapManager 的两个核心方法,使用模版方法模式,具体操作session 的方法retrieveFlashMaps,updateFlashMaps 由子类 SessionFlashMapManager 实现
public abstract class AbstractFlashMapManager implements FlashMapManager {
/**
* @param request the current request
* @param response the current response
* @return 本方法是从 session 中获取所有 FlashMap,然后删除过期的 FlashMap;寻找匹配当前请求的 FlashMap ;并将匹配上的 FlashMap 也删除(删除的时候加锁)
* FlashMap 中有 失效时间,目标请求参数,目标请求路径
* 该方法用于重定向后 获取 flashMap,从而获取重定向前设置的参数
*/
@Override
@Nullable
public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
//retrieveFlashMaps 子类实现
// 从 session 中获取 FLASH_MAPS_SESSION_ATTRIBUTE = SessionFlashMapManager.class.getName() + ".FLASH_MAPS";
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
if (CollectionUtils.isEmpty(allFlashMaps)) {
return null;
}
//获取已经过期的 FlashMap 进行移除
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps);
//获取和当前请求 匹配的 FlashMap 目标url匹配,目标参数匹配
FlashMap match = getMatchingFlashMap(allFlashMaps, request);
//匹配上之后,传递参数的责任完成,加入待移除队列
if (match != null) {
mapsToRemove.add(match);
}
if (!mapsToRemove.isEmpty()) {
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
//加锁,
synchronized (mutex) {
//retrieveFlashMaps 子类实现
allFlashMaps = retrieveFlashMaps(request);
if (allFlashMaps != null) {
//移除后,更新session
allFlashMaps.removeAll(mapsToRemove);
// 子类实现
updateFlashMaps(allFlashMaps, request, response);
}
}
} else {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
return match;
}
/**
* @param flashMap the FlashMap to save
* @param request the current request
* @param response the current response
* 重定向前设置 重定向后需要的参数,目标重定向url
*/
@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);
// private int flashMapTimeout = 180;
flashMap.startExpirationPeriod(getFlashMapTimeout());
//获取锁
Object mutex = getFlashMapsMutex(request);
if (mutex != null) {
synchronized (mutex) {
//调子类方法 从 session 中获取 flashMap 列表
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<>());
//将刚刚生成的 flashMap 加入列表
allFlashMaps.add(flashMap);
//更新 session 中的 flashMap 列表
updateFlashMaps(allFlashMaps, request, response);
}
} else {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new LinkedList<>());
allFlashMaps.add(flashMap);
updateFlashMaps(allFlashMaps, request, response);
}
}
}
SessionFlashMapManager 定义了操作 session 中的 FlashMap List的方法和 获取锁的方法
public class SessionFlashMapManager extends AbstractFlashMapManager {
protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) {
HttpSession session = request.getSession(false);
return (session != null ? (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null);
}
protected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response) {
WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (!flashMaps.isEmpty() ? flashMaps : null));
}
protected Object getFlashMapsMutex(HttpServletRequest request) {
return WebUtils.getSessionMutex(request.getSession());
}
}
网友评论