美文网首页
SpringMVC 之 FlashMap,FlashMapMan

SpringMVC 之 FlashMap,FlashMapMan

作者: 码而优则仕 | 来源:发表于2020-08-27 09:04 被阅读0次

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());
    }
}

相关文章

网友评论

      本文标题:SpringMVC 之 FlashMap,FlashMapMan

      本文链接:https://www.haomeiwen.com/subject/troqsktx.html