2012年9月26日 星期三

存貨管理系統 - MySQL (Part III)

第二個範例 (Part III)

The following examples had been tested on Mozilla's Firefox and Microsoft's IE. The document is provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

請勿轉貼
看其他教材

ZK 與資料庫的結合

在建立完 ZK 的畫面,並且安裝完資料庫之後,剩下的就是如何讓 ZK 與資料庫 來互動;基本上,這就是開始使用 ZK 的事件處理機制。在之前的 Ajax 的範例, 我們使用 Javascript 來完成這個部分,可是由於 ZK 可以與多種語言結合,而且 其預設的語言是 Java,所以我們也以 Java 來完成這項工作。 ZK 和 Java 連結使用的方式有以下三種:
  1. 直接將 Java 程式碼寫在 zul 檔案內,而這些程式碼只需要放在 <zscript> 標籤內即可,它就可以像 JSP 一樣,在載入 zul 時就可以 執行。
  2. 把 Java 的原始碼放置於另一個檔案內,然後讓 zul 檔把它引入。
  3. zul 檔可以使用已經編譯好的 Java 類別檔(即 .class 檔)。
在本範例中,我們使用了第一種和第三種方式。第三種的使用方式就像 在 Part II 中說明的 Product 類別;至於第一種的使用方式 就是 Part III 的重點。在載入 inv.zul 網頁的時候,我們希望能夠 先到資料庫中把已經存在的存貨資料載入,並放到視窗內。為了 達成這個目標,我們首先把資料載入,載入的方式如下所示, 而 <zscript> 需要放在 <window> 內。
<zscript>
  // 除了方法,其他的部分只會執行一次
  import java.sql.*;
  import java.util.*;


  Statement stmt = null;
  Connection conn = null;
  List allItems = new ArrayList();
  try {
    Class.forName("com.mysql.jdbc.Driver");
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/eric", "jlu", "newpasswd");
    stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select * from Product");

    Product p;
    while(rs.next()) {
      p = new Product();
      p.setId(rs.getInt(1));
      p.setName(rs.getString(2));
      p.setPrice(rs.getDouble(3));
      p.setQty(rs.getInt(4));
      allItems.add(p);
    }
  } catch (SQLException e) {
    e.printStackTrace();
  } finally {
    try {
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
    try {
      conn.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
</zscript>
這個程式跟 MySQL Server 簡介 中介紹的 Java 程式非常類似,因此我們只針對比較不同的地方做說明。 第一個是例外處理的部分,我們將 stmt.close();conn.close();、 以及其他資料庫連接的部分分開,如此一來可以比較容易的找出錯誤;我們建議 讀者甚至可以把"連接資料庫"所可能產生的例外分開處理,這個部分就當作 練習題了。第二個不一樣的地方在於綠色的部分,我們宣告了一個 List allItems = new ArrayList();;ArrayList 可以把它看成一個大小可以變動 的陣列,因此我們可以將任意數量的資料加入 allItems 中;除了這項方便性 之外,宣告成 List 的主要原因是要配合使用 ZK 的 forEach 指令。 經過上述程式的執行,它會將資料庫中的資料一筆一筆的放到 allItems 中, 而 allItems 中的每一筆資料都是一個 Product 的物件。 有了資料,我們需要一個機制把資料放到 <listitem> 內。為了能夠 簡易的做到這一點,ZK 提供了一個非常強的功能,也就是 <listitem> 的 forEach 屬性,其原始碼如下:
    <listitem forEach="${allItems}" value="${each}">
      <listcell label="${each.id}"/>
      <listcell label="${each.name}"/>
      <listcell label="${each.price}"/>
      <listcell label="${each.qty}"/>
    </listitem>
forEach 的用法需要特別仔細的說一下:forEach 的參數值是一個集合物件, 如 List,在本範例中就是 allItems;請注意,如果程式碼中 List 物件 的名稱改成 xxx,那麼 forEach 的屬性值也必須改成 xxx。如果直接把 forEach 定義成 forEach="allItems",ZK 處理器無法判斷屬性值可以直接 使用,還是一個變數的名稱,因此 ZK 採用跟 JSP 一樣的 EL-expression, 如果看到 ${allItems},則 ZK 會從變數 allItems 中取得其值, 並指定給 forEach。在 forEach 的每一個迴圈中,forEach 會從 List 物件 (也就是 allItems)一次取得一個物件,而在本範例中,該物件的資料型態 為 Product,而且該物件的名稱被定義為 each;因此,在每一個 <listcell> 中,我們就可以 each 的資料成員名稱 來取得 Product 物件中的資料成員。以上述程式碼為例,${each.id} 會取得 Product 物件的 id 成員;同樣的道理, ${each.name}、${each.price} 和 ${each.qty} 分別取得該物件的 name、price 和 qty 資料成員。 最後,原始碼的綠色部分在目前是可以不必定義的,該定義是指定 each 物件(也就是 Product 物件)當作是 Listitem 物件的 value 屬性值。value 屬性在之後的修改以及刪除的時候才會用到。
執行該段程式碼後,執行的畫面如下:

我想這個時候,把整個完整的 zul 碼列示出來應該有幫助,這裡也先當一個 檢查點,以便確定從安裝到現在,一切都正常的運行:
<?xml version="1.0" encoding="Big5"?>
<window title="存貨管理系統" width="640px" border="normal" mode="highlighted">
<zscript>
  // 除了方法的部分,其他的部分只會執行一次
  import java.sql.*;
  import java.util.*;


  Statement stmt = null;
  Connection conn = null;
  List allItems = new ArrayList();
  try {
    Class.forName("com.mysql.jdbc.Driver");
    conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/eric", "jlu", "newpasswd");
    stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("select * from Product");

    Product p;
    while(rs.next()) {
      p = new Product();
      p.setId(rs.getInt(1));
      p.setName(rs.getString(2));
      p.setPrice(rs.getDouble(3));
      p.setQty(rs.getInt(4));
      allItems.add(p);
    }
  } catch (SQLException e) {
    e.printStackTrace();
  } finally {
    try {
      stmt.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
    try {
      conn.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

</zscript>
  <listbox id="box" multiple="true" rows="4">
    <listhead>
      <listheader label="料號" width="50px" />
      <listheader label="品名" />
      <listheader align="right" label="價格" width="60px" />
      <listheader align="right" label="數量" width="60px" />
    </listhead>
    <listitem forEach="${allItems}" value="${each}">
      <listcell label="${each.id}"/>
      <listcell label="${each.name}"/>
      <listcell label="${each.price}"/>
      <listcell label="${each.qty}"/>
    </listitem>
  </listbox>
  <groupbox>
    <caption label="存貨管理"/>
    料號: <intbox id="num" cols="5" />
    品名: <textbox id="name" cols="25" />
    價格: <decimalbox id="price" cols="8" />
    數量: <intbox id="qty" cols="8" />
    <div>
    <button label="新增" width="46px" height="24px"/>
    <button label="修改" width="46px" height="24px"/>
    <button label="刪除" width="46px" height="24px"/>
    </div>
  </groupbox>
</window>

Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu







沒有留言:

張貼留言