设为首页 收藏本站
查看: 1202|回复: 0

[经验分享] 比较 JSR 168 Java Portlet 规范与 IBM Portlet API

[复制链接]

尚未签到

发表于 2015-10-3 15:22:07 | 显示全部楼层 |阅读模式
  本文详细说明了 Java TMJava TMStandardization Request for the Java Portlet 规范(以下称为 JSR 168)和 IBM WebSphere Portal Version 5.0 支持的 IBM Portlet API之间的相似点和不同点。文中解释了 JSR 168 的一些基本概念和特征,并将它们与 IBM Portlet API 进行了比较,并且为两个 Portlet 编程接口中的每一个都提供了一个示例 Portlet。本文是为那些对 Java 编程、Servlet 或Portlet 编程有良好理解并具备 portal 方面的基本知识的 Portlet 开发人员和 Portal 架构师准备的。


  引言
  
随着越来越多的企业Portal 的出现,不同的厂商已经创建了各种用于 Portal 组件的 API(称为 Portlet)。存在多种不兼容的接口产生了应用程序提供者、Portal 消费者和Portal 服务器厂商之间的问题。Java Community Process(JCP)定义的Java Portlet 规范(JSR 168)提供了 Portlet 和 Portal之间的互操作性的标准。它将及时解决这些问题。
  本文档的目的是比较 JSR 168 和 WebSpherePortal V5.0 Portlet API,并且给出了一些示例。
  重要:为了给顾客和合作伙伴提供一个方便的移植窗口,WebSphere Portal的下一个版本仍将支持 IBM Portlet API。
  JSR168 简介
  
Java Standardization Request 168(JSR 168)定义了一个Portlet规范,包括 Portlet 容器和 portlet 之间的合约。JSR 168 是由Java Community Process(JCP)定义的。JSR 168 是由 IBM 和 Sun共同领导的,并且有一个很大的 Expect Group以帮助创建目前可用的最终版本。这个专家组由 Apache Software Foundation、Art Technology Group Inc.(ATG)、BEA、Boeing、Borland、Citrix Systems、Fujitsu、Hitachi、IBM、Novell、Oracle、SAP、SAS Institute、Sun、Sybase、Tibco和 Vignette 组成。关于这个 JSR 的更多信息可以在 http://jcp.org/en/jsr/detail?id=168上找到。
  重要:在本分析中提供的信息不承担任何性质的保证之责。本分析旨在为读者提供一个指示性的工具。
  JSR 168定义
  
这部分提供了基本的 JSR 168定义,目的是帮助您理解 JSR 168 如何融入整个 Portal体系结构中。
  Portal 和 Portlet 容器
  
portal是一个 Web应用程序,它通常提供不同来源的个性化、单点登录的内容集合,并且托管不同后端系统的表示层。
  Portal的主要任务是将不同的应用程序集合到一个页面,这个页面的外观是Portal 用户共有的。Portal也可以有复杂的个性化特征,这些特征能够给用户提供自定义内容。Portal页可以有不同的 Portlet 集,以便为不同的用户创建内容。
  图1展示了 Portal 的体系结构,比如一个由 WebSphere Portal 提供服务的Portal。客户端请求由 PortalWeb 应用程序进行处理,它为当前用户检索当前页上的 Portlet。然后,Portal Web应用程序为每个 Portlet 调用 Portlet 容器来通过 Container Invoker API 检索它的内容。Portlet 容器通过 Portlet API 调用Portlet。Container Provider Service Provider Interface(SPI)允许 portlet 容器通过Portal 检索信息。
  图 1. 基本的 Portal 体系结构
DSC0000.gif
  Portlet 容器运行 Portlet,给它们提供所需的运行时环境,并且管理它们的生命周期。它为Portlet 首选项项提供持久性存储,这使得能够为不同的用户生成自定义输出。
  Portal 页和 Portlet
  
图2展示了基本的 Portal 页组件。Portal 页表示一个完整的标记文档并且聚集若干 Portlet 窗口;也就是说,它将不同的应用程序用户界面组合到一个统一的表示中去。Portal 页使用户能够通过登录对话框向 Portal 验证自己的身份以便访问个性化的 Portal 视图。大部分 Portal 页包括一些导航机制以允许用户导航到其他的 Portal 页。
  
图 2:Portal 页
DSC0001.jpg
  Portlet 窗口包括:


  • 标题栏,带有 Portlet 的标题
  • 修饰,包括用于更改 Portlet 的窗口状态的按钮(比如最大化或最小化 Portlet)和用于更改 Portlet 的模式的按钮(比如显示帮助或编辑预定义的 Portlet 设置)
  • 由 Portlet 产生的内容(也称为一个标记段)。
  图 3在不同的浏览器上展示了一个 Portlet 窗口。如您所见,该 portlet 产生的标记段并不局限于 HTML,而可以是任何标记。
  
图 3:在 HTML 浏览器(顶部)和 WML 浏览器(底部)中显示的 Portlet
DSC0002.jpg
  Portlet 生命周期
  
基本的 portlet 生命周期必须:


  • 初始化,使用初始化类初始化 Portlet 并将其放入服务中。
  • 处理请求,处理不同种类的动作并呈现内容。
  • 完成,使用销毁类除去 Portlet。
  Portlet 基于用户与 Portlet 或 Portal页的交互来接收请求。请求处理分为两个阶段:


  • 动作处理  如果用户单击 Portlet上的链接,就会触发动作。动作处理必须在页面上的任何Portlet 呈现开始之前结束。在动作阶段,Portlet可以改变 Portlet 的状态。

  • 呈现内容  在呈现阶段,Portlet 会产生要发送回客户端的标记。呈现不应该改变任何状态。它允许一个页面重新刷新而不需要改变Portlet  的状态。一个页面上的所有 Portlet的呈现都可以并行执行。

  图 4描述从客户端到 Portlet的请求流,并且更详细地展示了动作和呈现阶段。在这个示例中,Portlet A接收了一个动作。在该动作执行之后,页面(A、B、C)上的所有Portlet 的呈现方法都被调用。
  
图 4. 从客户端到 Portlet 的请求流
DSC0003.gif
  Portlet 模式
  
Portlet执行不同的任务并根据它们的当前函数来创建内容。Portlet模式指示 Portlet 何时将执行函数。Portlet模式指定 Portlet应该执行哪一类任务和应该生成什么样的内容。当调用 Portlet时,Portlet 容器提供当前对 Portlet 的请求的模式。在处理动作请求时,Portlet可以程序化地改变它们的 Portlet 模式。
  JSR 168 定义了三类 Portlet 模式:


  • 必须支持的模式(语义同上)  Edit 显示一个或多个视图以让用户自定义个性化的 Portletsettings.Help Help 显示帮助视图。 View 显示 Portlet 输出。   



  • 可选择的客户模式  About 显示 Portlet 的目的、来源、版本和其他信息。 Config 显示一个或多个配置视图以让管理员配置对所有用户有效的Portlet 设置。 Edit_defaults 设置可修改的首选项的缺省值,这些首选项通常可以在EDIT 屏幕中进行更改。 Preview 呈现输出而不需要后端连接或特定于用户的可用数据。 Print 显示适于打印的视图。   



  • 特定于 Portal 厂商的模式  这些模式只适用于特定的厂商Portal。

  窗口状态
  
窗口状态是分配给 Portlet 生成的 Portal 页面空间的指示器。Portlet容器提供当前的窗口状态给 Portlet,而 Portlet 通过窗口状态来决定它应该呈现多少信息。然而,在处理动作请求时,Portlet也可以程序化地改变它们的窗口状态。
  JSR 168 定义了如下窗口状态: Normal Portlet 与其他 Portlet共享空间,在产生它的输出时应该对考虑这种状态。 Maximized 与处于正常的窗口状态相比,窗口有更真实的状态来提供它的输出。 Minimized Portlet 应该只呈现最小的输出或没有输出。   
  除了这些窗口状态之外,JSR 168 允许 Portal 定义自定义窗口状态。
  数据模式
  
JSR 168为 Portlet定义了不同的机制以访问瞬态数据和持久性数据。
  Portlet 可以设置和获取下列作用域内的瞬态数据:



请求请求有附加的数据,比如请求参数和属性,与Servlet类似。请求可以包含一些特性,以允许进行扩展;也可以包含从Portal 传送到 Portlet 的客户端头字段(反之亦然)。
会话Portlet可以将数据存储在具有全局作用域的会话中,以让 Web应用程序中的其他组件访问这些数据;也可以将数据存储在Portlet作用域中,这个作用域是 Portlet 私有的。
上下文Portlet可以将数据存储在 Web 应用程序上下文中,与 Servlet类似。
    Portlet 可以访问这些作用域内的持久性数据:



每个  PortletPortlet可以将配置和个人数据存储在 Portlet引用中,以允许 Portlet 创建个性化的输出。Portlet可以定义允许用户在编辑模式下更改那些数据(例如股票报价)以及哪些数据是只能由管理员在配置模式下进行更改的配置设置(例如股票报价服务器)。
每个用户Portlet可以读取用户概要信息来针对用户调整它的输出(例如显示用户所在城市的天气情况)。
    Portlet 应用程序
  
所有资源、Portlet 和配置描述符一起打包成一个 Web应用程序档案文件(WAR)。有两个配置描述符:




  • 所有不是 Portlet 的 Web 应用程序资源必须在 web.xml配置描述符中指定。
  • 所有 Portlet 和 Portlet 相关的设置必须在 portlet.xmldeployment 描述符中指定。                                   比较 JSR 168 与 IBM Portlet API
      
    这一部分大概地比较了 JSR 168 Portlet API 与 IBM Portlet API。首先讲解了一些相似的概念,接着说明了两者之间的不同之处。
      相似点
      
    下列概念在 JSR 168和 IBM Portlet API 中是非常相似的。

    特征 相似点 不同点
    Portlet 模式两者都支持基本的 Portlet 模式:Edit、Help 和 View。这种配置模式在 JSR 168中是可选的。IBM Portlet API 不支持其他可选的 JSR 168模式(About、Edit_defaults、Preview、Print)。
    窗口状态支持如下窗口状态:Maximized、Normal和 Minimized。Solo 窗口状态只有 IBM Portlet API支持。
    Portlet 生命周期生命周期是相同的:初始化、处理请求、毁坏。没有
    请求处理请求处理分为处理用户动作的动作阶段和产生标记的呈现阶段。没有
    URL 编码两者都支持创建指向 Portlet或资源的 URL。没有
    包含 Servlet/JSPServlet 和 JSP 可以包括在 Portlet中。没有
    Portlet 会话Portlet可以存储瞬态信息,这些信息应该都在会话中的请求内。没有
    Portlet 应用程序打包两者都通过附加的部署描述符(名为 portlet.xml )来将 Portlet 应用程序打包成 WAR文件。 portlet.xml 格式有所不同。
    基于到期时间的缓存Portlet可以支持基于到期时间的缓存。API使用不同的机制来实现这一功能。
    IBM Portlet API使用轮询机制,在这种机制中, Portal 查询 Portlet以获取标记的有效时间,而在 JSR 168 中,Portlet可以将到期时间附加到创建的每个标记上。在用户之间共享缓存条目只有在IBM Portlet API 中才是可能的。
      不同点
      
    JSR168 和 IBM Portlet API 在以下几个方面有所不同。

    特征 IBM Portlet API JSR 168
    Portlet 应用程序实体使您可以通过部署描述符将抽象的Portlet 应用程序及其不同的实例定义为具体的 Portlet应用程序。这允许重用抽象的 Portlet应用程序的设置,而只重写对于每个具体的 Portlet应用程序惟一的部分。该部署描述符紧跟在 web.xml 部署描述符之后,它定义一个应用程序及其 Portlet定义。
    Portlet 实体Web 部署描述符中的每个 Portlet配置都有一个 Portlet 对象实例。根据 Flyweight模式,可以有许多 PortletSettings 对象来参数化相同的 Portlet对象(基于每个请求)。 PortletSettings 中的改变会应用到这个具体的 Portlet 中的所有 Portlet实例。用户也可以具体 Portlet的个人视图,它是通过使用自定义输出的 PortletData 呈现的。 PortletSettings 和 PortletData 合并成一个名为 PortletPreferences 的对象。
    请求/响应对象Portlet在呈现调用中接收到的请求/响应对象与动作调用接收到的相同。在 JSR 168中,有两个不同的对象。
      JSR 168 独有的特征
      


    这些项只适用于 JSR 168。


    特征 描述
    呈现参数呈现参数允许 Portlet存储它的导航状态。
    呈现参数在随后的呈现请求中保持不变,而只是在Portlet接收到一个新的动作时才发生改变。这启用了书签功能,并且解决了浏览器后退按钮问题。
    全局 HttpSession 作用域Portlets 不仅可以存储具有 Portlet可见性的数据,而且可以存储具有整个 Web 应用程序可见性的数据。
    重定向Portlet可以重定向到动作阶段中的其他 Web 资源。
      IBM Portlet API 独有的特征
      
    以下概念只适用于 IBM?Portlet API。

    特征 描述
    事件事件可以在?Portlet之间发送。
    附加的生命周期侦听器除了动作和呈现之外,生命周期侦听器(比如首页)也不适用于 JSR168 的第一个版本。
    Portlet 菜单让 Portlet可以提供内容到菜单栏,以便通过 Portal页使导航更加容易。
    基于无效时间的缓存让 Portlet可以显式使缓存的内容无效。

    DSC0004.gif



    回页首



      示例 Portlet
      
    这一部分展示一个 HelloWorld Portlet,在两个 API的每一个中都有它的实现。其主要的不同之处突出显示在第二个Portlet 中。
      这两个示例 Portlet 实现了相同的功能:

    • 将 JSP 用于呈现输出
    • 根据特定于用户的数据自定义 Portlet 输出
    • 处理动作以允许用户改变这些动作
      这个示例展示了一个个性化的 HelloWorld Portlet。它通过名称识别用户,并且允许用户进入编辑模式以设置一个新的名称。在 action方法(在 IBM Portlet API 中称为 actionPerformed ,而在 JSR 168中称为 processAction )中,Portlet持久化存储用户输入的新用户名。

    清单 1. IBM Portlet API 示例 Portlet
      首先看一看通过 IBM Portlet API 实现的 Portlet。


    public class HelloWorld extends AbstractPortlet implements ActionListener
    {
    public void doView (PortletRequest request, PortletResponse response)
    throws PortletException, IOException
    {
    //Get the user's name to display from persistent storage
    PortletData portletData = request.getData();
    String stringToDisplay=(String)portletData.getAttribute("userName");
    if (stringToDisplay == null) {
    stringToDisplay = defaultString;    // set default string
    }
    // Add the display string to the portlet request to make it
    // accessible by the view JSP
    request.setAttribute("userName", stringToDisplay);
    // Get a context for the current session for invoking the JSP
    PortletContext context = getPortletConfig().getContext();
    context.include(viewJSP, request, response);
    }
    public void doEdit(PortletRequest portletRequest,
    PortletResponse portletResponse )
    throws PortletException, IOException
    {
    // Create the cancel return URI for the edit page
    PortletURI cancelURI = portletResponse.createReturnURI();
    // Preserve the Cancel URI in the request to make it
    // accessible by the edit JSP
    portletRequest.setAttribute("cancelURI", cancelURI.toString());
    // Create the save URI for the edit page
    PortletURI saveURI = portletResponse.createReturnURI();
    // For the "Save" button the return URI must include the "Save" action
    //    so the Action Listener for this portlet will be invoked      
    SimpleActionHelper.
    addSimplePortletAction(getPortletConfig().getContext(), saveURI, "save");
    // Preserve the Save URI in the request to make it accessible by
    // the edit JSP
    portletRequest.setAttribute("saveURI", saveURI.toString());
    //Get the user's name to display from persistent storage
    String stringToDisplay = (String)
    portletRequest.getData().getAttribute("userName");
    if (stringToDisplay == null) {
    stringToDisplay = defaultString;    // none found, set default string
    }
    // Add the display string to the request to make it accessible by the
    // edit JSP as an inital value of the input field on the edit form
    portletRequest.setAttribute("userName", stringToDisplay);
    // Get a context for the current session for invoking the JSP
    PortletContext context = getPortletConfig().getContext();
    context.include(editJSP, portletRequest, portletResponse);
    }
    public void actionPerformed(ActionEvent event) {
    String action =
    SimpleActionHelper.getActionString(getPortletConfig().getContext(),
    event);
    HelloWorld helloPortlet = (HelloWorld)event.getPortlet();
    PortletLog log = helloPortlet.getPortletLog();
    // If this is a save action, then see if the user specified a name
    if ( action!=null ) {
    if ( action.equals("save") ) {
    PortletRequest request = event.getRequest();
    PortletData portData = request.getData();
    String userName = request.getParameter("userName");
    try {
    // Save the name specified by the user
    if ( userName != null ) {
    portData.setAttribute("userName", userName);
    portData.store();
    }
    } catch ( AccessDeniedException ade ) {
    } catch ( IOException ioe ) {
    log.error( "

    Couldn't write the user date to
    persistence because an I/O Error occurred.

    " );
    }
    }
    }
    }
    }     


    清单 2. JSR 示例Portlet
      现在,看一看已修改为使用 JSR 168 的同一 Portlet。更改过的文本用粗体标记。


    public class HelloWorld extends
    GenericPortlet
    {
    public void doView (
    RenderRequest request,
    RenderResponse response)
    throws PortletException, IOException
    {
    //Get the user's name to display from persistent storage
    Portlet
    Preferences portletData = request.get
    Preferences();  String stringToDisplay = (String) portletData.get
    Value("userName",
    defaultString);
    // Add the display string to the portlet request to make it
    // accessible by the view JSP
    request.setAttribute("userName", stringToDisplay);
    // Get a context for the current session for invoking the JSP
    PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(viewJSP);      
    rd
    .include(request, response);
    }
    public void doEdit(
    RenderRequest portletRequest,
    RenderResponse portletResponse )
    throws PortletException, IOException
    {
    // Create the cancel URI for the edit page
    PortletUR
    L cancelURI = portletResponse.create
    ActionUR
    L();
    // Preserve the Cancel URI in the request to make it
    // accessible by the edit JSP
    portletRequest.setAttribute("cancelURI", cancelURI.toString());
    // Create the save URI for the edit page
    PortletUR
    L saveURI = portletResponse.create
    ActionUR
    L();
    // For the "Save" button the return URI must include the "Save" action
    // so the Action Listener for this portlet will be invoked
    saveURI.setParameter("action", "save");
    // Preserve the Save URI in the request to make it accessible by
    // the edit JSP
    portletRequest.setAttribute("saveURI", saveURI.toString());
    //Get the user's name to display from persistent storage
    String stringToDisplay = portletRequest.get
    Preferences().get
    Value("userName",
    defaultString);
    // Add the display string to the request to make it accessible by the edit JSP
    // as an inital value of the input field on the edit form
    portletRequest.setAttribute("userName", stringToDisplay);
    // Get a context for the current session for invoking the JSP
    PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(editJSP);
    rd.
    include(portletRequest, portletResponse);
    }
    public void
    processAction(ActionRequest request, ActionResponse response)
    throws PortletException, IOException

    {
    String action =
    request.getParameter("action");
    // If this is a save action, then see if the user specified a name
    if ( action!=null ) {
    if ( action.equals("save") ) {
    Portlet
    Preferences portData = request.get
    Preferences();
    String userName = request.getParameter("userName");
    // Save the name specified by the user
    if ( userName != null ) {
    portData.setAttribute("userName", userName);
    portData.store();
    }
    }  


      IBM Portlet API 版本的 Portlet 的主要区别在于:


    • 请求分配器使用  JSR 168 和 IBM Portlet API之间的请求分配器使用略有不同。JSR 168使用相同的机制以从上下文中取得一个请求分配器作为 servlet API 的参数。JSR168使用相同的机制从带有路径的上下文中获取请求分配器,以作为与Servlet API 一样的参数。

    • 持久性 Portlet 数据  JSR 168 的持久性数据 PortletPreferences 有一个类似于 JDK 1.4 Preferences 的API,并且允许为 get方法指定缺省值。不再需要检查零返回值并且显式设置缺省值的代码。JSR168 只允许 String 和 String 数组作为首选项的值;IBMPortlet API 可以支持任意对象。

    • 动作处理  在 JSR 168 中的动作处理被简化,并且不需要创建特定的动作对象被创建。自动创建动作 URL会触发调用 processAction 方法。                                              


    结束语
  
由于 JSR 168 的定义,最终有了一个标准的 Portlet API,它提供独立于 Portal 厂商的编程 Portlet,并且使您可以在不同的 Portal 上不加改变地运行相同的 Portlet。
  JSR 168 的概念与 IBM Portlet API 有密切的联系。与 IBM Portlet API 相比,JSR 168的功能是有限的,因为它是 Portlet 规范的 第一个版本。熟悉 IBM Portlet API 的开发人员应该能够毫无困难地尽快学会使用JSR 168 API。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-122254-1-1.html 上篇帖子: 来自-老赵:IBM面试记 下篇帖子: IBM X3650M4简单排错方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表