本文將帶讀者瞭解如何在 IBM WebSphere Portal Version 5 中開發和部署一個基於 portlet 的簡單 JSP。
引言
在“Hello World”序列的第一篇文章中,您已經瞭解到如何在 Java 中建立一個 portlet,它能夠輸出“hello, world”。這是示範性的,並不是開發 portlet 的一種實用方法。那麼,它到底有什麼樣的問題呢?本文(第二篇文章)將來解決其中的一個問題。
在這個最簡單的“Hello World!”程式中,Java 程式碼封裝含了文本“hello, world”,也包含了顯示這個文本的邏輯。如果您能夠將 portlet 的邏輯和呈現該邏輯的部分分開,那麼程式將會做得更好,因為這樣可以讓您建立支援不同元語言和不同國家語言的 portlet。今天,您可能不需要建立一個用於無線傳輸標記語言(Wireless Markup Language,WML)的 portlet,或者不需要建立一種德語版的 portlet。但是,明天呢?
您也可能是和一名圖形設計師一塊工作,他頻繁地更改外觀和感覺。如果呈現部分是在 Java 代碼中完成的,則需要一名開發人員和一名編輯加工人員對它做修改。解決這一問題的辦法就是用 JSP 來呈現您的 portlet,它可以讓您建立獨立的 JSP 檔案,每個檔案支援一種中繼資料或一種國家語言。設計師就可以完全控制 JSP 並對它做修改,而不再需要開發人員的協助了。
在本文中,您將會看到如何在 IBM WebSphere Portal Version 5 中構建一個 portlet,它調用一個 JSP 以便在其中呈現。然後我們再介紹該 JSP 以及一些來自 portlet 標記庫的標記。最後,建立部署描述符,將所有的這些東西打成一個包,並將它部署到門戶網站中。
建立目錄結構
首先,您必須建立一個目錄結構,在其中可以儲存您的 portlet。以下內容是你在 portlet 中將會用到的:
helloWorld/com/ibm/portlets/sample
—— 存放原始碼的位置。
helloWorld/WEB-INF
—— 儲存部署描述符的位置。
helloWorld/WEB-INF/lib
——存放 JAR 檔案的位置。
helloWorld/jsp
—— 儲存 JSP 檔案的位置。
重要: 所有的目錄和環境引用都是基於 Windows 慣例的。您可以做些相應的調整,使之適用於 Unix 系統。
建立 Java 代碼
樣本目錄是您存放 Java 源檔案的位置。在該目錄中建立一個名為 HelloWorld.java
的檔案,並用您喜歡的文字編輯器開啟。下面這個類您需要將它鍵入(或者剪下和粘貼到)所建立的 HelloWorld.java
檔案中:
package com.ibm.portlets.sample; //portlet APIs import org.apache.jetspeed.portlet.*; //Java stuff import java.io.*; public class HelloWorld extends PortletAdapter { public void service(PortletRequest request, PortletResponse response) throws PortletException, IOException { // Include the view jsp getPortletConfig().getContext().include( "/jsp/view.jsp", request, response); } }
|
編譯代碼
建立源檔案之後,您就可以來編譯 Java 代碼了。您可以使用以下的指令碼,在批次檔中編譯該 portlet。首先定義一些環境變數,例如定義 Java 安裝位置的環境變數(JAVA_HOME
)。使用 WebSphere Application Server 所提供的 JDK 來編譯通常是一個很好的主意,因為這是您將要運行應用程式的環境。
您也需要設定 PATH
環境變數,使它包括 Java 編譯器的安裝位置。同時還要設定 LIBPATH
變數,使它指向 WebSphere JAR 檔案所在的目錄。
接下來,為我們的編譯類路徑設計一個名為 CP
的變數。CP
變數可以構建在一行上,但為了說明所需的不同 JAR 檔案,我們將它拆開分行顯示。然後調用 Java 編譯器對代碼進行編譯。代碼假定您是在 helloWorld
目錄下。請將目錄路徑調整為適合您安裝的路徑。
set JAVA_HOME=C:/WebSphere/AppServer/java set PATH=%JAVA_HOME%/bin set LIBPATH=C:/WebSphere/AppServer/lib set CP=. set CP=%CP%;%LIBPATH%/j2ee.jar set CP=%CP%;%LIBPATH%/dynacache.jar set CP=%CP%;C:/WebSphere/PortalServer/shared/app/portlet-api.jar javac -classpath %CP% com/ibm/portlets/sample/HelloWorld.java
|
如果由於某些原因這不能編譯,在繼續執行之前必須先修正錯誤。一些常見的錯誤是:
- 輸入錯誤——類名稱、路徑、變數名稱輸入錯誤。
- 檔案名稱錯誤——檔案名稱必須和類名稱相匹配。在我們的樣本中,檔案名稱是
HelloWorld.java
,類名稱是 HelloWorld
。如果您已經改變了一個名稱,另一個名稱也必須改變。
- 編輯器錯誤——確定編輯器確實將檔案儲存體為文本。像寫字板這樣的編輯器不會將檔案預設儲存為文本。
建立 JAR 檔案
在完成了 Java 源檔案的編譯之後,您需要在 WEB-INF/lib
目錄下建立一個 JAR 檔案。再次假定您位於 helloWorld
目錄下。這些語句可以作為您在上面建立的批次檔的一部分包含在其中。這取決於您已經將 PATH
設定為指向 jar 程式。
set JAVA_HOME=C:/WebSphere/AppServer/java set PATH=%JAVA_HOME%/bin jar -cv0f ./WEB-INF/lib/HelloWorldFromJSP.jar com/ibm/portlets/sample/*.class
|
建立 JSP 檔案
編譯完 Java 原始碼並建立了 JAR 檔案之後,您就可以專心來建立 JSP 檔案了。JSP 目錄是存放 JSP 源檔案的位置。在這個 JSP 目錄下建立一個名為 view.jsp
的檔案,並用您喜歡的文字編輯器開啟。這裡是一些 JSP 代碼,您需要將它們鍵入(或者剪下和粘貼到) view.jsp
檔案中:
Hello world from the JSP!
|
就這麼簡單。現在,您可以將這些打包並運行!在這之後,您可以再回過頭來看看這個 JSP,看看您還可以再添加什麼以便支援不同的國家語言和不同的元語言。
建立部署描述符
現在,您需要建立兩個 XML 檔案:
helloWorld/WEB-INF/web.xml
—— Web 部署描述符。
helloWorld/WEB-INF/portlet.xml
—— portlet 部署描述符。
web.xml —— Web 部署描述符
Web 部署描述符是 WebSphere Portal 所需要的。現在 Portlet 擴充了 Servlet,所以需要使用 Web 部署描述符來聲明 Servlet(Portlet)類。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app id= "HelloWorldFromJSPWebApp"> <display-name>HelloWorldFromJSPPortlet</display-name> <servlet id="Servlet_1"> <servlet-name>HelloWorldFromJSP</servlet-name> <servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class> </servlet> <servlet-mapping id="ServletMapping_1"> <servlet-name>HelloWorldFromJSP</servlet-name> <url-pattern>/HelloWorldFromJSP/*</url-pattern> </servlet-mapping> </web-app>
|
portlet.xml —— portlet 部署描述符
Portlet 部署描述符向門戶網站定義 portlet。每個 portlet 通過 portlet 元素的 href 屬性對應到 Web 部署描述符中定義的一個 Servlet 上。以粗體表示這些引用。Portlet 必須定義一個惟一的 id,每個具體的 portlet 都能引用該 id。每個具體的 portlet 利用 concrete-portlet 元素的 href 屬性的給定 id 來引用 portlet。以藍色表明這些引用。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 1.1//EN" "portlet_1.1.dtd"> <portlet-app-def> <portlet-app uid="com.ibm.portlets.sample.HelloWorldFromJSP.1" major-version="1" minor-version="0"> <portlet-app-name>HelloWorldFromJSP0Portlet</portlet-app-name> <portlet href="WEB-INF/web.xml#Servlet_1" id="Portlet_1" major-version="1" minor-version="0"> <portlet-name>HelloWorldFromJSP</portlet-name> <cache> <expires>0</expires> <shared>no</shared> </cache> <allows> <maximized/> <minimized/> </allows> <supports> <markup name="html"> <view/> </markup> </supports> </portlet> </portlet-app> <concrete-portlet-app uid="com.ibm.portlets.sample.HelloWorldFromJSP.1.2"> <portlet-app-name>Concrete HelloWorldFromJSP</portlet-app-name> <context-param> <param-name>Author</param-name> <param-value>tcat@us.ibm.com</param-value> </context-param> <concrete-portlet href="#Portlet_1"> <portlet-name>HelloWorldFromJSP</portlet-name> <default-locale>en</default-locale> <language locale="en"> <title>Hello World from JSP</title> </language> </concrete-portlet> </concrete-portlet-app> </portlet-app-def>
|
建立這些 XML 檔案時,許多地方會出錯。而只有在您試圖將 portlet 部署到門戶網站的時候這些錯誤才會被發現。這裡有一些事項需要特別注意:
- 檢查每個 XML 元素,確保它們都有一個閉元素。
- 檢查類名是否輸入錯誤,對於本例而言,檢查您給類起的名稱是否是
HelloWorldFromJSP
。
- 確保 id 和 href 屬性相匹配。
- 確保編輯器確實將檔案儲存成文本類型。
建立 WAR 檔案
最後,我們就可以建立供分發的 WAR 檔案了。我們將使用標準 jar
命令來構建 WAR 檔案。在 helloWorld
目錄下運行以下命令:
set JAVA_HOME=C:/WebSphere/AppServer/java set PATH=%JAVA_HOME%/bin jar -cf HelloWorldFromJSP.war WEB-INF jsp
|
部署 WAR 檔案
- 以門戶網站管理員的身份(
wpsadmin
)登入到門戶網站。
- 在預設主題的右上方選擇 Administration 連結。
圖 1. 管理員連結
- 在左邊選擇 Portlets 頁面,並選擇 Install portlet。
圖 2. 安裝 portlet 管理頁面
- 單擊 。
- 找到 WAR 檔案的位置,選定,然後單擊 。
圖 3. 檔案選擇對話方塊
- 單擊 。這可能要花費一些時間,請耐心等待它完成。
- 驗證 Portlet 是否為 HelloWorld。單擊 。再次等待直到安裝完成。
圖 4. Portlet 安裝驗證螢幕
- 最後,您將看到這條確認訊息: 。
如果在部署過程中碰到某類出錯資訊,通常意味著您在某個 XML 檔案中出錯了。仔細分析安裝頁面呈現給您的出錯資訊,您通常能夠從中找到出錯原因。這些資訊也會記錄在最新的記錄檔中:
%WPS_HOME%/log/wps_YYYY.MM.DD-HH.MM.SS.log
在上面也列出了 XML 檔案常見的一些錯誤。您還應該檢查下列內容:
- XML 聲明必須位於檔案的第一行(沒有空格)。
- 在正確的大小寫情況下,xml 檔案有正確的名稱。
將 portlet 添加到某一頁面中
- 在左邊選擇 Portal User Interface 頁面。
- 單擊 Manage Pages 。
圖 5. 管理頁面 portlet
- 然後選擇 My Portal 頁面。
- 單擊 。
- 為新頁面鍵入一個標題。
- 單擊 。
- 看到 以後單擊 。
- 單擊新頁面邊上的編輯頁面表徵圖 。
- 單擊 。
- 搜尋
Hello
,單擊 。
- 選中 Hello World portlet 並單擊 。
圖 6. 尋找 portlets
- 單擊 來完成頁面版面設計。
圖 7. 編輯版面設計
- 在右上方單擊 My Portal 連結,然後選擇您建立的頁面。
圖 8. 顯示我們建立的 Portal 的門戶網站
I18N 與多個中繼資料語言
I18N 是一個國際化的通用縮寫詞,這個術語指代以某種方式設計一個應用程式(您的 portlet),採用這種方式設計的應用程式可以適用於不同的語言和地區,而無需再去修改代碼。採用您當前的這種實現方法是無法支援多個國家語言或多個中繼資料語言的。使用 JSP 來呈現的 portlet 具有兩類支援方式可以支援 I18N,哪一種都可以協助您實現多個中繼資料語言。
第一類支援方式是採用多個 JSP 來呈現您的 portlet。這種支援方式允許一個 portlet 有不同的版面設計、顏色、圖片、文本,以及其他特定於所支援的語言、地區和元語言的表示方式。
您的 JSP 的目錄結構是 /jsp/view.jsp
。門戶網站將這個目錄作為搜尋一個最適合的 JSP 的一個基地。以下是設定為英語(美國)場所的 網頁瀏覽器的搜尋順序:
/jsp/html/en_US/view.jsp /jsp/html/en/view.jsp /jsp/html/view.jsp /jsp/view.jsp
|
找到的第一個 view.jsp
用於呈現 portlet。這種約定可以讓您為不同的國家語言指定不同的 JSP。例如,您可以在 /jsp/html/de/
目錄中建立一個 view.jsp
。它會讀取“Hallo Welt”(這是我想要的結果,即德語的“Hello World”)。中心思想就是說每種語言和每個地區都可以有它自己的 JSP,其中提供了專門的版面設計和 verbage。而不同的元語言呢?在上面的搜尋路徑中您可以發現指定了 /html/
。您可以按照以下的路徑為 portlet 給出 JSP:
/jsp/html/en_US/view.jsp /jsp/html/en/view.jsp /jsp/html/de/view.jsp /jsp/html/view.jsp /jsp/wml/en_US/view.jsp /jsp/wml/en/view.jsp /jsp/wml/de/view.jsp /jsp/wml/view.jsp /jsp/view.jsp
|
擁有不同的 JSP 可以讓您的 portlet 使用者通過 WML 瀏覽器訪問,並且 portlet 可以使用 /wml/
目錄結構中的 JSP 來執行搜尋。所以,這是支援 I18N 的第一個層次。
提供協助的第二個層次是採用 Java 資源綁定(resource bundles)的形式。對於您的 portlet 而言,Java 資源綁定具有這樣的能力,即可以將字串放入容易解釋、與 JSP 代碼相互獨立的特性檔案中。您可以採用同一個版面設計,但以正確的國家語言來呈現文本。為了在 WebSphere Portal V5 中做到這一點,您需要深入到 JSTL(JSP Standard Tab Library,JSP 標準標記庫)的世界中。以前,您是使用 WebSphere Portal 中附帶的 IBM portlet 標記庫從 JSP 訪問資源綁定。在 V5 中,您還是可以這樣做,只是它已經棄用了文本標記,未來的遠景是 JSTL。
用於 I18N 的 JSTL 介紹
JSTL 為 JSP 標記提供了各種各樣的功能。實際上,JSTL 是四個不同的標記庫:
- 核心標記庫 —— 它提供了一種表達語言,以及通用的控制流程程標記。例如 if 和迴圈標記。
- 格式化標記庫 —— 它提供了 I18N 特徵,例如從資源綁定、date、time 和其他格式化標記中檢索訊息。
- 資料庫訪問標記庫 —— 可以讓您直接從 JSP 訪問資料庫。
- XML 標記庫 —— 各種 XML 標記,可以讓您解析和轉換 XML 文檔。
我發現 JSTL 的資料庫和 XML 部分與 WebSphere Portal 中的其他標記庫往往衝突。舉個例子,當我將資料庫標記庫包含進一個使用 DB2 資料來源的 portlet 時,遇到了一個類衝突,這使我無法訪問我的資料庫。還有就是當我將 XML 標記庫包含進一個 portlet 時,我發現我的 JSP 不能再編譯了。
這些小問題只在 WebSphere Portal V5.0.2 中出現過。我最後才發現是由於 JSTL XML 標記庫發生衝突。所以我建議您減少 JSTL,使它只包含格式化標記庫和核心標記庫,除非您覺得您真正需要的 JAR 檔案對衝突有一個好的解決辦法。
說到 JAR 檔案,您可以從標準標記庫下載 JSTL 庫,或者從標準標記庫入門尋找您自己的鏡像網站,從中下載。本文闡述的是 Version 1.0。
當您解壓下載的標記庫時,你會發現裡面已經建立了幾個目錄。其中兩個您最感興趣的是 lib
和 tld
目錄。您需要從 lib
目錄複寫兩個 JAR 檔案到您的 WEB-INF/lib
目錄下,這兩個檔案是 jstl.jar
和 standard.jar
。所有其他的標記庫本練習並不需要用到,它們也不會妨礙您執行 portlet,如上所述。
您也需要建立 WEB-INF/tld
目錄。請將 c.tld
、c-rt.tld
、fmt.tld
和 fmt-rt.tld
從 tld
目錄複寫到您的 WEB-INF/tld
目錄。這些檔案定義了核心(c)標記庫和格式化(fmt)標記庫。現在您可能在想為什麼需要兩個不同的 tld
檔案。JSTL 有一個“孿生庫(twin libraries)”的概念,它不在本文的討論範圍內。簡要地講就是一個允許使用 JSTL 表示語言,而另一個允許使用 JSP 表示。
是的,從外頭看是 JSTL,而在後端則是兩種表達方式。您可能要開始表示不滿了,抱怨我對 JSTL 不公平,是的,我知道,我對 JSTL 有點輕描淡寫了,我也鼓勵您寫一篇關於 JSTL 的文章。您是一位文雅的讀者,您必須去瞭解讀一些比我寫得更好的資源,從中瞭解 JSTL。可以用 Google 去找,也可以去您喜歡的線上書店找。您會找到很多的資源的,但記住是 JSTL 1.0!
為了在您的 portlet 中運用 JSTL 來訪問資源綁定,您已經做了大部分的預備工作了。現在,您必須修改 web.xml
檔案來聲明您將要使用的標記庫。請注意看一下 servlet-mapping 標記後面的 taglib 標記。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> <web-app id= "HelloWorldFromJSPWebApp"> <display-name>HelloWorldFromJSPPortlet</display-name> <servlet id="Servlet_1"> <servlet-name>HelloWorldFromJSP</servlet-name> <servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class> </servlet> <servlet-mapping id="ServletMapping_1"> <servlet-name>HelloWorldFromJSP</servlet-name> <url-pattern>/HelloWorldFromJSP/*</url-pattern> </servlet-mapping> <taglib id="TagLibRev_JSTL_fmt"> <taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri> <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location> </taglib> <taglib id="TagLibRev_JSTL_fmt_rt"> <taglib-uri>http://java.sun.com/jstl/fmt_rt</taglib-uri> <taglib-location>/WEB-INF/tld/fmt-rt.tld</taglib-location> </taglib> <taglib id="TagLibRev_JSTL_core"> <taglib-uri>http://java.sun.com/jstl/core</taglib-uri> <taglib-location>/WEB-INF/tld/c.tld</taglib-location> </taglib> <taglib id="TagLibRev_JSTL_core_rt"> <taglib-uri>http://java.sun.com/jstl/core_rt</taglib-uri> <taglib-location>/WEB-INF/tld/c-rt.tld</taglib-location> </taglib></web-app>
|
您已經定義了您可能用得到的所有標記庫了。在本文中您不需要所有的都用到,但我認為把它們都做一下定義並沒有什麼壞處。此外,我在這告訴您如何定義所有的標記庫,在您的 portlet 中就不需要自己再去琢磨了!
現在進入真正的 JSP 代碼部分。為了利用 JSTL 格式化標記庫,需要在 JSP 的開頭加入以下的指示以便訪問格式化標記庫:
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
|
您可以使用類似的指示來利用核心庫。現在我們要使用格式化庫來從資源綁定中檢索訊息。
<fmt:setBundle basename="nls.labels"/><fmt:message key="helloWorldLabel"/>
|
這些代碼會試著從標籤特性檔案中擷取“helloWorldLabel”。如果沒有找到合適的特性檔案,那麼在預設情況下是呈現 opening 和 closing 文本標記之間的內容,在我們的樣本中是“Hello world from the JSP!”。在 Java 中,搜尋特性檔案與搜尋標準 ResourceBundles 採用的是同樣的方式:
<basename>_<lang>_<country>_<variant> <basename>_<lang>_<country> <basename>_<lang> <basename>
|
在這個練習中,您要建立兩個特性檔案:
/WEB-INF/classes/nls/labels_en.properties /WEB-INF/classes/nls/labels_de.properties
|
它們會有以下的內容:
/WEB-INF/classes/nls/labels_en.properties: helloWorldLabel=Hello World! /WEB-INF/classes/nls/labels_de.properties: helloWorldLabel=Hallo Welt!
|
總結一下,JSP 檔案 /jsp/view.jsp
具有以下的內容:
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %><fmt:setBundle basename="nls.labels"/><fmt:message key="helloWorldLabel"/>
|
如果在 HTML 瀏覽器中將語言設定為英語,則這個 JSP 檔案,連同兩個特性檔案會產生以下的內容:
圖 9. 英語顯示的 Hello World portlet
然後在我們的 HTML 瀏覽器中將語言設定為德語,則 portlet 會產生:
圖 10. 德語顯示的 Hello World portlet
漂亮極了!但您可能要問,如何去更新已經部署在門戶網站中的 portlet 呢?您可以直接將這個 portlet 刪除,然後再重新部署。但在真實的門戶環境中,這樣做會丟失使用者資料和部署資訊。本文的最後一節將要簡要地介紹一下如何更新一個已部署的 portlet。
更新一個已部署的 portlet
- 作為門戶管理員(
wpsadmin
)登入到門戶網站中。
- 在預設主題的右上方選擇 Administration 連結。
圖 1. 管理員連結
- 在左邊選擇 Portlets 頁面,然後單擊 Install 來安裝 portlet。
- 選擇 Manage Applications portlet。
圖 11. 管理 portlets 螢幕
- 在 Web Modules 列表框中,選擇 HelloWorldFromJSP.war 條目。
- 單擊 按鈕。
- 單擊 按鈕。
- 尋找 WAR 檔案的位置,選中它並單擊 。
- 單擊 ,這可能需要花費一些時間,請耐心等待它完成。
- 驗證 Portlet 確實為 HelloWorldFromJSP,單擊 ,然後等待安裝完成。
- 最後您會看到確認資訊 。
結束語
這就結束了。本文讓您瞭解到如何運用 JSP 來呈現您的 portlet。本文介紹如何為一個 portlet 編寫、編譯並打包 Java 代碼。首先建立部署描述符並打包 portlet 以便分發和部署;然後將 portlet 部署到您的門戶網站中;最後,重新編寫 JSP,使之國際化,並更新部署的 portlet。portlet 開發課程可以讓您一學再學。祝您好運!玩得開心!
回頁首
參考資料
- WebSphere 門戶網站產品文檔
- WebSphere 門戶網站地帶
- JSTL 規範