什麼是Portlet ?

什麼是Portlet ?

作者:Sunil Patil

譯者:observer





版權聲明:任何獲得Matrix授權的網站,轉載時請務必以超鏈接形式標明文章原始出處和作者信息及本聲明
作者:Sunil Patil;observer
原文地址:http://www.onjava.com/pub/a/onjava/2005/10/19/challenging-java-dominance.html
中文地址:http://www.matrix.org.cn/resource/article/44/44029_Portlet.html
關鍵詞: Portlet Java


Portlets
“Portlets是一種Web組件-就像servlets-是專爲將合成頁面裏的內容聚集在一起而設計的。通常請求一個portal頁面會引發多個portlets被調用。每個portlet都會生成標記段,並與別的portlets生成的標記段組合在一起嵌入到portal頁面的標記內。”(摘自Portlet規範,JSR 168)

本文探討了以下內容:
1.        Portal頁面的元素
2.        Portal是什麼?
3.        Portlets是什麼?
4.        開發“Hello World” Portlet
5.        在Pluto上部署HelloWorld Portlet
6.        如何創建Portal頁面
7.        結束語
8.        資源


  Portlet規範將portlet定義爲一種“基於Java技術的web組件,由處理請求和生成動態內容的portlet容器管理”。這段話聽起來是不是有些費解?本文將說明portlets是什麼以及能用它們做什麼。


圖1顯示了在訪問一個portal服務器時瀏覽器中頁面的樣子。

image
圖1 典型的portal服務器的頁面(點擊查看原圖)

  如果仔細查看瀏覽器裏的頁面,就會看到頁面是由不同的“窗口”組成的。一個窗口用於刷新天氣,另一個用於新聞,還有一個用於刷新股價,等等。這裏的每一個窗口都代表了一個portlets。如果看得再仔細些,還會發現每個窗口都有一個標題條和一些按鈕,包括最小化和最大化按鈕。

  在系統裏,這些窗口是相互獨立開發、各不同的應用。新聞portlet的開發者創建應用並打包成war格式的文件,隨後portal服務器的管理員在服務器上部署該war文件並創建頁面,接下來每個用戶會選擇在他的頁面裏有哪些應用。例如,如果用戶對股價不感興趣而對體育感興趣,他可以用“體育”窗口替換“股價”窗口。

  Portlet技術需要學習許多新概念,本文不可能全都涵蓋,因此本文分爲兩部分。在第一部分裏我們詳細說明portals和portlets,並開發一個簡單的“Hello World”portlet;在第二部分我們將探討一些高級主題。

  我們將用Apache的Pluto服務器(Portlet API 1.0規範的參考實現)來測試我們的示例portlets,我們還會花些時間探討如何安裝和使用Pluto服務器。

Portal頁面的元素

圖2顯示了Portal頁面的各種元素。

image
圖2 portal頁面的元素

  每個portlet頁面由一個或多個portlet窗口組成,每個portlet窗口又分爲兩部分:一個是外觀,它決定了portlet窗口的標題條、控制和邊界的樣式;另一個是portlet段,它由portlet應用填充。

  Portal服務器決定了portal頁面的整體觀感,像標識、標題條顏色、控制圖標等。通過修改幾個JSP和css模板文件就可以改變portal的整個觀感。我們將在“如何創建portal頁面”部分對此做深入討論。

Portal是什麼?

  在瞭解portlet之前有必要先了解portal。在Portlet規範裏是這樣講的:“portal是一種web應用,通常用來提供個性化、單次登錄、聚集各個信息源的內容,並作爲信息系統表現層的宿主。聚集是指將來自各個信息源的內容集成到一個web頁面裏的活動”。

  Portal的功能可以分爲三個主要方面:
1.        Portlet容器:Portlet容器與servlet容器非常類似,所有的portlet都部署在portlet容器裏,portlet容器控制portlet的生命週期併爲其提供必要的資源和環境信息。Portlet容器負責初始化和銷燬portlets,向portlets傳送用戶請求併合成響應。
2.        內容聚集:Portlet規範中規定portal的主要工作之一是聚集由各種portlet應用生成的內容,我們將在“如何創建Portal頁面”部分對此做進一步討論。
3.        公共服務:portlet服務器的一個強項是它所提供的一套公共服務。這些服務並不是portlet規範所要求的,但portal的商業實現版本提供了豐富的公共服務以有別於它們的競爭者。在大部分實現中都有望找到的幾個公共服務有:
         o 單次登錄:只需登錄portal服務器一次就可以訪問所有其它的應用,這意味着你無需再分別登錄每一個應用。例如一旦我登錄了我的intranet網站,我就能訪問mail應用、IM消息應用和其它的intranet應用,不必再分別登錄這些應用。
  Portal服務器會爲你分配一個通行證庫。你只需要在mail應用裏設定一次用戶名和密碼,這些信息將以加密的方式存儲在通行證庫中。在你已登錄到intranet網站並要訪問mail應用的時候,portal服務器會從通行證庫中讀取你的通行證替你登錄到mail服務器上。你對其它應用的訪問也將照此處理。
          o個性化:個性化服務的基本實現使用戶能從兩方面個性化她的頁面:第一,用戶可以根據她的自身喜好決定標題條的顏色和控制圖標。第二,用戶可以決定在她的頁面上有哪些portlets。例如,如果我是個體育迷,我可能會用一個能提供我鍾愛球隊最新信息的portlet來取代股票和新聞portlets。
        一些在個性化服務方面領先的商業實現版本允許你建立爲用戶顯示什麼樣的應用所依據的標準(如收入和興趣)。在這種情況下,可以設定一些像“對任何收入爲X的用戶顯示饋贈商品的portlet”和“對任何收入爲X的用戶顯示打折商品的portlet”這樣的商業規則。

        此外還有一些公共服務,比如機器翻譯,是由portal服務器將portlet生成的內容翻譯爲用戶要求的語言。大部分的商業portal服務器都支持手持設備訪問並具有針對不同的瀏覽終端生成不同內容的能力。

Portlets是什麼?

  與servlets類似,portlets是部署在容器內用來生成動態內容的web組件。從技術角度講portlet是一個實現了javax.portlet.Portlet接口的類,它被打包成war文件格式部署到portlet容器裏。

  Portlets在以下方面與servlets相似:
1.        portlets由特定的容器管理。
2.        portlets生成動態內容。
3.        portlet的生命週期由容器管理。
4.        portlets通過請求/響應模式與web客戶端交互。

  Portlets在以下方面與servlets相異:
1.        portlets只能生成標記段,而不是整個文檔。
2.        portlets沒有可供直接訪問的URL地址。不過你還是能夠讓別人通過URL訪問到portlet,你可以把包含該portlet的頁面的URL發給他。
3.        portlets不能隨意地生成內容,這是因爲portlet生成的內容最終要成爲portal頁面的一部分。如果portal服務器要求的是html/text類型,那麼所有的portlets都應生成html/text類型的內容。再比方說,如果portal服務器要求的是WML類型,那麼所有的portlets都應生成WML類型的內容。

  portlets還提供了一些附加的功能:
1.        設置參數的持久化存儲:portlets提供了一個PortletPreferences對象用來保存用戶的設置參數。這些參數被存入一個持久化數據庫,這樣服務器重啓後數據依然有效。開發者不必關心這些數據存儲的具體實現機制。
2.        請求處理:portlets提供了更爲細粒度的請求處理。對於用戶在portlet上動作時向該portlet發出的請求(一種稱爲活躍期的狀態),或者因用戶在其它portlet上動作而引發的刷新頁面請求,Portal服務器提供了兩種不同的回調方法來處理。
3.        Portlet模式:portlets用模式的概念來表示用戶在做什麼。在使用mail應用的時候,你可能會用它來讀信、寫信或檢查信件――這些都是mail應用的預定功能,Portlets通常以VIEW模式提供這些功能。但還有一些活動,像指定刷新時間或(重新)設置用戶名和密碼,這些活動允許用戶定製應用的行爲,因此它們用的是EDIT模式。Mail應用的幫助功能用的是HELP模式。

  如果仔細想想其實這裏面並沒有什麼新東西,它們反而大部分都是普通的業務需求。Portlet規範的作用在於它提供了一個抽象層,這纔是它對所有與之相關的人-最終用戶、開發者和管理員-的價值所在。

  作爲一個開發者,我會將所有與VIEW模式有關的業務邏輯放入doView()方法,將與應用配置有關的業務邏輯放入doEdit()方法,將與幫助有關的邏輯放入doHelp()方法

  這就簡化了管理員對portlet應用的訪問控制管理,因爲他只需改變portlet的訪問權限就能決定用戶能做什麼。例如,如果mail應用的一個用戶能夠在EDIT模式下設定用戶名和密碼,那麼就可以斷定他具有EDIT模式訪問權限。

  不妨考慮這樣一種情形:我是一個intranet網站的管理員,我的公司買了一個能顯示新聞信息的第三方portlet應用,該應用允許用戶指定跟蹤新聞更新的URL地址,我想借助它爲用戶顯示公司的內部新聞。另一個需求是我不想讓用戶通過該應用來跟蹤任何其它的新聞信息來源。作爲管理員,我可以爲所有的用戶指定一個用於內部新聞更新的URL地址,同時通過改變portlet應用的部署描述符來取消其它人修改該地址的權限。

  由於所有的portlet應用都具有相似的UI界面,因此採用portlets可使網站對最終用戶更具吸引力。如果她想閱讀任何一個應用的幫助信息,她可以點擊幫助按鈕;她也知道點擊編輯按鈕能讓她進入應用的配置屏。標準化的用戶界面使你的portlet應用更引人。

4.        窗口狀態:窗口狀態決定了portal頁面上留給portlet生成內容的空間。如果點擊最大化按鈕,portlet將佔據整個屏幕,成爲用戶唯一可用的portlet;而在最小化狀態,portlet只顯示爲標題條。作爲開發者應當根據可用空間的大小來定做內容。

5.        用戶信息:通常portlets向發出請求的用戶提供個性化的內容,爲了能更加行之有效,portlets需要訪問用戶的屬性信息,如姓名、email、電話等。Portlet API爲此提供了用戶屬性的概念,開發者能夠用標準的方式訪問這些屬性,並由管理員負責在這些屬性與真實的用戶信息數據庫(通常是LDAP服務器)之間建立映射關係。

  我們將在本文的第二部分深入討論這些特點-請求處理、用戶信息和portlet模式。

開發"Hello World" Portlet

  現在我們就來開發一個簡單的HelloWorld portlet。
1.        創建一個名爲HelloWorld的web項目,它與通常的servlet項目類似,有一個/WEB-INF/web.xml文件作爲項目的部署描述符。

2.        在build path里加入portlet-api-1.0.jar文件,該jar文件是Pluto發行包的一部分。

3.        在Source文件夾中按如下內容創建HelloWorld.java文件:
public class HelloWorld extends GenericPortlet{
  protected void doView(RenderRequest request,
  RenderResponse response) throws
  PortletException, IOException {
        response.setContentType("text/html");
        response.getWriter().println("Hello Portlet");
        }
}


  每個portlet都要實現Portlet接口,該接口爲portlet定義了生命週期方法。由於不想覆蓋所有這些方法,我們只對GenericPortlet類進行擴展,它是一個實現了Portlet接口的適配器類。GenericPortlet類提供了所有生命週期方法的默認實現,所以我們只需實現我們所需要的方法。

  我們在 HelloWorld portlet裏要做的只是顯示“Hello Portlet”,所以我們將覆蓋GenericPortlet類的doView()方法,該方法以PortletRequest 和 PortletResponse作爲參數。在doView()方法中首先調用response.setContentType()以通知portlet容器該portlet將要生成何種類型的內容-如果不這樣做就會導致IllegalStateException異常。一旦設置了內容的類型,就可以從response對象中獲得PrintWriter並開始寫入。

4.        每個portlet應用在/WEB-INF文件夾中都有一個portlet.xml文件,它是portlet應用的部署描述符。按以下內容創建portlet.xml文件:
<portlet>
  <description>HelloWorldDescription
        </description>
    <portlet-name>HelloWorld
        </portlet-name>
    <display-name>Hello World
        </display-name>

    <portlet-class>com.test.HelloWorld
        </portlet-class>
    <expiration-cache>-1
        </expiration-cache>
        <supports>
          <mime-type>text/html</mime-type>
      <portlet-mode>VIEW
          </portlet-mode>
        </supports>
    <supported-locale>en
        </supported-locale>

        <portlet-info>
          <title>Hello World</title>
          <short-title>Hello World
          </short-title>
          <keywords>Hello,pluto</keywords>
      </portlet-info>
</portlet>


  <portlet-name>元素聲明瞭portlet的名字,<portlet-class>元素指定了portlet的全限定類名,<expiration-cache>元素以秒爲單位指定了內容超期的時間。這裏面有一點需要注意:你在portlet上的某些動作可能會導致內容刷新,這與緩存時間無關。
  <supports>元素指定對於給定的<mime-type>有哪些模式可供支持。在示例中我們假定HelloWorld只能生成text/html類型的內容,且只有view模式可支持該內容類型。如果要增加對其它內容類型的支持,需要添加新的<support>元素並指定支持該MIME類型的模式有哪些。通常portlet對於text/html類型有VIEW、EDIT和HELP模式可供支持,而對於WML MIME類型則只有VIEW模式。
  還可以用<supported-locale>元素來指定portlet支持哪些本地化。<title>元素用來指定portlet的標題。如果要對標題做國際化處理,可以用元素<resource-bundle>指定資源(比例properties文件)的文件名。在這種情況下,容器將根據用戶所在的地區從適當的properties文件中選擇標題。

5.        每個portlet應用都是一個web應用,因此除了portlet.xml文件之外還需要有web.xml文件。
<web-app>
  <display-name>Hello World Portlet
  </display-name>
  <welcome-file-list
    <welcome-file>index.jsp
        </welcome-file>
  </welcome-file-list>
</web-app>


6.        接下來將這些文件進行編譯並打包爲war文件。你可以自己完成這些工作,或者下載帶有build.xml 的示例代碼(參見“資源”部分)來創建war文件。
在Pluto上部署HelloWorld Portlet

  Pluto尚處於開發階段的早期,因此還沒有一套易於使用的管理工具。爲了能使用Pluto服務器,需要將編譯和源代碼兩個版本都下載。需要注意的是以下說明是針對Windows平臺的,Unix用戶通過修改斜槓符號和執行sh shell腳本(不是bat批命令文件)會得到類似的結果。

1.        創建一個文件夾,比如C:/PlutoInstallation。
2.        從Pluto的網站下載pluto-1.0.1-rc1.zip和pluto-src-1.0.1-rc1.zip。
3.        將pluto-1.0.1-rc1.zip解壓到C:/PlutoInstallation.文件夾,它應被解壓到C:/PlutoInstallation/pluto-1.0.1-rc1文件夾下。
4.        執行C:/PlutoInstallation/pluto-1.0.1-rc1/bin/startup.bat啓動Pluto,現在可以通過地址http://localhost:8080/pluto/portal訪問Pluto服務器。
5.        將pluto-src-1.0.1-rc1.zip解壓到C:/PlutoInstallation/PlutoSrc文件夾。
6.        進入C:/PlutoInstallation/PlutoSrc文件夾,執行maven distribute:all.,編譯並下載運行常規管理任務所必需的相關資源文件。現在可以將HelloWorldPortlet.war作爲portlet進行安裝了。
7.        首先將HelloWorldPortlet.war文件拷貝到C:/PlutoInstallation/portlets目錄,如果沒這個目錄就創建它。
8.        將C:/PlutoInstallation/plutosrc/build.properties.sample更名爲build.properties。
9.        編輯build.properties,將maven.tomcat.home指向Pluto編譯版的安裝位置,在本例中應改爲maven.tomcat.home=C:/PlutoInstallation/pluto-1.0.1-rc1。
10.        爲了安裝portlet,進入C:/plutoInstallation/plutosrc/deploy文件夾,執行maven deploy -Ddeploy=c:/PlutoInstallation/portlets/HelloWorldPortlet.war,應能看到“build successful”信息。
11.        在C:/PlutoInstallation/pluto-1.0.1-rc1/webapps文件夾下,應該有一個HelloWorldPortlet文件夾。
12.        現在進入C:/PlutoInstallation/pluto-1.0.1-rc1/webapps/HelloWorld/WEB-INF/ folder文件夾,打開portlet的web.xml文件,你會發現裏面自動多了幾行,如下所示:
<servlet>
  <servlet-name>HelloWorld</servlet-name>
     <display-name>HelloWorld Wrapper</display-name>
      <description>Automated generated
      Portlet Wrapper</description>
      <servlet-class>org.apache.pluto.core.PortletServlet
      </servlet-class>
      <init-param>
         <param-name>portlet-class</param-name>
         <param-value>com.test.HelloWorld
         </param-value>
      </init-param>
      <init-param>
         <param-name>portlet-guid</param-name>
         <param-value>HelloPluto.HelloWorld
         </param-value>
      </init-param>
</servlet>

13.        接下來我們將該portlet加到頁面裏。進入C:/PlutoInstallation/pluto-1.0.1-rc1/webapps/pluto/WEB-INF/data文件夾,可以看到有兩個XML文件:pageregistry.xml和portletentityregistry.xml。
14.        portletentityregistry.xml包含了portlet的定義,在該文件中加入以下幾行:
 <application id="5">
   <definition-id>HelloWorld</definition-id>
     <portlet id="1">
       <definition-id>HelloWorld.HelloWorld</definition-id>
     </portlet>
</application>

  應用的<definition-id>應爲web應用所在文件夾的名字,portlet的<definition-id>應與web.xml中生成的portlet-guid相一致。
15.        pageregistry.xml定義了頁面中包含了哪些portlets,對該文件做如下改動:
  <fragment name="p2" type="portlet">
    <property name="portlet" value="5.1"/>
</fragment>

16.        執行shutdown命令和startup命令重啓Pluto服務器,返回到地址http://localhost:8080/pluto/portal並點擊“Test Link”-此時頁面中將出現我們的

HelloWorld portlet。

圖3的右側顯示了HelloWorld portlet看上去的樣子。

image
圖3 portlet的屏幕截圖

如何創建Portal頁面

圖4顯示了portal容器如何將分離的portlets組裝爲頁面。

image
圖4 創建Portal頁面

  大部分的portal服務器基本上都是部署於應用服務器上的web應用,通過servlet來處理訪問portal服務器的請求。查看一下Pluto的安裝目錄就會發現Pluto不過是一個部署於Tomcat服務器上的一個普通web應用,再看看C:/PlutoInstallation/pluto-1.0.1-rc1/webapps/pluto/WEB-INF/web.xml會發現所有發往Pluto服務器的請求都被映射到org.apache.pluto.portalImpl.Servlet上。

  在本文開始部分“Portal頁面的元素”中,我們提到portal頁面由兩部分組成。一部分是由頁面中的portlets生成的內容,另一部分是由portal服務器生成的內容。

  在Pluto裏,只要用戶發出請求,就會由servlet進行控制,根據用戶所請求的頁面來確定需要顯示的portlets的列表。一旦生成了列表,servlet就將控制轉給這些portlets線程並收集由它們生成的內容。

  對於由portal服務器生成的內容(像portal網站的觀感及每個portlet的外觀和控制之類)則取決於C:/PlutoInstallation/pluto-1.0.1-rc1/webapps/pluto/WEB-INF/aggregation文件夾下的JSP文件。RootFragment.jsp是主JSP文件,它決定了整體的觀感和對齊方式;它還包含了Heads以定義在生成的頁面中的<HEAD>標籤裏的內容。TabNavigation.jsp用來選擇在banner中該顯示什麼(默認情況下在banner顯示列表中也包擴了pluto.png圖片)。TabNavigation.jsp用來確定portal網站的導航方案。這意味着只需改動該文件夾下少量的幾個JSP文件,就能改變整個portal網站的觀感。

  Pluto根據pageregistry.xml中的設置確定頁面中有多少行,並用RowFragment.jsp去填充。ColumnFragment.jsp用來填充每個欄目。PortletFragmentHeader.jsp用來填充每個portlet的頁頭,像標題條及最大化和最小化控制。footer.jsp用來填充JSP的頁腳。如果去看一下portal頁面的HTML代碼就會發現每個portlet窗口無非都是嵌入<TD>標籤的內容塊。

結束語

  任何一種新技術要想獲得成功都應具備以下條件:首先,它能提升現有技術;其次,它能解決現有技術遇到的普遍問題;再次,它能提供多於一個的抽象層(有人說,每抽象出一層,問題就解決一半)。

  由於portlet與現有的應用服務器架構兼容,這對Portlet API來說是一次發展servlet技術的好機會。你可以從portlet裏調用EJB,或者用它啓動和參與由應用服務器控制的全局性事務。換句話說,在以商業邏輯爲核心的領域裏,portlet完全可以做得和servlet一樣好。

  Portlets提供了一個抽象層,現在你不必再擔心客戶端使用了什麼樣的HTTP方法,也不必自己編寫程序去捕獲像點擊按鈕這樣的客戶端事件。最後但絕不是最次要的一點是,portlets以提供像單次登錄、個性化等服務的方式解決了servlets不能解決的大部分問題。

資源
·本文的示例代碼
·JSR 168的首頁:http://www.jcp.org/en/jsr/detail?id=168
·Pluto的首頁:http://portals.apache.org/pluto/
·onjava.com:onjava.com
·Matrix-Java開發者社區:http://www.matrix.org.cn


Sunil Patil從事J2EE技術工作已有5年,他感興趣的領域包括對象關係映射工具、UI框架以及portals。
發佈了14 篇原創文章 · 獲贊 3 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章