Dockbar是Liferay中最活跃的元素了,因为几乎用户的所有的操作都要从Dockbar开始,所以我们这里深入的来分析下dockbar.

 

Dockbar的结构:

Dockbar从整体上分2部分,一部分是左边的

    另外一部分是右边的

       

       

      所以,最终Dockbar的结构为(我省略了很多代码):

       

         
         
         
         
      1. <%@ include file="/html/portlet/dockbar/init.jsp" %> 
      2.  
      3. <div class="dockbar" data-namespace="" id="dockbar"> 
      4.     <ul class="aui-toolbar"> 
      5.         <li class="pin-dockbar"> 
      6.             <a href="javascript:;"><img alt='' src="<%= HtmlUtil.escape(themeDisplay.getPathThemeImages()) %>/spacer.png" />a> 
      7.         li> 
      8.  
      9.             <li class="add-content has-submenu" id="addContent"> 
      10.                 <a class="menu-button" href="javascript:;"> 
      11.                     <span> 
      12.                         <liferay-ui:message key="add" /> 
      13.                     span> 
      14.                 a> 
      15.      
      16.                  
      17.  
      18.             .. 
      19.  
      20.             <li class="manage-content has-submenu" id="manageContent"> 
      21.                 <a class="menu-button" href="javascript:;"> 
      22.                     <span> 
      23.                         <liferay-ui:message key="manage" /> 
      24.                     span> 
      25.                 a> 
      26.  
      27.                     .. 
      28.                  
      29.                 <div class="aui-helper-hidden layout-customizable-controls" id="layout-customizable-controls"> 
      30.                     <span title=''> 
      31.                         <aui:input helpMessage='<%= group.isLayoutPrototype() ? "modifiable-help" : "customizable-help" %>' inputCssClass="layout-customizable-checkbox" id="TypeSettingsProperties--[COLUMN_ID]-customizable--" label='<%= (group.isLayoutSetPrototype() || group.isLayoutPrototype()) ? "modifiable" : "customizable" %>' name="TypeSettingsProperties--[COLUMN_ID]-customizable--" type="checkbox" useNamespace="<%= false %>" /> 
      32.                     span> 
      33.                 div> 
      34.     .. 
      35.         <li class="aui-toolbar-separator"> 
      36.             <span>span> 
      37.         li> 
      38.  
      39.      
      40.             <li class="toggle-controls" id="toggleControls"> 
      41.                 <a href="javascript:;"> 
      42.                     <liferay-ui:message key="edit-controls" /> 
      43.                 a> 
      44.             li> 
      45.          
      46. ... 
      47.     <ul class="aui-toolbar user-toolbar"> 
      48.          
      49.             <li class="my-sites has-submenu" id="mySites"> 
      50.                 <a class="menu-button" href="javascript:;"> 
      51.                     <span> 
      52.                         <liferay-ui:message key="go-to" /> 
      53.                     span> 
      54.                 a> 
      55.                  
      56.                 .. 
      57.  
      58.                 <div class="aui-menu my-sites-menu aui-overlaycontext-hidden" id="mySitesContainer"> 
      59.                     <div class="aui-menu-content"> 
      60.                         <liferay-ui:my-sites /> 
      61.                     div> 
      62.                 div> 
      63.             li> 
      64.      .. 
      65.  
      66.         <li class="aui-toolbar-separator"> 
      67.             <span>span> 
      68.         li> 
      69.  
      70.         <li class="user-avatar <%= themeDisplay.isImpersonated() ? "impersonating-user has-submenu" : "" %>id="userAvatar"> 
      71.             <span class="user-links <%= themeDisplay.isImpersonated() ? "menu-button": "" %>"> 
      72.                 <aui:a cssClass="user-portrait use-dialog" data-controlPanelCategory="<%= PortletCategoryKeys.MY %>" href="<%= themeDisplay.getURLMyAccount().toString() %>" title="manage-my-account"> 
      73.                     <img alt="<%= HtmlUtil.escape(user.getFullName()) %>" src="<%= HtmlUtil.escape(user.getPortraitURL(themeDisplay)) %>" /> 
      74.                 aui:a> 
      75.  
      76.                 <aui:a cssClass="user-fullname use-dialog" data-controlPanelCategory="<%= PortletCategoryKeys.MY %>" href="<%= themeDisplay.getURLMyAccount().toString() %>" title="manage-my-account"><%= HtmlUtil.escape(user.getFullName()) %>aui:a> 
      77.  
      78.                 <c:if test="<%= themeDisplay.isShowSignOutIcon() %>"> 
      79.                     <span class="sign-out">(<aui:a href="<%= themeDisplay.getURLSignOut() %>" label="sign-out" />)span> 
      80.                 c:if> 
      81.             span> 
      82.  
      83.         ... 

       

      dockbar的portletId:

      dockbar也是一个portlet,因为它也是可以嵌入在页面上的,所以,它也有自己的portletId,我们可以从页面源码中看出来这个portletId为145:

      Liferay Dockbar 解析_第1张图片

      那么这个145是怎么来的呢?

      我们可以去ROOT应用中找,因为dockbar是特殊的系统级的portlet,所以它的id必然定义在liferay-portlet.xml中,事实果然符合我所预料,在/ROOT/WEB-INF/liferay-portlet.xml中指定了这个dockbar的portletId为145:

         
         
         
         
      1. ... 
      2. <portlet> 
      3.         <portlet-name>145portlet-name> 
      4.         <icon>/html/icons/default.pngicon> 
      5.         <struts-path>dockbarstruts-path> 
      6.         <use-default-template>falseuse-default-template> 
      7.         <show-portlet-access-denied>falseshow-portlet-access-denied> 
      8.         <show-portlet-inactive>falseshow-portlet-inactive> 
      9.         <private-request-attributes>falseprivate-request-attributes> 
      10.         <private-session-attributes>falseprivate-session-attributes> 
      11.         <render-weight>50render-weight> 
      12.         <css-class-wrapper>portlet-dockbarcss-class-wrapper> 
      13.         <add-default-resource>trueadd-default-resource> 
      14.         <system>truesystem> 
      15.     portlet> 
      16.  
      17. .. 

       

      生成策略:

      因为Dockbar 也是一个portlet,所以它的也要被解析,参照浏览器调试器可以看出的值是"_145_"

      Liferay Dockbar 解析_第2张图片

      那么这个的值是如何生成的呢?

      我们在util-taglib/src/META-INF/liferay-portlet.tld中找到了元素的定义:

         
         
         
         
      1. <tag> 
      2.         <name>namespacename> 
      3.         <tag-class>com.liferay.taglib.portlet.NamespaceTagtag-class> 
      4.         <body-content>JSPbody-content> 
      5.     tag> 

      可以看出,这个标记的输出是一段JSP(也就是我们例子中的_145_),并且标记类为NamespaceTag 类,这个类很简单:

         
         
         
         
      1. public class NamespaceTag extends TagSupport { 
      2.  
      3.     @Override 
      4.     public int doStartTag() throws JspException { 
      5.         try { 
      6.             HttpServletRequest request = 
      7.                 (HttpServletRequest)pageContext.getRequest(); 
      8.  
      9.             PortletResponse portletResponse = 
      10.                 (PortletResponse)request.getAttribute( 
      11.                     JavaConstants.JAVAX_PORTLET_RESPONSE); 
      12.  
      13.             if (portletResponse != null) { 
      14.                 String namespace = portletResponse.getNamespace(); 
      15.  
      16.                 JspWriter jspWriter = pageContext.getOut(); 
      17.  
      18.                 jspWriter.write(namespace); 
      19.             } 
      20.         } 
      21.         catch (Exception e) { 
      22.             throw new JspException(e); 
      23.         } 
      24.  
      25.         return SKIP_BODY; 
      26.     } 
      27.  

      其实真正输出在jspWriter.write(namespace),而这个namespace字符串内容的是用的portletResponse.getNamespace()生成的,其实是委托PortletResponseUtil的getNamepsace()方法:

         
         
         
         
      1. public String getNamespace() { 
      2.         if (_wsrp) { 
      3.             return "wsrp_rewrite_"
      4.         } 
      5.  
      6.         if (_namespace == null) { 
      7.             _namespace = PortalUtil.getPortletNamespace(_portletName); 
      8.         } 
      9.  
      10.         return _namespace; 
      11.     } 

      所以这里是用的工具类PortalUtil的getPortletNamespace来产生的,我们继续跟进:

         
         
         
         
      1. public static String getPortletNamespace(String portletId) { 
      2.         return getPortal().getPortletNamespace(portletId); 
      3.     } 

      然后用Portal类(实际是实现类PortalImpl类)的getPortletNamespace方法并且传入一个portletId来生成的:

         
         
         
         
      1. public String getPortletNamespace(String portletId) { 
      2.     return StringPool.UNDERLINE.concat(portletId).concat( 
      3.         StringPool.UNDERLINE); 

       

      从这里我们就真相大白了,其实就是一个字符串连接,用下划线+“portletId”+下划线组成,因为在StringPool类中:

         
         
         
         
      1. public static final String UNDERLINE = "_"

      而我们dockbar的portletId为145,所以,dockbar的被解析为"_145_"