Lotus Notes/Domino How To Document

主 題 如何使用 Java 代理程式及 JDBC 連結 Oracle 資料庫
發表人 Ken Chen
E-mail None

內     容

前言:

  如何讓 Notes 和關聯式資料庫 (RDBMS) 連結,一直以來都是令許多 Notes 應用系統開發人員感到頭痛的大問題。儘管 Notes 從 R5.0 開始 (甚至回溯到 R4.6x 比較後期的版本) 提供 DECS可以讓 Notes 應用系統開發人員透過簡單的設定,就可以在 Notes 應用程式上存取 RDBMS 上的資料,但是只能從 Notes 端新增資料到 RDBMS,卻無法讓 RDBMS端新增的資料反應在 Notes 端,使得 DECS 的實用價值大大的打了折扣。另一方面,儘管 LEI 確實是個很不錯的解決方案,但是高昂的售價對大部分的中小企業來說並不是可以負擔得起的。我猜 ODBC 或 ADO 應該是目前比較多人採用的方式,但是面對動輒數十台甚至數百台的用戶端 PC,安裝驅動程式和設定維護,實在教人望之卻步。因此,在這裡和大家分享這篇筆記,希望對能對大家有一點幫助。

關於 Oracle JDBC Driver:

  JDBC 是一組讓 Java 程式可以存取 RDBMS 的一組 API,在這邊我們不打算討論太多關於 JDBC API 的理論,有興趣的朋友可以參考專門討論 JDBC 的書籍。就 Notes Client 連結 Oracle database 來說,通常可以透過以下兩種方式

    • Oracle OCI driver
        Oracle OCI driver 是 Oracle 提供的原生 (Native) 驅動程式,當您需要大量使用 Store procedure 時,Oracle 建議您使用 Oracle OCI driver,以俾獲得最佳的效能。但是使用 Oracle OCI Driver 時,Client 端 PC 必須安裝 Oracle Client 程式 (註:這確實是很討厭的事情,我的 Notebook 就一直沒辦法成功的安裝 Oracle Client 程式)。
    • Oracle Thin driver
        Oracle Thin driver 也是 Oracle 提供的 Pure Java 驅動程式,適合給用戶端或是 Java applet 程式使用。使用 Oracle Thin driver的好處是,用戶端不需要任何事先的安裝或設定就可以執行 Java 應用程式去存取 Oracle database。但相較之下,執行效能會明顯的比Oracle OCI driver 差上許多。

  在這個範例當中,我們將採用 Oracle Thin driver 來連接Oracle Database,原因很簡單 — 不需要去設定那一堆你永遠搞不定的用戶端 PC。

準備工作:

  首先,您必須先取得 Oracle Thin JDBC driver,您可以到 http://otn.oracle.com/software/tech/java/sqlj_jdbc/content.html 網站下載,當然,您必須先註冊成為 Oracle 的網站會員,不過這花不了多少時間,而且註冊之後,您便可以下載所有的 Oracle軟體 (比 IBM 大方的多吧??)。請注意,我們需要的是 JDK 1.2 的版本。

  完成下載之後,請將 classes12.zip 檔案放在適合的磁碟路徑下 (例如:C:\Lotus\Notes\Data\Domino\Java ),然後我們要在 C:\Lotus\Notes\notes.ini 檔加入 J avaUserClasses=C:\Lotus\Notes\Data\Domino\Java\classes12.zip 設定,讓 Domino Designer 裡的 Java 編譯器可以找到我們需要使用的 Java Class 檔案。

  接下來就可以開始準備動手寫 Java 代理程式了,其實,Java 代理程式除了使用的指令和語法規則不一樣之外,在 Notes Class的操作的方法上幾乎和 LotusScript是完全一樣的。所以,如果您已經很熟悉 LotusScript的話,要進入 Java 代理程式的領域是輕而易舉的。在這個範例當中,我們要做的是:
    • User 在建立新文件時,輸入一個員工編號,然後透過 Java 代理程式到 Oracle 資料庫中把這員工的相關資料撈回來並且顯示在畫面上
    • 由於使用者可能會放棄這份文件的申請作業,所以,在使用者按下儲存或送出的動作之前,這份文件不能存檔
  很快的您就會發現一件美中不足的事情,就是Notes 並沒有提供前端的 Java Class,這對於習慣使用 LotusScript UI Class 的人,剛開始可能會感到小小的痛苦。以我們這次要做的範例來說,因為沒有 NotesUIDocument Class 裡的 FiledAppendText Method 可以用,所以被迫要先將 Oracle database 傳回來的資料寫到 Notes.ini 裡,然後再用另一段程式把資料寫到 UI 開啟的文件上面。當然,如果你正在操作的這份文件使已經存檔過或者是可以存檔的話,沒有 UI Class 可以用是不會有什麼問題的。

Let’ s roll:

1. 首先我們假設 Oracle database 上的相關資料如下,您的實際狀況可以問一下您的 Oracle 系統管理員。弄清楚 Oracle database 那邊的情況之後,我們就可以開始動手了。
    • Host Name:OracleDB
    • SID:Personnel
    • Username:user
    • Password:password
    • Table Name:Person
    • Filed:EmpNum, Name, Department, Title


2. 建立套表,圖一是我們需要的套表設計。
 

【圖一】
 
名稱類型 公式
EmpNum 欄位 文字,可編輯
Name 欄位 文字,寫作時計算“”
Department 欄位文字,寫作時計算 “”
Title 欄位 文字,寫作時計算“”
Retrieve Data 按鈕公式@Command([ToolsRunMacro];"(RetrieveData)");
@Command([ToolsRunMacro];"(ShowData)");
@Command([ToolsRunMacro];"(ClearTempData)")
 
3. 在資料庫上建立 RetrieveData 代理程式,代理程式的基本設定圖二。(註:我使用的是 ND6 的 Designer)
 

【圖二】
 
4. 選擇使用 Java 設計代理程式代理程式,並且按一下【編輯 Project】按鈕,我們要把 Oracle JDBC Class "包" 進來這支代理程式裡面
 


【圖三】

 
5. 如圖四,先切換到之前我們存放 classes12.zip 的磁碟目錄下,然後找到 classes12.zip 檔案,按【新增/取代檔案】按鈕,把 classes12.zip "包" 進來。這時候,左邊的列示框中顯示的檔案類型是可以透過顯示檔案類型(如標註(2))篩選過濾的,所以如果你不是勾選 "全部" 或 "備存" (註:R5 中為"壓縮"),可能會找不到這個檔案。
 


【圖四】
 
6. 把 classes12.zip 包進來之後,按【確定】按鈕,回到編寫代理程式的狀態。
 


【圖五】

 
7. RetrieveData 代理程式內容
(註7.1:為了方便解說,每行程式前面都標上 "行號",實際在撰寫的時候,請把行號拿掉)
(註7.2:為了畫面編排,這段程式碼中包含全形空白字元,切勿直接 copy-paste,請下載文末的附加檔案使用 )
 
001 import java.sql.*;
002 import lotus.domino.*;
003
004 public class RetrieveData extends AgentBase {
005
006  public void NotesMain() {
007
008   Driver drv = null;
009   PrintWriter out = null;
010
011  try
012  {
013
014   Session session = getSession();
015   AgentContext agentContext = session.getAgentContext();
016
017   Document doc = agentContext.getDocumentContext();
018   String tmpEmpNum = doc.getItemValueString("EmpNum");
019
020   // Load the Oracle JDBC driver
021   DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
022
023   // Connect to the database.. ...("jdbc:oracle:thin:@HostNameOrIPAddress:Port:SID", "UserName", "Password")
024   Connection conn = DriverManager.getConnection ("jdbc:oracle:thin:@Oracle:1521:Personnel", "Username", "Password");
025
026   // Create a Statement
027   Statement stmt = conn.createStatement ();
028
029   // Select the columns we need from the Person table
030   ResultSet rset = stmt.executeQuery ("select Name,Department,Title from Person where EmpNum ='"+tmpEmpNum+"'");
031
032   // Write the results to notes.ini which located on users' computer
033   if (rset.next ())
034   {
035    session.setEnvironmentVar("XX_System_Name", rset.getString("Name"),false);
036    session.setEnvironmentVar("XX_System_Department", rset.getString("Department"),false);
037    session.setEnvironmentVar("XX_system_Title", rset.getString("Title"),false);
038   }
039
040   // Close the ResultSet
041   rset.close();
042
043   // Close the Statement
044   stmt.close();
045
046   // Close the Connection
047   conn.close();
048  }
049  catch (Exception e)
050  {
051   System.out.println("DoSql err: " + e.getMessage());
052   e.printStackTrace();
053  }}}
 
 
8. RetrieveData 代理程式內容解說
 
001,002 是告訴 Java 編譯器,我們要使用到的 class 來自於哪些 class package
014 建立 Session 物件 (session),和 LotusScript 一樣,session通常是第一個被宣告出來的物件
015 建立 AgentContext 物件 (agentContext),getAgentContext() 會傳回代理程式在目前這個 session 中執行時的環境
017 建立 Docuement 物件 (doc),AgentContext class 的 getDocumentContext() method 會傳回代理程式啟動時在記憶體中的文件內容
018 建立 tmpEmpNum 字串,讓它等於 doc 文件上的 EmpNum item 的值,getItemVauleString() 是把 item 的值以字串格式傳回
021 載入 Oracle Thin JDBC 驅動程式
024 建立 Connection 物件 (conn) ,即是與 Oracle Database Server 的連接,記得@ 符號之後的參數要和你的實際環境配合
027 建立 Statement 物件 (stmt),Statement 物件讓你可以對 Oracle Database 要求 SQL 指令的執行
030 建立 ResultSet 物件 (rset),並要求 Oracle Database Server 傳回符合 SQL 查詢指令的所有資料,存放在 rset 中
033 使用 ResultSet class 中的 next() method 檢驗是否有資料傳回
035-037 從 rset 中取得各欄位的值(字串格式),並且把他們分別寫到 notes.ini 當中,當成 Notes Client 的環境變數
041 關閉 ResultSet 物件
044 關閉 Statement 物件
047 關閉 Connection 物件,即是切斷與 Oracle Database Server 的連接
049 意外狀況處置
051 如果有意外 (錯誤) 發生時,在 Java console 顯示錯誤訊息
052 把意外 (錯誤) 發生當時,從程式最後被執行的 method 開始回溯到第一個被執行的 method 的歷程顯示在 Java console 上

9. ShowData 代理程式
 
ShowData 代理程式的基本設定和 RetrieveData 代理程式一樣,但是用公式寫就可以了,程式碼如下
 
@If(@Environment("XX_System_Name")="";@Do(@Prompt([OK];"系統提示";"無法根據您輸入的工號找到人員資料 !");@Return(""));"");
@SetField("Name";@Environment("XX_System_Name"));
@SetField("Department";@Environment("XX_System_Department"));
@SetField("Title";@Environment("XX_System_Title"));
 
 
10. ClearTempData 代理程式
 
事實上,我們也可以把這段程式碼接著寫在 ShowData 代理程式的後面,不過,在這邊我們還是把它們獨立出來,如果有什麼需要,可以單獨呼叫這個代理程式來執行
 
@Environment( "XX_System_Name" ; "" );
@Environment( "XX_System_Department" ; "" );
@Environment( "XX_System_Title" ; "" );

評分機制尚未完成, 請稍待!