Terry.Li-彬

          虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
           

          上一篇講到當用戶在瀏覽器地址欄上輸入http://localhost:8080/后,經過幾次迭代,服務器最終處理的是http://localhost:8080/c/portal/update,那當服務器收到/c/portal/update的請求后做了什么動作,最后是怎么向瀏覽器發送網頁信息呢?

          1. 首先MainServlet接收這個請求,然后傳遞到LayoutAction。(具體怎么傳遞后續會介紹到)
          在struts-config.xml中有定義,表明有關"/portal/layout"的請求是由LayoutAction來處理的。而在tiles-def.xml中定義"/portal/layout"最終傳遞到"/portal/layout.jsp"。

          struts-config.xml
          ------------------------
          <action path="/portal/layout" type="com.liferay.portal.action.LayoutAction">
            <forward name="portal.layout" path="portal.layout" />
          </action>

          tiles-def.xml
          ------------------
          <definition name="portal.layout" extends="portal">
          <put name="content" value="/portal/layout.jsp" />
           <put name="selectable" value="true" />
          </definition>

          2. 下面分析LayoutAction的簡要流程

          LayoutAction.execute()
          --------------------------------
          ThemeDisplay themeDisplay = (ThemeDisplay)req.getAttribute(WebKeys.THEME_DISPLAY);
          Layout layout = themeDisplay.getLayout();

          /* 加入/html/portal/layout/view/portlet.jsp 到網頁*/
          incluldeLayoutContent(req, res, themeDisplay, layout);

          /* 加入/html/portal/layout.jsp 到網頁,先portlet.jsp,后layout.jsp*/
          return mapping.findForward("portal.layout");

          LayoutAction.includeLayoutContent()
          -----------------------------------------------------
          String path = StrutsUtil.TEXT_HTML_DIR;
          /* path = "/html" */

          path += PortalUtil.getLayoutViewPage(layout);
          /* path = "/html/portal/layout/view/portlet.jsp" */

          RequestDispatcher rd = ctx.getRequestDispatcher(path);
          rd.include(req, stringServletRes);

          可見兩個jsp文件是頁面的關鍵所在。

          /portal/layout/view/portlet.jsp
          -----------------------------------------
          <%
          String content = LayoutTemplateLocalUtil.getContent(layoutTypePortlet.getLayoutTemplateId(),
             false, theme.getThemeId());
          %>
          <%= RuntimePortletUtil.processTemplate(application, request, response, pageContext, content) %>

          /*****************************************************
          其中content的內容通過斷點調試可以知道(是什么時候生成的呢?)
          <div class="columns-2" id="content-wrapper">
            <table id="layout-grid">
              <tr>
                <td class="lfr-column thirty" id="column-1" valign="top">
                  $processor.processColumn("column-1")
                </td>
                <td class="lfr-column seventy" id="column-2" valign="top">
                  $processor.processColumn("column-2")
                </td>
              </tr>
            </table>
          </div>
          *****************************************************/
          /* RuntimePortletUtil.processTemplate()函數返回的是一個很長很長的字符串,就是最終用于顯示頁面上各個portlet的代碼,下面有分析 */

          RuntimePortletUtil.processTemplate()
          ------------------------------------------------------
          TemplateProcessor processor = new TemplateProcessor(ctx, req, res, portletId);
          VelocityContext vc = new VelocityContext();
          vc.put("processor", processor);
          // Velocity variables
          VelocityVariables.insertVariables(vc, req);
          vc.put("taglibLiferay", velocityTaglib);
          vc.put("theme", velocityTaglib);
          StringWriter sw = new StringWriter();
          Velocity.evaluate(vc, sw, RuntimePortletUtil.class.getName(), content);

          String output = sw.toString();
          /*****************************************************
          output的初始內容為:
          <div class="columns-3" id="content-wrapper">
            <table id="layout-grid">
              <tr>
                <td class="lfr-column thirty" id="column-1" valign="top">
                  [$TEMPLATE_COLUMN_column-1$]
                </td>
                <td class="lfr-column thirty" id="column-2" valign="top">
                  [$TEMPLATE_COLUMN_column-2$]
                </td>
                <td class="lfr-column thirty" id="column-3" valign="top">
                  [$TEMPLATE_COLUMN_column-3$]
                </td>
              </tr>
            </table>
          </div>
          *****************************************************/

          Map columnsMap = processor.getColumnsMap();

          while (itr.hasNext()) {
            Map.Entry entry = (Map.Entry)itr.next();
            String key = (String)entry.getKey();
            String value = (String)entry.getValue();
            output = StringUtil.replace(output, key, value);
          }

          /*****************************************************
          如果首頁面上有四個portlet,名字為A,B,C,D,其中A在左邊一列上,B,C同在中間一列,D在右邊一列。則output的內容為:
          <div class="columns-3" id="content-wrapper">
            <table id="layout-grid">
              <tr>
                <td class="lfr-column thirty" id="column-1" valign="top">
                  <div class="lfr-portlet-column" id="layout-column_column-1">
                    [$TEMPLATE_PORTLET_A$]
                  </div>
                </td>
                <td class="lfr-column thirty" id="column-2" valign="top">
                  <div class="lfr-portlet-column" id="layout-column_column-2">
                    [$TEMPLATE_PORTLET_B$]
                    [$TEMPLATE_PORTLET_C$] 
                  </div>
                </td>
                <td class="lfr-column thirty" id="column-3" valign="top">
                  <div class="lfr-portlet-column" id="layout-column_column-3">
                    [$TEMPLATE_PORTLET_D$] 
                  </div>
                </td>
              </tr>
            </table>
          </div>
          *****************************************************/

          Map portletsMap = processor.getPortletsMap();
          itr = portletsMap.entrySet().iterator();
          while (itr.hasNext()) {
            StringMaker sm = new StringMaker();
            processPortlet(sm, ctx, req, res, portlet, queryString, columnId, columnPos,columnCount, null);
            output = StringUtil.replace(output, "[$TEMPLATE_PORTLET_" + portlet.getPortletId() + "$]", sm.toString());

          /*****************************************************
            這里每迭代一個portlet,output的內容中就添加了該portlet的view.jsp代碼段落,而且還會增加portlet的標準頭部和邊框,如最小化,關閉等按鈕及其對應的JavaScript代碼。
          *****************************************************/
          }

          return output;
          /* 這個output就是在portlet.jsp中要顯示的內容 */


          portal.jsp
          ------------
          <c:choose>
            <c:when test="<%= themeDisplay.isStateExclusive() %>">
              <%= request.getAttribute(WebKeys.LAYOUT_CONTENT) %>
            </c:when>
            <c:when test="<%= themeDisplay.isStatePopUp() %>">
              <liferay-theme:include page="portal_pop_up.jsp" />
            </c:when>
            <c:otherwise>
              <liferay-theme:include page="portal_normal.jsp" />
            </c:otherwise>
          </c:choose>

          在Liferay中沒有發現portal_normal.jsp的蹤影,發現portal_normal.vm似乎有點相關。portal_normal粉墨登場。

          portal_normal.vm
          -------------------------
          #parse ($init)
          <html dir="#language ("lang.dir")">
          <head>
            <title>$company_name - $the_title</title>
              $theme.include($top_head_include)
              #css ($css_main_file)
              #js ($js_main_file)
              #if ($company_logo != "")
                <style type="text/css">
                  #banner .logo {background: url($company_logo) no-repeat;
                         height: ${company_logo_height}px;
                         width: ${company_logo_width}px; }
                </style>
              #end
          </head>

          <body class="$css_class">
          $theme.include($top_messages_include)
          <div id="wrapper">
            <div id="banner">
              <div id="banner-inner">
                <h1 class="logo">
                  <a href="$company_url">$company_name</a>
                </h1>
                <div id="page-search">
                  $theme.journalContentSearch()
                </div>
                #parse ("$full_templates_path/dock.vm")
                  #if ($update_available_url)
                    <div class="popup-alert-notice">
                      <a class="update-available" href="$update_available_url">#language("updates-are-available-for-liferay")</a>
                    </div>
                  #end
                  #if ($has_navigation)
                    #parse ("$full_templates_path/navigation.vm")
                  #end
                </div>
              </div>

              #if ($selectable)
                $theme.include($content_include)
              #else
                <div id="content-wrapper" class="login">
                  $portletDisplay.recycle()
                  $portletDisplay.setTitle($the_title)
                  $theme.wrapPortlet("portlet.vm", $content_include)
                </div>
              #end

              <div id="footer">
                <p class="language">$theme.language()</p>
              </div>
          </div>

          $theme.include($bottom_ext_include)
          $theme.include($session_timeout_include)
          $theme.include($sound_alerts_include)

          </body>
          </html>

          可見關鍵是一些Velocity變量的值,例如$top_head_include。


          init.vm
          ----------
          #set ($bottom_ext_include = "$dir_include/common/themes/bottom.jsp")
          #set ($content_include = "$dir_include$tilesContent")
          #set ($session_timeout_include = "$dir_include/common/themes/session_timeout.jsp")
          #set ($sound_alerts_include = "$dir_include/common/themes/sound_alerts.jsp")
          #set ($top_head_include = "$dir_include/common/themes/top_head.jsp")
          #set ($top_messages_include = "$dir_include/common/themes/top_messages.jsp")

          可見$top_head_include就是top_head.jsp。

          top_head.jsp
          -------------------
          <%@ include file="/html/common/themes/top_js.jspf" %>
          <%@ include file="/html/common/themes/top_js-ext.jsp" %>
          portal/portal-web/docroot/html/common/themes/top_js.jspf
          <%
            String[] javaScriptFiles = PropsUtil.getArray(PropsUtil.JAVASCRIPT_FILES);
            for (int i = 0; i < javaScriptFiles.length; i++) {
          %>
          <script src="<%= themeDisplay.getPathJavaScript() %>/<%= javaScriptFiles[i] %>" 
          type="text/javascript"></script>
          <%
          }
          %>

          那javascriptFiles又如何得到的呢?

          portal.properties
          ------------------------
          javascript.files=\
                  jquery/jquery.js,\
                  jquery/cookie.js,\
               
                  jquery/tabs.js,\
                  \
                  liferay/liferay.js,\
                  liferay/browser.js,\
                  liferay/util.js,\
                  liferay/language.js,\
                  liferay/layout.js,\
                  \
                  liferay/ajax.js,\
                  liferay/animate.js,\
                  liferay/auto_fields.js,\
                  liferay/color_picker.js,\
                  liferay/columns.js,\
                  liferay/dock.js,\
                  liferay/dynamic_select.js,\
                  liferay/freeform.js,\
                  liferay/layout_configuration.js,......

          另外還有一個很重要的properties文件值得關注:language.properties。好累啊,還有很多細節可以繼續挖掘,還涉及到Velocity的一些變量的操作,休息下先。

           

          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2177391

          posted on 2008-03-14 14:11 禮物 閱讀(1810) 評論(0)  編輯  收藏 所屬分類: Liferay
          主站蜘蛛池模板: 楚雄市| 犍为县| 大埔区| 巴南区| 思南县| 广饶县| 仁布县| 高邮市| 安仁县| 沁源县| 开平市| 盐亭县| 涞水县| 福清市| 崇明县| 永定县| 民县| 鄢陵县| 新丰县| 社旗县| 临湘市| 广丰县| 抚州市| 宁阳县| 长沙县| 嘉鱼县| 灵宝市| 灌南县| 通海县| 云霄县| 航空| 平南县| 宁安市| 右玉县| 上思县| 六枝特区| 柳河县| 黎平县| 固安县| 饶河县| 衡东县|