zoukankan      html  css  js  c++  java
  • springMVC源码学习之addFlashAttribute源码分析

    本文主要从falshMap初始化,存,取,消毁来进行源码分析,springmvc版本4.3.18。关于使用及验证请参考另一篇jsp取addFlashAttribute值深入理解即springMVC发redirect传隐藏参数

    说明:在action中通过redirectAttributes.addFlashAttribute(userName,"mike"),retrun "redirect:indexTest.jsp",页面indexTest.jsp中打印该session的值发现有这组属性

    org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS==[FlashMap [attributes={userInfo=com.ccb.xx.vdo.UserInfo@2c367ad4, userID=ID001,userName=mike}, targetRequestPath=/project/page/public/indexTest.jsp, targetRequestParams={flag=[opening]}]],能过el表达式${sessionScope['org.springframework.web.servlet.support.SessionFlashMapManager.FLASH_MAPS'][0]['userId']}可取能值。

    1.初始化和调用,首先是入springMVC 入口webmvc包中org.springframework.web.servlet.DispatcherServlet中的doService方法进行调用

    public class DispatcherServlet extends FrameworkServlet
    {
      private FlashMapManager flashMapManager;
     public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
      protected void initStrategies(ApplicationContext context)
      {
        initMultipartResolver(context);
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
      //初始化 initFlashMapManager(context); }
    private void initFlashMapManager(ApplicationContext context) { try {
        //同级目录下DispatcherServlet.properties中配置
        //org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
        //此处代码相当于this.flashMapManager=(FlashMapManager)new SessionFlashMapManager(),
        //因SessionFlashMapManager extends AbstractFlashMapManager,此处会执行AbstractFlashMapManager.AbstractFlashMapManager()构造方法
        //,并设置过期时间this.flashMapTimeout = 180;
    this.flashMapManager = ((FlashMapManager)context.getBean("flashMapManager", FlashMapManager.class)); if (this.logger.isDebugEnabled()) this.logger.debug("Using FlashMapManager [" + this.flashMapManager + "]"); } catch (NoSuchBeanDefinitionException ex) { this.flashMapManager = ((FlashMapManager)getDefaultStrategy(context, FlashMapManager.class)); if (this.logger.isDebugEnabled()) this.logger.debug("Unable to locate FlashMapManager with name 'flashMapManager': using default [" + this.flashMapManager + "]"); } } protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
       //从session中获取及session中删除
       //此处执行的是模板类org.springframework.web.servlet.support.AbstractFlashMapManager中的retrieveAndUpdate方法    FlashMap inputFlashMap
    = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null)//转存request request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));

      //下面解释在调用controller的方法时,将request中falshmap==>ModelMap中,ModelMap继承自LinkedHashMap
      //在doDispatch中通过反射调用@RequestMapping修饰的方法,
       //HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      // mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      //HandlerAdapter是接口,模板类AbstractHandlerMethodAdapter具体handle(调用handleInternal)实现,
      //实际调用子类RequestMappingHandlerAdapter.handleInternal(调用invokeHandlerMethod(request, response, handlerMethod))进行处理,
      //在invokeHandlerMethod方法中,由下面代码将上面"转存request"放put到ModelMap中,所以jsp取addFlashAttribute值深入理解即springMVC发redirect传隐藏参数
      //中3.2的model输出中有flashAttribute参数
        // ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        // mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
       //invokeHandlerMethod详解SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解
       doDispatch(request, response);//最终由RequestMappingHandlerAdapter.invokeHandlerMethod(request, response, handlerMethod)进行处理 } }

    AbstractFlashMapManager源码如下,

    retrieveAndUpdate调用实现子类的retrieveFlashMaps取session中的flashmap,调用子类updateFlashMaps删除session的方法

    public abstract class AbstractFlashMapManager
      implements FlashMapManager
    {

    public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {//从session中取SessionFlashMapManager.FLASH_MAPS
    List allFlashMaps
    = retrieveFlashMaps(request); if (CollectionUtils.isEmpty(allFlashMaps)) { return null; } if (this.logger.isDebugEnabled()) this.logger.debug("Retrieved FlashMap(s): " + allFlashMaps); List mapsToRemove = getExpiredFlashMaps(allFlashMaps);
      //此处match返回SessionFlashMapManager.FLASH_MAPS值,值的结构如([FlashMap [attributes={userInfo=com.ccb.xx.vdo.UserInfo@2c367ad4, userId=ID001,
      //userName=mike}, targetRequestPath=/project/page/public/indexTest.jsp, targetRequestParams={flag=[opening]}]]

      //虽然此时request attribute为空,

      //但实际执行此函数的spring-web包中org.springframework.web.util.UrlPathHelper中方法
      //getOriginatingRequestUri(request)代码“if (uri == null) uri = request.getRequestURI()

      //代码可取到值,与SessionFlashMapManager.FLASH_MAPS中的targetRequestPath值相等 FlashMap match
    = getMatchingFlashMap(allFlashMaps, request); if (match != null) {//将FLASH_MAPS加入待删除列表,后续请空allFlashMaps,再清空session该项的值 mapsToRemove.add(match); } if (!(mapsToRemove.isEmpty())) { if (this.logger.isDebugEnabled()) this.logger.debug("Removing FlashMap(s): " + mapsToRemove); Object mutex = getFlashMapsMutex(request); if (mutex != null) { synchronized (mutex) { allFlashMaps = retrieveFlashMaps(request); if (allFlashMaps != null) {
            //将SessionFlashMapManager.FLASH_MAPS从allFlashMaps中删除 allFlashMaps.removeAll(mapsToRemove);
            //此时allFlashMaps中SessionFlashMapManager.FLASH_MAPS为空,下面方法将其从session中删除 updateFlashMaps(allFlashMaps, request, response); } } }
    else { allFlashMaps.removeAll(mapsToRemove);
         updateFlashMaps(allFlashMaps, request, response); } }
    return match; }
    //具体实现在SessionFlashMapManager中

       protected abstract List<FlashMap> retrieveFlashMaps(HttpServletRequest paramHttpServletRequest);

      protected abstract void updateFlashMaps(List<FlashMap> paramList, HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse); 
    }

     实现类SessionFlashMapManager中重写retrieveFlashMaps和updateFlashMaps

    public class SessionFlashMapManager extends AbstractFlashMapManager
    {
      private static final String FLASH_MAPS_SESSION_ATTRIBUTE = SessionFlashMapManager.class.getName() + ".FLASH_MAPS";
    
      protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request)
      {
        HttpSession session = request.getSession(false);
        return ((session != null) ? (List)session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null);
      }
    
      protected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response)
      {//flashMaps中SessionFlashMapManager.FLASH_MAPS为空,(!(flashMaps.isEmpty())) ? flashMaps : null)整个表达式返回null
      //即实现falshMaps中值为空,清空sesssion中该项的目的 WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (
    !(flashMaps.isEmpty())) ? flashMaps : null); } protected Object getFlashMapsMutex(HttpServletRequest request) { return WebUtils.getSessionMutex(request.getSession()); } }

    spring-web包org.springframework.web.util.WebUtils中WebUtils.setSessionAttribute

    public static void setSessionAttribute(HttpServletRequest request, String name, Object value)
      {
        Assert.notNull(request, "Request must not be null");
        if (value != null) {
          request.getSession().setAttribute(name, value);
        }
        else {//进入此步
          HttpSession session = request.getSession(false);
          if (session != null)
            session.removeAttribute(name);//删除falshmap
        }
      }


    接口类org.springframework.web.servlet.FlashMapManager

    public abstract interface FlashMapManager
    {
      public abstract FlashMap retrieveAndUpdate(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse);
    
      public abstract void saveOutputFlashMap(FlashMap paramFlashMap, HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse);
    }
  • 相关阅读:
    三范式最简单最易记的解释
    Mysql添加用户错误:ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value解决方法
    mysql体系结构管理
    mysql的简单操作
    flush privileges刷新MySQL的系统权限相关表
    二进制安装mysql
    扩展一台mysql-5.6.40
    mysql5.6.40部署过程
    三剑客-awk
    三剑客-sed
  • 原文地址:https://www.cnblogs.com/pu20065226/p/10059744.html
Copyright © 2011-2022 走看看