提要 本文重点讨论如何利用bea weblogic portal所提供的新功能实现ui(titlebar)的定制开发。
一、 引言
也许,没有什么比发行你的第一个portal产品更让你激动的了。在经过长时间的努力后,你(和你的团队)所倾力开发的应用程序终于与用户见面了!然而,本文不是教给你如何进行基本的portal开发,而是探讨如何为你的现有portal加入新的功能。
本文将描述有关bea weblogic portal的一些非常有用的新特征-你可以借助这些特征来扩展你的portal页面功能。
二、 定制titlebar
如果你已经使用过所有内置的titlebar功能,那么你可以很容易地实现titlebar的定制--你仅需要把一些新图标放到其上即可。首先,让我们看一下bea为portal开发在titlebar所提供的内置功能(分别对应四个图标):
? minimize:如果页面上有相当多的portlet以至于用户想最小化其中的某些以便看清其它portlet,那么在设计初期可能把它们分解成独立的页面更好些。
? maximize:这在使用一种多列布局时非常有用,尽管通常情况下,许多用户更喜欢单列布局。
? delete:如果不进行编程,那么这个图标不会作为用户设置数据的一部分而存储起来;因此这有可能惹恼你的用户-每次必须返回。更不用提,如果他们真正想要返回的话,他们不得不开始一个新的会话。
? help:这项功能几乎是必须的。
因此,对大多数用户来说,在titlebar中只放置一个图标就够了。然而,下面我们将详细讨论如何进一步定制titlebar-再添加两个用户常用图标。
三、 加入打印图标
我们知道,现在已经到了无纸办公时代。尽管如此,portal用户仍会使用打印图标。而实际上,除了昂贵的报告和旅行计划外,他们真正想要打印的其实只是该页面的一部分:单个的portlet。作为开发者,只要用户需要,我们就应该尽最大努力满足他们的要求。因此,下面我将向你介绍怎样打印单个的portlet。
注意,本文中的例程实现与命名惯例有一定联系。但是,我们所使用的命名不会影响真正的实现机制。首先,让我们来看一下window.jsp文件中的下面一行代码:
在此,你仅需要把id值改变为window.getdefinitionlabel(),因为它可由所有版本的portal从任何存在window上下文的地方进行存取。
现在,既然你已经有一个该portlet的句柄,那么你可以创建一个能够打开一个可打印页面的小脚本。
上面的脚本应该驻留在一个.js文件中,这样在每个页面上就可以只加载单个副本。
然后,打开titlebar.jsp并且找到下面内容:
在这个空的td(填充了bea图标)中,放入你的打印图标和一个对你的脚本的调用。为了实现可移植性,你要动态地传入参数:
这样就可以使你的新图标出现在你的用户titlebar中:
最后,你需要创建你自己的打印页面以使该图标做一些有用的事情。因为该页面不是portal上下文的一部分,所以你需要硬编码你的样式参考(style reference)。另外,由于在标准框架中的嵌套div的继承特点,所以你需要一些正式生成的html,后面再另上你的脚本生成和打印该portlet的部分代码:
阅读完上面的标注和代码后,你就会看到,我们已定义的标签现在可用于填充我们的弹出菜单-通过仅使用portlet实现,从而使该页面的其它空间用于实现打印,如下图所示:
当然,你还可以进一步修改这个打印页面,例如停用链接或把页面馈送到一个隐蔽的iframe并且由用户调用打印功能,等等。 四、 加入速算表功能
与打印密切相关的另外一项功能-也是商业用户最经常使用的一项功能,是操作表格数据。当然,在他们登录到你的portal的同时,你可以通过实现一些ajax技巧以允许他们以不同方式来观看数字,而且很可能你应该这样做。但是,当用户想取走你的数据并想在飞机上操作它们时,情况会如何呢?通过对整个portal加以缓冲而使他们陷于困境,或者提示他们如何把数据复制到一个速算表(除非你有一项巨大的技术支持预算)中吗?最好不要这样。那么,你为什么不按他们想要的方式把数据给他们呢?
我们的实现思想是,首先通过标签定义得到我们的portlet的一个句柄,然后用它构建一个速算表。
注意,现在你想要在自己的页面上创建一个隐藏的iframe来接收页面(因为其结果是一个文件,而不是一个页面)。为此,你只需把下面内容添加到footer.jsp中:
然后,你要在你的jsp文件中建立一个类似于打印函数的新函数。不过这个新函数作了一些改变以隐藏被调用的页面并传递表格数据:
接下来,你要使用与前面操作打印图标类似的方式来把你的图标添加到工具栏上-当然现在你必须隐藏该图标(直到你想使用它并且参考你的表格而不是整个的portlet为止)。请参考如下代码:
当然,为了使用该图标,你首先需要取消隐藏它。为此,你可以在portlet jsp本身实现-通过添加一个到window上下文的参考,然后再调用你的标签定义的句柄,象下面这样:
当然,你还要编写一个简短的jsp来生成你的速算表:
在隐藏的iframe和响应变化这一时间段内,用户只能看到下载部分,而不会看到屏幕后台的逻辑实现:
如果你在表格的标题行上使用了<th>标签,那么excel将把它设置为一个标题行以便于可能的进一步排序。
如果你在一个portlet中有多张表,你可以使用相同的参考id来打开该图标从而动态地设置脚本调用。 五、更新日期数据
现在,我们要实现更新日期的问题-向titlebar中添加portlet最后被更新的日期信息。当然,你可以把此信息放到portlet本身的设计中去;但是,通过这种方式将会节省屏幕空间。
因为bea没有事先考虑到这一点,所以你需要简单地修改一下titelbar.jsp-把声明移到生成上下文的外面即可。然后,找到声明windowpresentationcontext的scriptlet部分并且把这一部分移动到<render:beginrender>标签的上面。现在,既然你能够从render范围的外部存取window对象,那么,让我们把下列语句添加到</tr>后面:
现在,让我们看一下所有你需要添加到你的portlet上的代码:
最后,你会得到如下一幅图像:
六、增加水平和垂直导航功能
加入了上面这些特征之后,你的portal将会更为流行,而且用户可能会要求增加更多的portlet。更多portlet将导致更多的页面(这样会使得页面空间非常拥挤,更不用提速度的问题了)。如果页面数继续增长,你的portal将最后变得很难在超出屏幕范围的组件(更不用提令用户恼火的向旁边卷动的组件了,见下图)之间进行导航。
标准的单级导航方式可以卷动,但是页面导航中的其它行将占居屏幕上方的空间。另外,你可以使用多级菜单方案,但是这将使用户为找到其目标增加更多的鼠标移动(尽管在你的站点有大量的页面时,这种情况也是难以避免的)。
要解决上面难堪的导航问题有一个非常酷的技巧:除了原有的水平导航选项卡外,你可以再增加一种垂直导航。这样可以把你的可视化设计和页面数目扩展许多--几乎加倍原来单个页面的存取空间。
实现这种双向导航方式的关键是使用隐藏的页面设置。
标准的单级菜单代码象下面这样跳过隐藏的页面:
你可以在单级菜单代码的后面为你的垂直菜单添加一个div区,然后使用相反的检查来运行相同的循环:
我去除了对isvisible的检查--它是冗余的。
现在,通过使用一些简单的css技巧,你就可以把这个菜单放到你想要放置的任何地方。在本文示例中,我选择把它放到右边:
至此,你用了不到10分钟实现了该页面的重新调用。
如果已经隐蔽了页面,那么就可以检查并使用你新加入的图标了。尽管可以实现这种类型的导航,但是我更喜欢使用图标方式。在我实现的portal中,选择水平的还是垂直的导航链接是由相应的页面类型决定的。例如,在一个主要面对商业信息的portal中,经常存在一些与主要内容不相关的页面(例如事件日历和业界新闻),但是对你的主要用户来说可能仍然具有一定参考价值。这些"工具"页面会把他们自然地导向其它不同的导航模型--它们独立于portal的中心内容。
在bea weblogic portal service pack 4之前,在api中存在一处不太合适的地方-pagectx.ishidden()从不返回true,因为该框架能够从页面列表中提取隐藏的页面(在把该隐藏页面返回到预定的上下文之前)。不过,你仍然能够使用隐藏的页面,但是你必须硬编码它们的值,而不是简单地通过增加更多隐藏的页面来动态地扩展你的垂直导航。因此,为了确保你的硬编码具有可移植性,请确保对链接使用了render标签,如下所示:
总之,就算你的用户对你第一次发布你的portal感到非常高兴,甚至于从未要求过什么;但是,现在你可以通过仅付出一点点努力而带给他们一些额外的惊喜了。
一、 引言
也许,没有什么比发行你的第一个portal产品更让你激动的了。在经过长时间的努力后,你(和你的团队)所倾力开发的应用程序终于与用户见面了!然而,本文不是教给你如何进行基本的portal开发,而是探讨如何为你的现有portal加入新的功能。
本文将描述有关bea weblogic portal的一些非常有用的新特征-你可以借助这些特征来扩展你的portal页面功能。
二、 定制titlebar
如果你已经使用过所有内置的titlebar功能,那么你可以很容易地实现titlebar的定制--你仅需要把一些新图标放到其上即可。首先,让我们看一下bea为portal开发在titlebar所提供的内置功能(分别对应四个图标):
? minimize:如果页面上有相当多的portlet以至于用户想最小化其中的某些以便看清其它portlet,那么在设计初期可能把它们分解成独立的页面更好些。
? maximize:这在使用一种多列布局时非常有用,尽管通常情况下,许多用户更喜欢单列布局。
? delete:如果不进行编程,那么这个图标不会作为用户设置数据的一部分而存储起来;因此这有可能惹恼你的用户-每次必须返回。更不用提,如果他们真正想要返回的话,他们不得不开始一个新的会话。
? help:这项功能几乎是必须的。
因此,对大多数用户来说,在titlebar中只放置一个图标就够了。然而,下面我们将详细讨论如何进一步定制titlebar-再添加两个用户常用图标。
三、 加入打印图标
我们知道,现在已经到了无纸办公时代。尽管如此,portal用户仍会使用打印图标。而实际上,除了昂贵的报告和旅行计划外,他们真正想要打印的其实只是该页面的一部分:单个的portlet。作为开发者,只要用户需要,我们就应该尽最大努力满足他们的要求。因此,下面我将向你介绍怎样打印单个的portlet。
注意,本文中的例程实现与命名惯例有一定联系。但是,我们所使用的命名不会影响真正的实现机制。首先,让我们来看一下window.jsp文件中的下面一行代码:
| <render:writeattribute name="id" value="<%= window.getpresentationid() %>"/> |
在此,你仅需要把id值改变为window.getdefinitionlabel(),因为它可由所有版本的portal从任何存在window上下文的地方进行存取。
现在,既然你已经有一个该portlet的句柄,那么你可以创建一个能够打开一个可打印页面的小脚本。
| function printportlet(apppath, portletid, portletname){ var pagestring = apppath+'/resources/jsp/ printpage.jsp?portletid='+portletid; var printwindow = window.open(pagestring, 'printpage',"location=no,scrollbars=no,resizable"); printwindow.focus(); } |
上面的脚本应该驻留在一个.js文件中,这样在每个页面上就可以只加载单个副本。
然后,打开titlebar.jsp并且找到下面内容:
| <td class="bea-portal-window-titlebar-buttons" nowrap="nowrap"> |
在这个空的td(填充了bea图标)中,放入你的打印图标和一个对你的脚本的调用。为了实现可移植性,你要动态地传入参数:
| <img src="<render:getskinpath imagename="printericon.gif" />" style="cursor:pointer; position:relative; top:-2px" onclick="printportlet('<%=request.getcontextpath()%>', '<%=window.getdefinitionlabel()%>')"> |
这样就可以使你的新图标出现在你的用户titlebar中:
![]() |
最后,你需要创建你自己的打印页面以使该图标做一些有用的事情。因为该页面不是portal上下文的一部分,所以你需要硬编码你的样式参考(style reference)。另外,由于在标准框架中的嵌套div的继承特点,所以你需要一些正式生成的html,后面再另上你的脚本生成和打印该portlet的部分代码:
| <%@ page language="java" contenttype="text/html;charset=utf-8"%> <%@ taglib uri="netui-tags-html.tld" prefix="netui"%> <netui:html> <head> <title> portlet print page </title> <meta name="bea-portal-meta-skin" content="/framework/skins/default"/> <meta name="bea-portal-meta-skin-images" content="/framework/skins/default/images"/> <link href="/snelsondemo/framework/skins/default/ css/body.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ css/button.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ alert/css/window-alert.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ css/window.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ plain/css/window-plain.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ css/portlet.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ css/book.css" rel="stylesheet"/> <link href="/snelsondemo/framework/skins/default/ css/layout.css" rel="stylesheet" type="text/css"/> <link href="/snelsondemo/framework/skins/default/ css/form.css" rel="stylesheet" type="text/css"/> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ menu.js"></script> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ util.js"></script> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ delete.js"></script> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ float.js"></script> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ menufx.js"></script> <script type="text/javascript" src="/snelsondemo/framework/skins/default/js/ skin.js"></script> <style type="text/css"> .bea-portal-window-titlebar-title{font-weight:bold} </style> </head> <body class="bea-portal-body"> <div class="bea-portal-book-primary"> <div class="bea-portal-book-primary-content"> <div class="bea-portal-book-primary-page" style="margin-right:10px"> <div id="portlethtml" class="bea-portal-window"> </div> </div> </div> </div> <script language="javascript"> var portletid = '<%=request.getparameter("portletid")%>'; document.getelementbyid('portlethtml').innerhtml = self.opener.document.getelementbyid(portletid). innerhtml; window.print(); </script> </body> </netui:html> |
阅读完上面的标注和代码后,你就会看到,我们已定义的标签现在可用于填充我们的弹出菜单-通过仅使用portlet实现,从而使该页面的其它空间用于实现打印,如下图所示:
![]() |
当然,你还可以进一步修改这个打印页面,例如停用链接或把页面馈送到一个隐蔽的iframe并且由用户调用打印功能,等等。 四、 加入速算表功能
与打印密切相关的另外一项功能-也是商业用户最经常使用的一项功能,是操作表格数据。当然,在他们登录到你的portal的同时,你可以通过实现一些ajax技巧以允许他们以不同方式来观看数字,而且很可能你应该这样做。但是,当用户想取走你的数据并想在飞机上操作它们时,情况会如何呢?通过对整个portal加以缓冲而使他们陷于困境,或者提示他们如何把数据复制到一个速算表(除非你有一项巨大的技术支持预算)中吗?最好不要这样。那么,你为什么不按他们想要的方式把数据给他们呢?
我们的实现思想是,首先通过标签定义得到我们的portlet的一个句柄,然后用它构建一个速算表。
注意,现在你想要在自己的页面上创建一个隐藏的iframe来接收页面(因为其结果是一个文件,而不是一个页面)。为此,你只需把下面内容添加到footer.jsp中:
| <iframe id="scriptrender" src="" style="visibility:hidden; height:0px; padding:0px; margin:0px"></iframe> |
然后,你要在你的jsp文件中建立一个类似于打印函数的新函数。不过这个新函数作了一些改变以隐藏被调用的页面并传递表格数据:
| function excelportlet(apppath, tableid, portletname){ var tabledata = document.getelementbyid(tableid).outerhtml; var pagestring =apppath+'/resources/jsp/excelpage.jsp?tabledata='+tabledata+'&portletname='+portletname; document.getelementbyid('scriptrender').src = pagestring; } |
接下来,你要使用与前面操作打印图标类似的方式来把你的图标添加到工具栏上-当然现在你必须隐藏该图标(直到你想使用它并且参考你的表格而不是整个的portlet为止)。请参考如下代码:
| <img src="<render:getskinpath imagename="excelicon.gif" />" id="<%=window.getdefinitionlabel()%>.excelicon" style="cursor:pointer; position:relative; top:-2px; visibility:hidden" onclick= "excelportlet('<%=request.getcontextpath()%>', '<%=window.getdefinitionlabel()%>. exceltable', '<%= title %>')"> |
当然,为了使用该图标,你首先需要取消隐藏它。为此,你可以在portlet jsp本身实现-通过添加一个到window上下文的参考,然后再调用你的标签定义的句柄,象下面这样:
| <%@ page import="com.bea.netuix.servlets.controls.window. windowpresentationcontext"%> <% windowpresentationcontext window =windowpresentationcontext. getwindowpresentationcontext(request); %> <script language="javascript"> document.getelementbyid('<%=window.getdefinitionlabel()%>.excelicon') .style.visibility = 'visible'; </script> |
当然,你还要编写一个简短的jsp来生成你的速算表:
| <%@ page language="java" contenttype="text/html;charset=utf-8"%> <% string tabledata = request.getparameter("tabledata"); response.reset(); response.setcontenttype("application/xls"); response.setheader("content-disposition","attachment;filename=" +request.getparameter("portletname") +".xls"); %> <%=tabledata%> |
在隐藏的iframe和响应变化这一时间段内,用户只能看到下载部分,而不会看到屏幕后台的逻辑实现:
![]() |
如果你在表格的标题行上使用了<th>标签,那么excel将把它设置为一个标题行以便于可能的进一步排序。
![]() |
如果你在一个portlet中有多张表,你可以使用相同的参考id来打开该图标从而动态地设置脚本调用。 五、更新日期数据
现在,我们要实现更新日期的问题-向titlebar中添加portlet最后被更新的日期信息。当然,你可以把此信息放到portlet本身的设计中去;但是,通过这种方式将会节省屏幕空间。
因为bea没有事先考虑到这一点,所以你需要简单地修改一下titelbar.jsp-把声明移到生成上下文的外面即可。然后,找到声明windowpresentationcontext的scriptlet部分并且把这一部分移动到<render:beginrender>标签的上面。现在,既然你能够从render范围的外部存取window对象,那么,让我们把下列语句添加到</tr>后面:
| <tr><td colspan="3" id="<%=window.getdefinitionlabel()%>.datecell"></td></tr> |
现在,让我们看一下所有你需要添加到你的portlet上的代码:
| <% string mydate = "as of march 1, 2006"; %> document.getelementbyid('<%=window.getdefinitionlabel()%> .datecell').innerhtml = '<%=mydate%>'; |
最后,你会得到如下一幅图像:
![]() |
六、增加水平和垂直导航功能
加入了上面这些特征之后,你的portal将会更为流行,而且用户可能会要求增加更多的portlet。更多portlet将导致更多的页面(这样会使得页面空间非常拥挤,更不用提速度的问题了)。如果页面数继续增长,你的portal将最后变得很难在超出屏幕范围的组件(更不用提令用户恼火的向旁边卷动的组件了,见下图)之间进行导航。
![]() |
标准的单级导航方式可以卷动,但是页面导航中的其它行将占居屏幕上方的空间。另外,你可以使用多级菜单方案,但是这将使用户为找到其目标增加更多的鼠标移动(尽管在你的站点有大量的页面时,这种情况也是难以避免的)。
要解决上面难堪的导航问题有一个非常酷的技巧:除了原有的水平导航选项卡外,你可以再增加一种垂直导航。这样可以把你的可视化设计和页面数目扩展许多--几乎加倍原来单个页面的存取空间。
实现这种双向导航方式的关键是使用隐藏的页面设置。
![]() |
标准的单级菜单代码象下面这样跳过隐藏的页面:
| if (!pagectx.ishidden() && pagectx.isvisible()) |
你可以在单级菜单代码的后面为你的垂直菜单添加一个div区,然后使用相反的检查来运行相同的循环:
| if (pagectx.ishidden()) |
我去除了对isvisible的检查--它是冗余的。
现在,通过使用一些简单的css技巧,你就可以把这个菜单放到你想要放置的任何地方。在本文示例中,我选择把它放到右边:
| <div id="verticalmenu" style="position:absolute; top:40px; right:20px; width:20px;"> |
![]() |
至此,你用了不到10分钟实现了该页面的重新调用。
如果已经隐蔽了页面,那么就可以检查并使用你新加入的图标了。尽管可以实现这种类型的导航,但是我更喜欢使用图标方式。在我实现的portal中,选择水平的还是垂直的导航链接是由相应的页面类型决定的。例如,在一个主要面对商业信息的portal中,经常存在一些与主要内容不相关的页面(例如事件日历和业界新闻),但是对你的主要用户来说可能仍然具有一定参考价值。这些"工具"页面会把他们自然地导向其它不同的导航模型--它们独立于portal的中心内容。
在bea weblogic portal service pack 4之前,在api中存在一处不太合适的地方-pagectx.ishidden()从不返回true,因为该框架能够从页面列表中提取隐藏的页面(在把该隐藏页面返回到预定的上下文之前)。不过,你仍然能够使用隐藏的页面,但是你必须硬编码它们的值,而不是简单地通过增加更多隐藏的页面来动态地扩展你的垂直导航。因此,为了确保你的硬编码具有可移植性,请确保对链接使用了render标签,如下所示:
| <a href="<render:pageurl pagelabel=" hackinguinews"/>">news</a> |
总之,就算你的用户对你第一次发布你的portal感到非常高兴,甚至于从未要求过什么;但是,现在你可以通过仅付出一点点努力而带给他们一些额外的惊喜了。








闽公网安备 35060202000074号