欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
開(kāi)發(fā)端到端的 Ajax 應用程序,第 2 部分: 實(shí)現 Ajax 客戶(hù)機和服務(wù)器層
Ajax(Asynchronous JavaScript + XML)正在迅速地成為時(shí)髦的技術(shù),它可以為在瀏覽器中運行的 Web 應用程序提供具有桌面質(zhì)量的軟件特性。這個(gè)分三部分的系列討論如何使用開(kāi)放源碼技術(shù)開(kāi)發(fā)端到端 Ajax 應用程序,本文是這個(gè)系列的第二篇文章。

在這個(gè)分三部分的系列的 第 1 部分 中,了解了 Firefox、Zend Core 和 MySQL 等開(kāi)放源碼技術(shù)的重要特性。我們討論了一個(gè)比較復雜的銀行場(chǎng)景,這個(gè)場(chǎng)景跨越 Ajax 應用程序的所有三層。還設置了開(kāi)發(fā)端到端 Ajax 應用程序所需的數據庫服務(wù)器、中間層服務(wù)器和基于 Eclipse 的 IDE。在本系列的第 2 部分中,將開(kāi)發(fā)銀行場(chǎng)景的一些部分。具體地說(shuō),將使用 MySQL 數據庫創(chuàng )建一個(gè)后端數據庫。我們將研究幾個(gè) MySQL 命令行工具,并使用這些工具連接數據庫、在數據庫中創(chuàng )建、定義和填充與銀行相關(guān)的數據。然后,開(kāi)發(fā)一個(gè)中間層 PHP 模塊來(lái)提供銀行的業(yè)務(wù)邏輯,這個(gè)模塊使用 ODBC 連接 MySQL 數據庫。最后,開(kāi)發(fā)一個(gè)銀行門(mén)戶(hù),用戶(hù)可以通過(guò)這個(gè)簡(jiǎn)單的瀏覽器用戶(hù)界面與這個(gè)端到端應用程序進(jìn)行交互,這個(gè)應用程序不久之后就可以在 Zend Core 上運行。

簡(jiǎn)介

請訪(fǎng)問(wèn) Ajax 技術(shù)資源中心,這是有關(guān) Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何關(guān)于 Ajax 的新信息都能在這里找到。

正如 第 1 部分 所指出的,這個(gè)銀行場(chǎng)景主要提供銀行出納員執行的基本服務(wù)。如果您還不了解這個(gè)場(chǎng)景,請閱讀 第 1 部分??蛻?hù)數據是這個(gè)場(chǎng)景的重要部分。對于本系列的場(chǎng)景,所有客戶(hù)數據將同時(shí)填充進(jìn)數據庫表中。在此之后,可以通過(guò) Zend Core 提供的 ODBC MySQL 驅動(dòng)程序獲取和更新存儲的客戶(hù)數據。處理了客戶(hù)數據之后,重點(diǎn)轉移到提供銀行出納功能所需的核心銀行邏輯。我們開(kāi)發(fā)一個(gè) PHP 代碼模塊來(lái)提供核心銀行邏輯,并使用 ODBC 進(jìn)行必要的數據庫訪(fǎng)問(wèn)。使用 Zend Core 和 PHP 實(shí)現銀行邏輯的主要優(yōu)點(diǎn)是,可以利用內置的 MySQL 支持。

在建立數據庫并開(kāi)發(fā) PHP 模塊之后,為銀行出納員提供執行四個(gè)核心功能的用戶(hù)界面。我們通過(guò)一個(gè)瘦客戶(hù)機訪(fǎng)問(wèn) PHP 模塊中封裝的核心銀行邏輯。具體地說(shuō),這個(gè)基于 Web 的瘦客戶(hù)機是按照 Ajax 風(fēng)格生成的:XHTML、Cascading Style Sheet(CSS)、JavaScript 和 XMLHttpRequest(XHR)。它為銀行出納員提供執行核心銀行功能的簡(jiǎn)單用戶(hù)界面。這個(gè)瀏覽器用戶(hù)界面還演示瀏覽器客戶(hù)機邏輯與服務(wù)器端 PHP 邏輯進(jìn)行網(wǎng)絡(luò )通信的方法。

使用 Ajax 的目的是設計出對用戶(hù)交互響應得非??斓臑g覽器應用程序。Ajax 還會(huì )減輕服務(wù)器加載頁(yè)面的沉重負載。在 Ajax 應用程序中,瀏覽器和服務(wù)器之間的交互僅僅是為了交換與應用程序相關(guān)的數據,這會(huì )優(yōu)化服務(wù)器資源的使用,讓服務(wù)器資源能夠支持更多的用戶(hù)和更多的應用程序。本系列講解一些基本的 Ajax 技術(shù),介紹構建單頁(yè)面瀏覽器應用程序所涉及的概念。

到本文結束時(shí),我們會(huì )建立數據庫、一個(gè)提供核心銀行邏輯的 PHP 模塊以及一個(gè)單頁(yè)面瀏覽器用戶(hù)界面,這些都是銀行場(chǎng)景的組成部分。

MySQL 數據庫

正如在 第 1 部分 中指出的,MySQL 是一種開(kāi)放源碼數據庫。在我們的場(chǎng)景中,使用社區服務(wù)器版本,這是一個(gè)緊湊的數據庫服務(wù)器,具有許多有用的特性。因為這個(gè)銀行場(chǎng)景的實(shí)現基于開(kāi)放源碼產(chǎn)品,所以 MySQL 和 Zend Core PHP 是合適的組合。Zend Core 本身支持 MySQL,還有各種支持 MySQL 管理和編程的工具。在我們的場(chǎng)景中,只使用 MySQL 命令行客戶(hù)機執行 MySQL 的管理。我們將用 MySQL 數據庫為這個(gè)場(chǎng)景建立銀行帳戶(hù)數據庫。

創(chuàng )建并填充銀行數據庫

在這個(gè)場(chǎng)景中,將為給定的客戶(hù)存儲以下帳戶(hù)信息:

  • AccountHolderName
  • AccountNumber
  • CheckingBalance
  • StockName
  • StockQuantity
  • StockValue

給定客戶(hù)的帳戶(hù)信息包括帳戶(hù)持有人的姓名、帳戶(hù)號、當前的資產(chǎn)余額、客戶(hù)擁有的一只股票的編號、擁有的股票總數以及股票投資組合的當前市值。下面幾節詳細介紹如何創(chuàng )建數據庫表,然后用一些虛構的銀行客戶(hù)的帳戶(hù)信息填充這個(gè)表。我們開(kāi)始吧!

按照以下步驟創(chuàng )建數據庫,然后用應用程序相關(guān)數據填充這個(gè)表:

  1. 如果 Eclipse 還未運行的話(huà),就啟動(dòng)它(c:\eclipse\eclipse.exe)。
  2. 確保在 Eclipse 中啟用了 PHP 透視圖:
    1. 選擇 Window->Open Perspective->Other->PHP 并單擊 OK。
  3. 在 Eclipse 中,選擇 File->New->Project。
  4. 選擇 General->Project 并單擊 Next。
  5. 在 project name 字段中輸入 BankDB。
  6. 單擊 Finish。
  7. 右擊 BankDB project 并選擇 New->Other。
  8. 選擇 General-> File 并單擊 Next。
  9. 在 File name 字段中,輸入 BankDB.sql 并單擊 Finish。
  10. 輸入或粘貼 清單 1 中的代碼作為 BankDB.sql 的內容。
  11. 保存并關(guān)閉這個(gè)文件。
  12. 為了啟動(dòng) MySQL 命令行客戶(hù)機,單擊 Windows Start Menu->All Programs->MySQL->MySQL Server->MySQL Command Line Client。
  13. 在 MySQL 命令行窗口中,輸入密碼 webtech 并按 Enter。
  14. 在 mysql> 提示下,輸入 source c:\eclipse\workspace\BankDB\BankDB.sql 并按 Enter。
  15. 檢查 BankDB 數據庫是否存在,以此確認前面的命令已經(jīng)正確地執行了。檢查所用的命令如下:
    1. show databases;
    2. use bankdb;
    3. show tables;
    4. describe account;
  16. 在 MySQL 命令行客戶(hù)機中,輸入 exit 關(guān)閉它。

清單 1. BankDB.sql 文件的內容
                        -- This file is part of the End-to-End Ajax development article in                        -- the IBM developerWorks. This file contains a simple DB script to                        -- create a database and populate it with the data.                        --                        -- Last Modified: May/10/2007                        --                        -- To execute the following statements in MySQL, do the following steps.                        -- 1) Start MySQL command line client.                        -- 2) Enter your MySQL admin password.                        -- 3) Type the following line by substituting <YOUR_SQL_FILE_DIR> with the                        --    directory name where the file is stored.                        --    source <YOUR_SQL_FILE_DIR>\bankdb.sql                        --                        -- Table structure for table ‘BankDB‘                        --                        DROP DATABASE BankDB;                        CREATE DATABASE BankDB;                        USE BankDB;                        CREATE TABLE account (                        AccountHolderName VARCHAR(20) NOT NULL,                        AccountNumber INTEGER NOT NULL,                        CheckingBalance DOUBLE NOT NULL,                        StockName VARCHAR(6),                        StockQuantity INTEGER,                        StockValue DOUBLE,                        PRIMARY KEY(AccountHolderName, AccountNumber)                        );                        --                        -- Populating data for table ‘a(chǎn)ccount‘                        --                        insert into ACCOUNT values (‘Frodo‘, 435245, 2344.45, ‘GOOG‘, 100, 3453.32);                        insert into ACCOUNT values (‘Sam‘, 928462, 7583.32, ‘CSCO‘, 200, 5323.43);                        insert into ACCOUNT values (‘Pippin‘, 234233, 3444.62, ‘INTC‘, 300, 4213.76);                        insert into ACCOUNT values (‘Merry‘, 642445, 1005.32, ‘MSFT‘, 250, 1353.32);                        insert into ACCOUNT values (‘Aragorn‘, 972321, 6424.24, ‘HPQ‘, 525, 12043.94);                        insert into ACCOUNT values (‘Gandalf‘, 432134, 5392.23, ‘IBM‘, 400, 10043.78);                        insert into ACCOUNT values (‘Legolas‘, 590134, 4313.82, ‘DELL‘, 325, 5926.62);                        

使用 PHP 訪(fǎng)問(wèn) MySQL 數據庫

PHP 最受人喜愛(ài)的特性之一是,它為訪(fǎng)問(wèn)不同廠(chǎng)商的數據庫中的數據提供了簡(jiǎn)單且出色的支持,包括 MySQL。它提供了一種集成業(yè)務(wù)邏輯和數據庫的簡(jiǎn)便有效的方法。在過(guò)去幾年中,PHP 社區完成了幾項改進(jìn),比如 PHP Data Objects(PDO),PDO 提供一個(gè)抽象層,無(wú)論使用哪種數據庫服務(wù)器,這個(gè)抽象層都公開(kāi)同樣的 API 函數。有兩種風(fēng)格的 PHP 數據庫 API 函數:過(guò)程式的和面向對象的。在這個(gè)場(chǎng)景中,我們使用針對 MySQL 的直接數據庫 API 來(lái)獲得一個(gè)基本的了解。PHP 提供兩種訪(fǎng)問(wèn) MySQL 的方法:

  • MySQL
  • MySQL Improved

常規的 MySQL 擴展不完全支持 MySQL 4.1.0 的所有功能。這些特性包括存儲過(guò)程、觸發(fā)器和視圖。MySQL Improved(mysqli)擴展是訪(fǎng)問(wèn)這些功能的最新方式。在 PHP 5.0 或更高版本中,可以使用 mysqli 的擴展。但是,mysqli 在默認情況下沒(méi)有啟用 —— 必須使用 Zend Core 管理工具啟用它。在這個(gè)系列的 第 1 部分 中,在安裝和配置 Zend Core 時(shí)已經(jīng)啟用了 mysqli。

PHP 數據庫 API 的出色特性之一是,它們可以將數據庫操作的結果以許多不同方式映射到 PHP 數據結構。換句話(huà)說(shuō),PHP 中的數據庫 API 可以以 PHP 關(guān)聯(lián)數組的形式返回數據庫結果,其中數據庫表的列名作為數組的鍵。在另一種情況下,它可以以 PHP 類(lèi)對象的形式返回結果,其中數據庫表的列名作為對象的屬性。因此可以以方便的方式表示數據庫查詢(xún)的結果。

構建 PHP MySQLi 函數塊

正如前面提到的,PHP 提供了許多 mysqli 函數。本節只解釋那些用來(lái)實(shí)現銀行場(chǎng)景的函數。具體地說(shuō),這里討論連接、讀、寫(xiě)和釋放連接等數據庫函數。更多細節請參考 參考資料 中列出的 PHP 官方文檔。

在執行任何數據庫操作之前,必須建立到數據庫服務(wù)器的連接。在 PHP 中,使用以下函數連接數據庫:

$link = mysqli_connect("hostname", "user", "password", "dbname");                        

這個(gè)函數嘗試用正確的憑證連接位于指定主機上的指定數據庫。這個(gè)函數還接受其他可選參數(參見(jiàn) PHP 文檔)。如果成功地連接到數據庫,這個(gè)函數會(huì )返回一個(gè)連接對象,后續的數據庫讀寫(xiě)操作需要使用這個(gè)對象。如果無(wú)法建立數據庫連接,那么這個(gè)函數返回 false。如果不希望在代碼中以明文形式直接嵌入數據庫服務(wù)器密碼,那么可以考慮使用 MySQL 的密碼摘要特性。

與連接操作對應的函數是數據庫關(guān)閉函數:

$result = mysqli_close($link);                        

這個(gè)函數嘗試關(guān)閉以前打開(kāi)的數據庫連接。它以 MySQL 數據庫連接對象作為參數;如果數據庫關(guān)閉操作成功,它就返回 true,否則返回 false。

在討論了連接管理函數之后,我們來(lái)看看數據庫讀/寫(xiě)操作涉及的函數。下面是讀/寫(xiě)操作涉及的一些函數:

  • (1) $result = mysqli_query($link, $queryStr);
  • (2) $numberOfRows = mysqli_num_rows($result);
  • (3) $row = mysqli_fetch_assoc($result);
  • (4) $row = mysqli_fetch_object($result);

函數 (1) 對數據庫執行一個(gè) SQL 查詢(xún)。它的參數是連接對象和一個(gè)有效的 SQL 查詢(xún)字符串。它在查詢(xún)成功時(shí)返回 true,在失敗時(shí)返回 false。但是,對于 SELECT SQL 查詢(xún),這個(gè)函數返回一個(gè)結果對象。

函數 (2) 計算一個(gè) SQL 查詢(xún)返回的結果集中的行數。它的參數是結果對象。

函數 (3) 以 PHP 關(guān)聯(lián)數組的形式返回結果行。這個(gè)數組以數據庫列名作為數組鍵,以數據庫字段值作為數組值。例如,如果一個(gè)數據庫查詢(xún)返回 “capital” 列的值,那么可以通過(guò)引用數組來(lái)訪(fǎng)問(wèn)結果:

$stateCapital = $row[‘capital‘];                        

函數 (4) 以 PHP 對象的形式返回結果行。這個(gè)對象以數據庫列名作為對象屬性,以數據庫字段值作為對象屬性值。例如,如果一個(gè)數據庫查詢(xún)返回 “park” 列的值,那么可以通過(guò)引用對象值來(lái)訪(fǎng)問(wèn)結果:

$nationalPark = $row->park;                        

函數 (3) 和 (4) 可以非常簡(jiǎn)便地將數據庫值映射到程序變量。正如前面提到的,PHP 還提供了執行數據庫值映射的其他方法。

在我們的場(chǎng)景中,在執行數據庫操作之后,要使用另外兩個(gè)函數進(jìn)行錯誤處理。了解數據庫操作是否成功執行是非常重要的。下面兩個(gè)函數可以方便地處理這個(gè)問(wèn)題:

  • $returnCode = mysqli_errno($link);
  • $errorMsg = mysqli_error($link);

mysqli_errno 函數返回最近的函數調用的錯誤碼。它的參數是連接對象,它返回已經(jīng)執行的函數的返回碼。返回碼為 0 就說(shuō)明沒(méi)有錯誤。mysqli_error 函數返回最近的錯誤的字符串描述。這兩個(gè)函數對于完成數據庫查詢(xún)的整個(gè)處理過(guò)程是非常重要的。

在 PHP 模塊中實(shí)現銀行業(yè)務(wù)邏輯

按照以下步驟創(chuàng )建一個(gè) PHP 模塊,并實(shí)現中間層業(yè)務(wù)邏輯:

  1. 切換到 Eclipse PHP 透視圖:?jiǎn)螕?Window->Open Perspective->Other->PHP 并單擊 OK。
  2. 單擊 File->New->PHP Project
    1. Project name 字段中,輸入 BankTeller。
    2. 單擊 Finish。
  3. Project Explorer 視圖中,右擊 BankTeller 項目并選擇 New->PHP File
    1. File Name 字段中,輸入 BankLogic.php 并單擊 Finish。
  4. 輸入或粘貼 清單 2 中的源代碼作為這個(gè)文件的內容。
    1. 單擊 File->Save 保存文件。
  5. 通過(guò)這個(gè)文件中的注釋了解代碼的作用,或者參考下一節中對代碼邏輯的解釋。

可以看出在 PHP 中執行數據庫操作是多么簡(jiǎn)便。您可能會(huì )注意到,在清單 2 中密碼是明文形式的。這個(gè)密碼只用在為本文創(chuàng )建的測試數據庫中??梢允褂妹艽a摘要替代明文,從而進(jìn)一步改進(jìn)這個(gè) PHP 模塊。


清單 2. BankLogic.php 文件的內容
                        <?php                        /*                        ============================================================                        Project: End-to-End-Ajax application development                        Purpose: This is an example scenario to be used in                        an IBM developerWorks article.                        Last modified: May/11/2007.                        This PHP module provides the core bank teller logic                        required to access the customer related data from the                        database. These functions can be called by other PHP                        modules present in the Bank scenario. All the logic                        involved in bank teller actions are divided into these                        three core functions.                        a) Get all account information                        b) Process Transaction (deposit or debit)                        c) Compute stock portfolio value                        It uses direct mysqli functions to access the database as                        opposed to the PHP PDO functions.                        ============================================================                        */                        // These globals will be used to hold the following values:                        // 1) $link is for storing the database connection object.                        // 2) $dbResult is for storing the db query result object.                        // 3) $finalResult is an associative array where the results                        //    from individual bank teller actions are packaged and                        //    returned to the caller.                        global $link, $dbResult, $finalResult;                        /*                        ============================================================                        Function: connect_to_db                        Last modified: May/11/2007.                        This function connects to the BankDB MySQL database.                        If the connection attempt is successful, it stores the                        connection object in a global scoped variable and                        returns true.                        If the connection attempt is not successful, then it                        returns false.                        ============================================================                        */                        function connect_to_db() {                        // We will use these global scoped variables here.                        global $link, $dbResult, $finalResult;                        // Initialize the variables.                        $link = null;                        $dbResult = null;                        $finalResult = null;                        // Do a mysqli connect to the local BankDB database using                        // proper credentials.                        $link = mysqli_connect("localhost", "root", "webtech", "bankdb");                        // Check if DB connection worked.                        if (mysqli_connect_errno()) {                        // It looks like there is some problem.                        // Get the MySQL error number and the error string.                        $resultMsg = "DB connection error: " . mysqli_connect_errno() .                        " [" . mysqli_connect_error() . "]";                        // Store the results in an associative array.                        // Set the result of the operation as not a successful one.                        $finalResult["ResultCode"] = 1;                        // Set the result message.                        $finalResult["ResultMsg"] = $resultMsg;                        // Return false to indicate the DB connection failure.                        return (false);                        } else {                        // DB connection is good.                        return(true);                        } // End of if (mysqli_connect_errno())                        } // End of function connect_to_db                        /*                        ============================================================                        Function: close_connection_to_db                        Last modified: May/11/2007.                        This function closes the connection made earlier to the                        BankDB database.                        ============================================================                        */                        function close_connection_to_db() {                        // We will use these globally scoped variables.                        global $link, $dbResult;                        // Close the connection if we have an active                        // DB connection object.                        if ($link != null) {                        if (($dbResult != null) && (is_object($dbResult))) {                        // If the DB result contains query data object, free it now.                        mysqli_free_result($dbResult);                        $dbResult = null;                        } // End of if ($dbResult != null)                        // Time to close the DB connection.                        mysqli_close($link);                        // Set the connection object variable to null.                        $link = null;                        } // End of if ($link != null)                        } // End of function close_connection_to_db                        /*                        ============================================================                        Function: getAllAccountInformation                        Last modified: May/11/2007.                        This function reads all the account information stored in                        the BankDB and returns them in an associative array.                        ============================================================                        */                        function getAllAccountInformation() {                        // We will use these globally scoped variables.                        global $link, $finalResult, $dbResult;                        // Get a connection to the BankDB.                        $result = connect_to_db();                        // If db connection failed, return now.                        if ($result == false) {                        return ($finalResult);                        } // End of if ($result == false)                        // Make an SQL statement to query all rows in the account table.                        $queryStr = "Select * from account";                        // Make the SQL query.                        $dbResult = mysqli_query($link, $queryStr);                        // Process if there are any query errors.                        if (mysqli_errno($link)) {                        // Close the connection first.                        close_connection_to_db();                        // Set the error message in the final result assoc. array.                        $resultMsg = "DB read error: " . mysqli_errno($link) .                        " [" . mysqli_error($link) . "]";                        // Set the application specific return code as FAILURE.                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = $resultMsg;                        // Return the final result.                        return ($finalResult);                        } // End of if (mysqli_errno($link))                        // Get the number of rows queried.                        $rowCount = mysqli_num_rows($dbResult);                        // If the database is empty, return now.                        if ($rowCount <= 0) {                        // Close the connection first.                        close_connection_to_db();                        // Set the return code and return message.                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = "No accounts were found in BankDB.";                        // Return the final result.                        return ($finalResult);                        } // End of if ($rowCount <= 0)                        // Set the counter to 0.                        $cnt = 0;                        // Create an array to hold all the fields from each row.                        $accountInfo = array();                        // From the query result set, fetch data fields from each row.                        while($row = mysqli_fetch_assoc($dbResult)) {                        // Initialize it to null.                        $data = null;                        // Create an associative array on the fly and store the                        // individual data fields read from the current database row.                        $data["AccountHolderName"] = $row["AccountHolderName"];                        $data["AccountNumber"] = $row["AccountNumber"];                        $data["CheckingBalance"] = doubleval($row["CheckingBalance"]);                        $data["StockName"] = $row["StockName"];                        $data["StockQuantity"] = intval($row["StockQuantity"]);                        $data["StockValue"] = doubleval($row["StockValue"]);                        // Now, store the entire associative array in to a regular array.                        $accountInfo[$cnt++] = $data;                        } // End of while($row = mysqli_fetch_assoc($dbResult))                        // We finished reading all the account information from the database.                        // Set the final result code as success.                        $finalResult["ResultCode"] = 0;                        // Set the final result message as success.                        $finalResult["ResultMsg"] = "ReadAllAccountsInfoFromDB successful";                        // Make the entire array holding all the account information into the                        // final result associative array.                        // $finalResult is an associative array containing an                        // regular array which in turn contains several associative arrays as                        // its elements.                        $finalResult["AccountInfo"] = $accountInfo;                        // Close the DB connection.                        close_connection_to_db();                        // Return the final result array now.                        return($finalResult);                        } // End of function getAllAccountInformation                        /*                        ============================================================                        Function: accountTransaction                        Last modified: May/11/2007.                        This function performs the bank teller account transaction.                        This function takes the account holder name, an amount and                        the transaction type as function parameter.                        The transaction type is 1 for deposit into checking account.                        The transaction type is 2 for debit from a checking account.                        After the transaction is done, it returns the snapshot of                        the account before this transaction and another snapshot of                        the account after this transaction.                        ============================================================                        */                        function accountTransaction($accountHolderName, $amount, $transactionType) {                        // We will use these globally scoped variables.                        global $link, $finalResult, $dbResult;                        // Get a database connection.                        $result = connect_to_db();                        // If the connection failed, return now.                        if ($result == false) {                        return ($finalResult);                        } // End of if ($result == false)                        // Make an SQL statement to read a particular account data for a                        // given account holder name.                        $queryStr = "Select * from account where AccountHolderName=‘$accountHolderName‘";                        // Perform the SQL query.                        $dbResult = mysqli_query($link, $queryStr);                        // Did you encounter a DB error?                        if (mysqli_errno($link)) {                        // Close the connection now.                        close_connection_to_db();                        // Set the DB error message.                        $resultMsg = "DB read error: " . mysqli_errno($link) .                        " [" . mysqli_error($link) . "]";                        // Set the application-specific result code.                        $finalResult["ResultCode"] = 1;                        // Set the result message.                        $finalResult["ResultMsg"] = $resultMsg;                        // Return the associative array with the error result.                        return ($finalResult);                        } // End of if (mysqli_errno($link))                        // How many rows were read from the DB?                        $rowCount = mysqli_num_rows($dbResult);                        // If no rows are obtained from DB, return now.                        if ($rowCount <= 0) {                        // Close the connection now.                        close_connection_to_db();                        // Setup the return value as not a successful one.                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = "No accounts were found in BankDB.";                        // Return the final result.                        return ($finalResult);                        } // End of if ($rowCount <= 0)                        // Store a record with the current checking balance.                        // Create an array to hold the pre-transaction and                        // post-transaction account snapshots.                        $accountInfo = array();                        // Fetch the query result as an associative array.                        $row = mysqli_fetch_assoc($dbResult);                        $data = null;                        // Record the filed values from the database row into                        // a new associative array.                        $data["AccountHolderName"] = $row["AccountHolderName"];                        $data["AccountNumber"] = $row["AccountNumber"];                        $data["PreviousCheckingBalance"] = doubleVal($row["CheckingBalance"]);                        $data["StockName"] = $row["StockName"];                        $data["StockQuantity"] = intval($row["StockQuantity"]);                        $data["StockValue"] = doubleVal($row["StockValue"]);                        // Store the pre-transaction account snapshot into a regular array.                        $accountInfo[0] = $data;                        // Initialize the variables.                        $newBalance = 0.0;                        // Since we are doing a transaction that changes the                        // checking balance, we need to update the DB later.                        $updateDB = true;                        if ($transactionType == 1) {                        // It is deposit.                        // Ensure that user wants to deposit an amount greater than 0.                        if ($amount > 0) {                        $newBalance = doubleval($data["PreviousCheckingBalance"]) + $amount;                        } else {                        // Deposit amount is 0. There is no need to do a database update.                        $updateDB = false;                        $newBalance = doubleval($data["PreviousCheckingBalance"]);                        } // End of if ($amount > 0)                        } else if ($transactionType == 2) {                        // It is debit.                        // Ensure that the user wants to debit an amount greater than 0 and                        // the amount is less than the money available in the checking account.                        if (($amount > 0) &&                        ($amount < doubleval($data["PreviousCheckingBalance"]))) {                        $newBalance = doubleval($data["PreviousCheckingBalance"]) - $amount;                        } else {                        // Debit amount is either 0 or it is bigger than a allowed value.                        $updateDB = false;                        $newBalance = doubleval($data["PreviousCheckingBalance"]);                        }                        } // End of if ($transactionType == 1)                        // Bank teller transaction is completed now.                        // Life is good. Send the result back.                        $finalResult["ResultCode"] = 0;                        $finalResult["ResultMsg"] = "AccountTransaction successful.";                        // If we modified the current checking balance because of a                        // deposited or debited amount, then update the database.                        if ($updateDB == true) {                        // Prepare an SQL Update statement.                        $updateStr = "update account set CheckingBalance=$newBalance " .                        "where AccountHolderName=‘$accountHolderName‘";                        // Execute the update query.                        $dbResult = mysqli_query($link, $updateStr);                        // See if there are any DB errors?                        if (mysqli_errno($link)) {                        // Close the connection to the database.                        close_connection_to_db();                        // Prepare the error message to be returned.                        $resultMsg = "DB write error: " . mysqli_errno($link) .                        " [" . mysqli_error($link) . "]";                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = $resultMsg;                        // Return the error message.                        return ($finalResult);                        }                        if ($dbResult == true) {                        // All fine.                        // Prepare to send back the result of this operation.                        $finalResult["ResultCode"] = 0;                        $finalResult["ResultMsg"] =                        "New balance for $accountHolderName has been stored in DB.";                        } else {                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] =                        "New balance for $accountHolderName could not be stored in DB.";                        // Return the final result that has an error.                        return($finalResult);                        } // End of if ($dbResult == true)                        } // End of if ($updateDB == true)                        // We already stored the pre-transaction account snapshot in an                        // array at the top of this function.                        // Store a second record that will have the updated checking balance.                        $data = null;                        $data["AccountHolderName"] = $row["AccountHolderName"];                        $data["TransactionAmount"] = $amount;                        $data["AccountNumber"] = $row["AccountNumber"];                        $data["NewCheckingBalance"] = $newBalance;                        $data["StockName"] = $row["StockName"];                        $data["StockQuantity"] = intval($row["StockQuantity"]);                        $data["StockValue"] = doubleval($row["StockValue"]);                        $accountInfo[1] = $data;                        $finalResult["AccountInfo"] = $accountInfo;                        // Close the DB connection.                        close_connection_to_db();                        // Return the final result.                        return($finalResult);                        } // End of function accountTransaction.                        /*                        ============================================================                        Function: portfolioValue                        Last modified: May/11/2007.                        This function stores the current portfolio value of a                        given account holder to the database. It takes the                        account holder name and the current stock price as input                        arguments. It reads the currently held position (in the                        Bank scenario, every account holder owns only a single                        company‘s stock. It is done to make the task simpler.)                        and computes the current market value. Then it updates                        the database with the new total stock value.                        ============================================================                        */                        function portfolioValue($accountHolderName, $stockPrice) {                        // We will use the globally scoped variables.                        global $link, $finalResult, $dbResult;                        // Connect to the MySQL BankDB database.                        $result = connect_to_db();                        // If error in connecting to the DB, return now.                        if ($result == false) {                        return ($finalResult);                        } // End of if ($result == false)                        // Prepare the query string to get account info for a given account holder.                        $queryStr = "Select * from account where AccountHolderName=‘$accountHolderName‘";                        // Execute the MySQL query.                        $dbResult = mysqli_query($link, $queryStr);                        // Are there any errors?                        if (mysqli_errno($link)) {                        // Error there. Close the db connection.                        close_connection_to_db();                        // Prepare error message to be returned.                        $resultMsg = "DB read error: " . mysqli_errno($link) .                        " [" . mysqli_error($link) . "]";                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = $resultMsg;                        // Return the error.                        return ($finalResult);                        } // End of if (mysqli_errno($link))                        // Did we read any rows from the DB?                        $rowCount = mysqli_num_rows($dbResult);                        // If there are no matching rows in DB, return now.                        if ($rowCount <= 0) {                        // Close the DB connection.                        close_connection_to_db();                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = "No accounts were found in BankDB.";                        // Return the final result.                        return ($finalResult);                        } // End of if ($rowCount <= 0)                        // Store a record with the current portfolio value.                        // Allocate an array to store the pre-transaction and the                        // post-transaction account snapshots.                        $accountInfo = array();                        // Do a database fetch to get the results as an associative array.                        $row = mysqli_fetch_assoc($dbResult);                        // Store the data fields of a row to an associative array.                        $data = null;                        $data["AccountHolderName"] = $row["AccountHolderName"];                        $data["AccountNumber"] = $row["AccountNumber"];                        $data["CheckingBalance"] = doubleval($row["CheckingBalance"]);                        $data["StockName"] = $row["StockName"];                        $data["StockQuantity"] = intval($row["StockQuantity"]);                        $data["PreviousPortfolioValue"] = doubleval($row["StockValue"]);                        // Store the associative array in a regular array.                        $accountInfo[0] = $data;                        // Calculate the portfolio value.                        $finalResult["ResultCode"] = 0;                        $finalResult["ResultMsg"] = "PortfolioValue successfully calculated.";                        $newPortfolioValue = intval($row["StockQuantity"]) * doubleval($stockPrice);                        // Since the stock portfolio value has changed, update it in DB.                        $updateStr = "update account set StockValue=$newPortfolioValue " .                        "where AccountHolderName=‘$accountHolderName‘";                        // Perform an SQL update.                        $dbResult = mysqli_query($link, $updateStr);                        // Check if there are any DB errors.                        if (mysqli_errno($link)) {                        // Close the connection to DB.                        close_connection_to_db();                        // Prepare the error message to returned.                        $resultMsg = "DB write error: " . mysqli_errno($link) .                        " [" . mysqli_error($link) . "]";                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] = $resultMsg;                        // Return the error message.                        return ($finalResult);                        } // End of if (mysqli_errno($link))                        if ($dbResult == true) {                        // All fine.                        // Prepare the success message to be returned.                        $finalResult["ResultCode"] = 0;                        $finalResult["ResultMsg"] =                        "New stock value for $accountHolderName has been stored in DB.";                        } else {                        $finalResult["ResultCode"] = 1;                        $finalResult["ResultMsg"] =                        "New stock value for $accountHolderName could not be stored in DB.";                        // Update failed. Hence return the error result.                        return($finalResult);                        } // End of else in if ($dbResult == true)                        // Store a second record that will have the updated portfolio value.                        // We have already stored the pre-transaction account snapshot in an array.                        // Let us store the post-transaction account snapshot also there.                        $data = null;                        $data["AccountHolderName"] = $row["AccountHolderName"];                        $data["AccountNumber"] = $row["AccountNumber"];                        $data["CheckingBalance"] = doubleval($row["CheckingBalance"]);                        $data["StockName"] = $row["StockName"];                        $data["CurrentStockPrice"] = doubleval($stockPrice);                        $data["StockQuantity"] = intval($row["StockQuantity"]);                        $data["NewPortfolioValue"] = $newPortfolioValue;                        // Store the associative array in a regular array.                        $accountInfo[1] = $data;                        $finalResult["AccountInfo"] = $accountInfo;                        // Close the DB connection and return the result.                        close_connection_to_db();                        return($finalResult);                        } // End of function portfolioValue.                        ?>                        

BankLogic PHP 模塊邏輯

清單 2 中的 PHP 文件包含核心銀行出納員函數所需的業(yè)務(wù)邏輯。具體地說(shuō),這些函數包括獲取數據庫中存儲的所有帳戶(hù)信息、執行存款或取款操作以及計算給定客戶(hù)的股票投資組合價(jià)值。這些函數都接受某些輸入參數,并返回一個(gè)包含相關(guān)帳戶(hù)信息的應用程序專(zhuān)有的關(guān)聯(lián)數組。這些函數中的邏輯都需要連接 BankDB MySQL 數據庫,并執行讀或更新操作。清單 2 的開(kāi)頭定義三個(gè)全局范圍的 PHP 變量。這些變量存儲數據庫連接對象 ($link)、SQL 查詢(xún)結果對象 ($dbResult) 以及要返回給這個(gè) PHP 模塊的調用者的最終結果 ($finalResult)。這個(gè) PHP 模塊用兩個(gè)實(shí)用程序函數連接 MySQL 數據庫和斷開(kāi)連接。在建立連接時(shí),創(chuàng )建一個(gè)連接對象并將它存儲在 $link 變量中,因為這是一個(gè)全局變量,所以可以在整個(gè) PHP 文件中使用它。同樣,在執行數據庫讀或更新時(shí),將一個(gè) SQL 查詢(xún)結果存儲在 $dbResult 變量中,這也是一個(gè)全局變量。當需要關(guān)閉數據庫連接時(shí),使用另一個(gè)實(shí)用程序函數 (close_connection_to_db) 斷開(kāi)數據庫連接。在關(guān)閉數據庫連接之前,這個(gè)實(shí)用程序函數確保釋放 $dbResult 中的結果集占用的內存。

這個(gè)文件中有三個(gè)核心函數:

  • 調用者通過(guò)調用 getAllAccountInformation 函數獲取數據庫中存儲的所有帳戶(hù)數據。這里的代碼使用 MySQLi 擴展 API 建立到 MySQL 數據庫的 ODBC 連接,并獲取帳戶(hù)表中存儲的所有帳戶(hù)信息。在數據庫讀操作成功之后,它循環(huán)遍歷結果集并收集帳戶(hù)數據信息。它將所有帳戶(hù)數據信息存儲在一個(gè) PHP 關(guān)聯(lián)數組中,并將這個(gè)數組返回給調用者。
  • 調用者通過(guò)調用 accountTransaction 函數執行存款或取款操作。調用這個(gè)方法時(shí)使用的參數是帳戶(hù)持有人姓名、交易數量和交易類(lèi)型(指明是存款還是取款操作)。建立到 MySQL 數據庫的 ODBC 連接,從數據庫獲取給定帳戶(hù)持有人的當前帳戶(hù)數據,并將這些信息存儲在一個(gè)關(guān)聯(lián)數組中。這是這個(gè)帳戶(hù)在交易之前的快照。然后,執行所需的操作(存款或取款)。用存款或取款操作產(chǎn)生的新的帳戶(hù)余額更新數據庫。這是交易之后的數據,也存儲在另一個(gè)關(guān)聯(lián)數組中?,F在,將交易之前和交易之后的帳戶(hù)快照存儲在一個(gè)常規數組中,并將這個(gè)數組作為最終結果返回給調用者。還要注意,只有在交易數量符合交易類(lèi)型的限制時(shí),代碼才會(huì )執行交易。
  • 調用者通過(guò)調用 portfoliovalue 方法計算給定帳戶(hù)持有人的股票投資組合價(jià)值。調用這個(gè)方法時(shí)使用的參數是帳戶(hù)持有人姓名,以及這個(gè)帳戶(hù)持有人擁有的單只股票的當前價(jià)格。這個(gè)方法獲取帳戶(hù)數據的交易前快照,并將它存儲在一個(gè)關(guān)聯(lián)數組中。然后,計算新的股票總價(jià)值,并更新 BankDB 數據庫中對應的數據庫字段。它還將帳戶(hù)數據的交易后快照存儲在另一個(gè)關(guān)聯(lián)數組中。它將兩個(gè)帳戶(hù)數據快照存儲在一個(gè)常規數組中,并將這個(gè)數組作為最終結果返回給客戶(hù)機。

源文件 中的注釋可以幫助您理解代碼邏輯。

單頁(yè)面 Ajax 用戶(hù)界面

為了提供銀行出納員用戶(hù)界面,我們要開(kāi)發(fā)一個(gè)單頁(yè)面瀏覽器應用程序。注意,單頁(yè)面瀏覽器應用程序與傳統的 “點(diǎn)擊并等待” 式 Web 應用程序不同。在 “點(diǎn)擊并等待” 式 Web 應用程序中,每當用戶(hù)到達新的頁(yè)面時(shí),瀏覽器會(huì )從服務(wù)器下載這個(gè) Web 頁(yè)面的完整內容。另一方面,單頁(yè)面瀏覽器應用程序背后的模型完全相反;在這種模型中,應用程序所需的所有表示內容(XHTML、CSS 和 JavaScript)只從服務(wù)器下載一次。這種一次性的下載通常在啟動(dòng)時(shí)進(jìn)行,也就是當用戶(hù)通過(guò)瀏覽器訪(fǎng)問(wèn)應用程序的 URL 時(shí)。XHTML 文件定義應用程序所需的所有用戶(hù)界面元素。CSS 文件提供用戶(hù)界面不同部分所需的所有樣式。特殊的 Document Object Model(DOM)技術(shù)用來(lái)隱藏和顯示用戶(hù)界面的某些部分,因此無(wú)需從服務(wù)器獲取另一個(gè)頁(yè)面,就可以模擬多頁(yè)面的效果。在瀏覽器中運行的與應用程序相關(guān)的 JavaScript 可以處理大部分應用程序邏輯。使用 Ajax 技術(shù)的目的是設計出對用戶(hù)交互響應得非??斓臑g覽器應用程序。Ajax 還會(huì )減輕服務(wù)器加載頁(yè)面的沉重負載。在 Ajax 應用程序中,瀏覽器和服務(wù)器之間的交互僅僅是為了交換與應用程序相關(guān)的數據,這會(huì )優(yōu)化服務(wù)器資源的使用,讓服務(wù)器資源能夠支持更多的用戶(hù)和更多的應用程序。

除了這里提到的好處之外,還有其他體系結構方面的考慮因素,比如數據安全性、數據私密性和業(yè)務(wù)邏輯的適當分隔,由于業(yè)務(wù)邏輯在瀏覽器客戶(hù)機上運行,在這些方面也會(huì )有好處。另外,當 HTTP 事務(wù)被中斷時(shí),需要從錯誤中恢復。這些考慮因素超出了本文的范圍,本文只希望實(shí)現一個(gè)簡(jiǎn)單的單頁(yè)面瀏覽器應用程序。同樣,可以組合使用許多 Ajax 技術(shù),為瀏覽器應用程序提供豐富的圖形效果。在本文中,我們只討論一些基本的技術(shù),介紹構建單頁(yè)面瀏覽器應用程序所涉及的概念。

在單頁(yè)面瀏覽器應用程序中,另一種用來(lái)隱藏和顯示不同部分的技術(shù)是使用 HTML 標記 <DIV>、<SPAN> 和 <TABLE>。圖 1 簡(jiǎn)要說(shuō)明了這些標記的作用。<DIV> 標記可以將 HTML 文檔分隔成單獨的部分。在分隔一個(gè)應用程序的許多屏幕時(shí),第一步是將一個(gè)屏幕中的用戶(hù)界面元素放在一個(gè) <DIV> 標記中。在此之后,通過(guò) JavaScript 控制在應用程序的某個(gè)執行階段應該顯示哪個(gè)屏幕(即 <DIV>)。另一個(gè)方便的標記是 <SPAN> 標記,可以使用這個(gè)標記對瀏覽器應用程序中的文本段應用樣式。在銀行場(chǎng)景中,使用這個(gè)標記在屏幕上創(chuàng )建菜單控件。另外,還使用 <TABLE> 標記管理文檔的布局。


圖 1. <SPAN>、<DIV> 和 <TABLE> 標記

在瀏覽器應用程序中,創(chuàng )建豐富的效果的另一種常用方法是對各個(gè)用戶(hù)界面元素應用樣式。CSS 常常用來(lái)管理瀏覽器應用程序的整體外觀(guān)。CSS 是單獨的代碼,具有它自己的語(yǔ)法。CSS 很容易設置,因為它不需要任何插件 —— 只需在文本文件中定義樣式規則即可。CSS 規則由一個(gè)選擇符和一個(gè)聲明塊組成。每個(gè)規則的開(kāi)頭是選擇符,后面是大括號。聲明塊放在大括號中,由聲明組成。聲明是屬性和值對,聲明之間由分號分隔。下面的 清單 3 給出一個(gè)簡(jiǎn)單的 CSS 規則示例。圖 2 顯示各種 CSS 選擇符。

有其他文章解釋了 CSS 選擇符的所有特性。要想全面了解 CSS 的內部工作原理,應該花些時(shí)間閱讀其他 CSS 資料。參考資料 中給出的 CSS Zen Garden 站點(diǎn)是體會(huì ) CSS 功能的好地方。

清單 3. 一個(gè)簡(jiǎn)單的 CSS 規則
                        body {                        color: maroon;                        font-size: medium;                        text-align: center;                        background:green;                        }                        


圖 2. CSS 選擇符類(lèi)型

幾個(gè) Ajax 框架為 I/O、網(wǎng)絡(luò )、圖形、數據等方面提供了代碼庫?;?Eclipse 的 Aptana 工具將許多 Ajax 框架集成在一個(gè) IDE 中。但是,對 Ajax 框架的討論超出了本文的范圍。銀行場(chǎng)景的 Ajax 相關(guān)代碼是用普通的 JavaScript 實(shí)現的,這主要是為了保持簡(jiǎn)單,并讓您能夠直接體會(huì )應用程序中的代碼,而不是通過(guò)框架庫。在學(xué)完本系列之后,您應該研究一下 Ajax 框架,比如 Dojo、Rico、Script.aculo.us 和 Prototype。

Ajax 可以在與服務(wù)器交換數據時(shí)保持用戶(hù)界面的響應性,可以避免中斷用戶(hù)的操作。

Ajax HTTP 交互

前一節討論了一些 XHTML、CSS 和 DOM 技術(shù),這些都是 Ajax 的組成部分。另外,與中間層服務(wù)器的 HTTP 交互方式也是 Ajax 應用程序的核心性質(zhì)。Ajax 使瀏覽器應用程序能夠以一種新方式與服務(wù)器進(jìn)行異步交互。與傳統的瀏覽器應用程序不同,在 Ajax 應用程序中,當用戶(hù)單擊 HTML 表單上的 Submit 按鈕時(shí),用戶(hù)不必等待頁(yè)面出現。這種異步的 HTTP 通信由 XHR 支持,XHR 是一個(gè)瀏覽器對象,它使瀏覽器端 JavaScript 代碼可以發(fā)出異步的 HTTP 服務(wù)器請求。因此,可以完全在后臺發(fā)出 HTTP 請求、接收響應并更新頁(yè)面的某些部分,這樣就不會(huì )中斷用戶(hù)的操作。Ajax 可以在與服務(wù)器交換數據時(shí)保持用戶(hù)界面的響應性。W3C 當前還在對 XHR 進(jìn)行標準化(參見(jiàn) 參考資料)。圖 3 顯示 XHR 的各個(gè)對象方法和屬性:


圖 3. XML HTTP Request(XHR)對象方法和屬性

下面是 XHR 的操作流程:

  1. 創(chuàng )建一個(gè) XMLHttpRequest 對象實(shí)例。
  2. 使用 XMLHttpRequest 對象對服務(wù)器進(jìn)行調用,采用的方法是定義一個(gè)回調函數,當收到服務(wù)器響應時(shí),會(huì )自動(dòng)執行這個(gè)函數。
  3. 在回調函數中處理服務(wù)器的響應。
  4. 如果需要,再執行第 2 步,與服務(wù)器進(jìn)行下一次異步交互。

后面將討論在銀行場(chǎng)景中使用 XHR 的實(shí)現細節。

構建 Ajax 瀏覽器應用程序的組件

我們的瀏覽器應用程序由以下部分組成:

  • XHTML 文件
  • CSS 文件
  • XHR JavaScript 文件
  • 用 JavaScript 編寫(xiě)的客戶(hù)端業(yè)務(wù)邏輯
  • 需要的實(shí)用程序 JavaScript 文件

XHTML 文件是用戶(hù)啟動(dòng)這個(gè)應用程序時(shí)瀏覽器指向的文件。這個(gè)文件包含所有用戶(hù)界面元素,這些元素是用常用的 HTML 標記構建的,比如 <DIV>、<SPAN>、<TABLE> 和 <FORM>。這個(gè)文件還使用另外幾種瀏覽器技術(shù)提供樣式、通信和數據格式支持。

CSS 文件為用戶(hù)界面元素提供樣式規則。因為 CSS 是一個(gè)大主題,在這個(gè)場(chǎng)景中不可能涉及所有 CSS 特性。但是,我將在這個(gè)應用程序的上下文中介紹一些重要的 CSS 基本特性。

XHR 文件解釋 XMLHttpRequest 對象的初始化邏輯。它還演示了如何以異步通信模式使用 XHR。我們并不重新設計 XHR 邏輯,而是按照 Web 開(kāi)發(fā)社區廣泛采用的一種方式使用 XHR。

在客戶(hù)端業(yè)務(wù)邏輯中,使用 JavaScript 建立銀行場(chǎng)景屏幕的 Ajax 操作;這里采用一個(gè)事件模型,在這個(gè)模型中客戶(hù)機與服務(wù)器的交互只是為了交換數據,而且可以異步地處理服務(wù)器響應。對于那些不熟悉 Ajax 概念的讀者,這個(gè)模塊演示了一些關(guān)鍵的概念,這些概念可以應用于任何單頁(yè)面 Ajax 瀏覽器應用程序。

另外,這個(gè)瀏覽器應用程序的組件還包括一個(gè)用于 JavaScript Object Notation(JSON)數據處理的開(kāi)放源碼實(shí)用程序。本系列的第 3 部分將詳細討論這個(gè)實(shí)用程序。

將銀行門(mén)戶(hù)實(shí)現為 Ajax 瀏覽器應用程序

我們的銀行場(chǎng)景需要一個(gè)簡(jiǎn)單的瀏覽器界面,銀行出納員使用這個(gè)界面執行 PHP 模塊中實(shí)現的核心函數。我們將使用 Aptana Web IDE 構建這個(gè)界面。Aptana Web IDE 提供了一種用 XHTML、CSS 和 JavaScript 構建瀏覽器應用程序的簡(jiǎn)便方法。Aptana 是一個(gè)免費的插件,可以無(wú)縫地插入 Eclipse 環(huán)境。這個(gè)插件仍然在開(kāi)發(fā)階段,但是目前的版本已經(jīng)能夠滿(mǎn)足銀行場(chǎng)景的需要了。盡管在銀行場(chǎng)景中將使用一般的 JavaScript 實(shí)現 Ajax 特性,但是 Aptana 集成了幾個(gè)開(kāi)放源碼 Ajax 框架庫。

按照以下步驟創(chuàng )建單頁(yè)面 Ajax 瀏覽器應用程序:

  1. 在 Eclipse 中,切換到 Aptana 透視圖:選擇 Window->Open Perspective->Other->Aptana 并單擊 OK。
  2. 在 Aptana 透視圖左下方的窗格中,選擇 Project 視圖。
  3. 右擊 BankTeller 項目并選擇 New->HTML file
    1. 在 File name 字段中,輸入 index.html 并單擊 Finish。
  4. 輸入或粘貼 清單 4 中的源代碼來(lái)替換 index.html 文件的內容,并單擊 File->Save。
  5. 右擊 BankTeller 項目并選擇 New->CSS file
    1. 在 File name 字段中,輸入 BankTeller.css 并單擊 Finish。
  6. 輸入或粘貼 清單 5 中的源代碼來(lái)替換 BankTeller.css 文件的內容,并單擊 File->Save。
  7. 右擊 BankTeller 項目并選擇 New->JavaScript file
    1. 在 File name 字段中,輸入 xhr.js 并單擊 Finish。
  8. 輸入或粘貼 清單 6 中的源代碼來(lái)替換這個(gè)文件的內容,并單擊 File->Save。
  9. 通過(guò)這些文件中的注釋了解代碼的作用,或者參考下一節中對代碼邏輯的解釋。

到目前為止,這個(gè)單頁(yè)面 Ajax 瀏覽器應用程序所需的組件已經(jīng)完成了三分之二!在本系列的第 3 部分中,將創(chuàng )建這個(gè)瀏覽器應用程序中余下的部分。


清單 4. index.html
                        <!--                        ============================================================                        Project: End-to-End-Ajax application development                        Purpose: This is an example scenario to be used in                        an IBM developerWorks article.                        Last modified: May/12/2007.                        This HTML file provides the required user-interface elements                        for the bank teller browser application. This is a                        single-page based Ajax browser application. It simply                        means that this application doesn‘t do any page fetches                        at all from the server other than the initial download                        of this single HTML file.                        This file liberally makes use of <DIV>, <SPAN> and                        <TABLE> tags to do some of the well-known Ajax tricks.                        It is a self-contained file that contains all the                        HTML markup required by the bank teller application.                        ============================================================                        -->                        <!DOCTYPE HTML PUBLIC                        "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">                        <html>                        <!--                        HTML document header describes the various properties of the document including                        its title and relationship with other documents such as CSS and JavaScript files.                        In the Bank Teller single-page application, the following documents will be used:                        1) json.js (It is an open-source JSON parser developed by Douglas Crockford.                        2) xhr.js (It is a generic utility that provides XHR related functions.                        3) BankTeller.js (All the client-side logic in this JavaScript file)                        4) BankTeller.css (All the styling needed for the browser application is here)                        -->                        <head>                        <title>Ajax Bank Teller Application</title>                        <script language"JavaScript" type="text/javascript" src="json.js"></script>                        <script language"JavaScript" type="text/javascript" src="xhr.js"></script>                        <script language"JavaScript" type="text/javascript" src="BankTeller.js"></script>                        <link rel="stylesheet" style="text/css" href="BankTeller.css" media="all" />                        </head>                        <!--                        Set an event handler to initialize the application-specific stuff.                        This event handler will be triggered during page load time.                        In this event handler, initial screen for the bank teller application will be                        set and the other screens will be hidden.                        -->                        <body onload="initOnPageLoad();">                        <!--                        This application has seven different sections that are divided                        using the <DIV> elements. Those sections are:                        1) Main section                        2) Teller Options (Menu) section                        3) Deposit section                        4) Debit section                        5) Stock portfolio section                        6) Bank teller action result section                        7) Page footer section                        All these sections will be shown selectively depending the application                        context where the user is in at a given time. This is done in the                        client side logic coded in JavaScript. This technique provides the                        dynamism and rich response to user actions. It elevates the user                        experience level drastically as compared to the traditional Web applications                        developed using the click and wait page refresh model.                        -->                        <!--                        The following the main DIV container for the entire application.                        All the other sections are children of this. They all hang on to                        this DIV container node in DOM.                        -->                        <div id="mainPage"                        title="This is an Ajax based single-page browser application.                        No browser Back button please. HTML download from server occurs ONLY ONCE.                        From then on, back-end server is contacted asynchronously ONLY                        for data exchanges.">                        <h1 title="This web application provides Bank teller services.">                        Bank Teller Operations                        </h1>                        <!--                        The tellerOptions DIV element holds the table that will provide the                        user with available teller options to select from. This container                        holds the menu choices for the entire bank teller application.                        -->                        <div id="tellerOptions" title="You can perform these teller operations.">                        <center><font color="Olive">                        <u>Click an operation below</u>                        </font></center>                        <!--                        Each menu option is a HTML text that is embedded within a                        SPAN tag. That will enable us to set the mouseover and mouseout                        events for that text element. We can combine those events with                        CSS styling to emulate a desktop-like menu behavior. When the user                        clicks on that menu, then the corresponding application logic can be                        performed.                        These different menu option are laid out inside a TABLE tag                        as individual rows.                        -->                        <table class="tellerOptionsTable" align="center">                        <tr>                        <!--                        Note that we are using class attribute in span to style                        the td value so that we can dynamically assign style classes                        (in JavaScript) as the user moves the mouse over different                        teller operation names. If we use the id attribute to                        CSS style, we can‘t dynamically assign styles in JavaScript.                        -->                        <!--                        The event handler functions are called with a                        function parameter that indicates the menu option number.                        i.e. 1, 2 or 3.                        -->                        <!-- Deposit menu option -->                        <td>                        <span id="tellerOptionsLink1" class="tellerOptionsLink"                        title="Deposit to an account."                        onmouseover="changeOptionsLinkStyleForSelection(1);"                        onmouseout="changeOptionsLinkStyleToDefault(1);"                        onclick="processTellerOperation(1);">                        1) Deposit to an account                        </span>                        </td>                        </tr>                        <tr>                        <!-- Debit menu option -->                        <td>                        <span id="tellerOptionsLink2" class="tellerOptionsLink"                        title="Debit from an account."                        onmouseover="changeOptionsLinkStyleForSelection(2);"                        onmouseout="changeOptionsLinkStyleToDefault(2);"                        onclick="processTellerOperation(2);">                        2) Debit from an account                        </span>                        </td>                        </tr>                        <tr>                        <!-- Get stock portfolio value menu option -->                        <td>                        <span id="tellerOptionsLink3" class="tellerOptionsLink"                        title="Get Stock portfolio value."                        onmouseover="changeOptionsLinkStyleForSelection(3);"                        onmouseout="changeOptionsLinkStyleToDefault(3);"                        onclick="processTellerOperation(3);">                        3) Current portfolio value                        </span>                        </td>                        </tr>                        </table>                        </div> <!-- End of <div id="tellerOptions"> -->                        <!--                        The tellerOptions DIV element holds a HTML form required for                        depositing money to an account.                        -->                        <div id="depositAction" title="Deposit to an account" class="depositAction">                        <!-- This HTML form provides the UI elements for deposit action -->                        <form name="depositActionForm">                        <span id="depositActionFormTitle" class="depositActionFormTitle">                        Deposit to an account                        </span>                        <!--                        This table provides a drop-down selection box and an                        input control to enter the deposit amount.                        -->                        <table class="depositActionTable" align="center">                        <tr>                        <td>Select Account Owner:</td>                        <td>                        <select id="depositAccountOwner" size=7                        name="depositAccountOwner">                        </select>                        </td>                        </tr>                        <tr>                        <td>Amount:</td>                        <td><input type="text" name="depositAmount"                        id="depositAmount" maxlength="15" size="15"                        title="e-g: 100"/></td>                        </tr>                        </table>                        <!--                        This table provides an action button. When pressed, it will                        trigger an onclick event handler that will perform the                        required client-side logic.                        -->                        <table align="center" class="depositAmountButtonTable">                        <tr>                        <td>                        <input id="depositAmountActionButton"                        value="Deposit" type="button"                        title="Click here to deposit to an account."                        onclick="depositAmountAction_Async();"/>                        </td>                        </tr>                        </table>                        </form>                        </div> <!-- End of <div id="depositAction"> -->                        <!--                        The tellerOptions DIV element holds a HTML form required for                        debiting money from an account.                        -->                        <div id="debitAction" title="Debit from an account" class="debitAction">                        <form name="debitActionForm">                        <span id="debitActionFormTitle" class="debitActionFormTitle">                        Debit from an account                        </span>                        <table class="debitActionTable" align="center">                        <tr>                        <td>Select Account Owner:</td>                        <td>                        <select id="debitAccountOwner" size=7                        name="debitAccountOwner">                        </select>                        </td>                        </tr>                        <tr>                        <td>Amount:</td>                        <td><input type="text" name="debitAmount" id="debitAmount"                        maxlength="15" size="15" title="e-g: 100"/></td>                        </tr>                        </table>                        <!--                        This table provides an action button. When pressed, it will                        trigger an onclick event handler that will perform the                        required client-side logic.                        -->                        <table align="center" class="debitAmountButtonTable">                        <tr>                        <td>                        <input id="debitAmountActionButton" value="Debit"                        type="button"                        title="Click here to debit from an account."                        onclick="debitAmountAction_Async();"/>                        </td>                        </tr>                        </table>                        </form>                        </div> <!-- End of <div id="depositAction"> -->                        <!--                        The portfolioOption DIV element holds the form for                        updating the current portfolio value.                        -->                        <div id="portfolioAction" title="Update portfolio value"                        class="portfolioAction">                        <form name="portfolioActionForm">                        <span id="portfolioActionFormTitle" class="portfolioActionFormTitle">                        Get portfolio value                        </span>                        <table class="portfolioActionTable" align="center">                        <tr>                        <td>Select Account Owner:</td>                        <td>                        <select id="portfolioAccountOwner" size=7                        name="portfolioAccountOwner">                        </select>                        </td>                        </tr>                        </table>                        <!--                        This table provides an action button. When pressed, it will                        trigger an onclick event handler that will perform the                        required client-side logic.                        -->                        <table align="center" class="portfolioValueButtonTable">                        <tr>                        <td>                        <input id="portfolioActionButton"                        value="Get Stock Portfolio Value" type="button"                        title="Click here to get the portfolio value."                        onclick="portfolioAction_Async();"/>                        </td>                        </tr>                        </table>                        </form>                        </div> <!-- End of <div id="portfolioAction"> -->                        <!--                        The tellerActionResult DIV element holds the form for                        getting portfolio value.                        -->                        <div id="tellerActionResult" title="Result of teller operation"                        class="tellerActionResult">                        <form name="tellerActionResultForm">                        <span id="tellerActionResultTitle" class="tellerActionResultTitle">                        Result from Teller Operation                        </span>                        <!--                        This table includes a text area that summarizes the result of                        the operation performed by the teller.                        -->                        <table class="tellerActionResultTable" align="center">                        <tr>                        <td>                        <textarea id="tellerActionResultArea" rows="15"                        cols="80" readonly></textarea>                        </td>                        </tr>                        </table>                        </form>                        </div> <!-- End of <div id="tellerActionResult"> -->                        <!--                        The pageFooter DIV element holds the footer information such as the                        currently logged in user and Go to main menu  option. This footer                        section will be stapled at the bottom of  every other section of                        this application.                        -->                        <div id="pageFooter">                        <h1></h1>                        <table id="footerTable" class="footerTable" align="center">                        <tr>                        <!--                        Note that we are using class attribute in span to style                        the td value so that we can dynamically assign style classes                        (in JavaScript) as the user moves the mouse over the footer                        options. If we use the id attribute to CSS style, we can‘t                        dynamically assign styles in JavaScript.                        -->                        <td>                        <span id="currentUserDisplay" class="currentUserDisplay"                        title="Currently logged in user‘s name.">                        Teller: John Doe                        </span>                        </td>                        <!--                        The event handler functions are called with a                        function parameter that indicates which footer option to be                        highlighted.                        -->                        <td>                        <span id="goToMainMenuLink" class="goToMainMenuLink"                        title="Click here to go to main menu."                        onmouseover="changeFooterLinkStyleForSelection(1);"                        onmouseout="changeFooterLinkStyleToDefault(1);"                        onclick="processFooterOperation(1);">                        Back to main menu                        </span>                        </td>                        </tr>                        </table>                        </div> <!-- End of <div id="PageFooter"> -->                        </div> <!-- End of <div id="mainPage"> -->                        </body>                        </html>                        


清單 5. BankTeller.css
                        /*                        ============================================================                        Project: End-to-End-Ajax application development                        Purpose: This is an example scenario to be used in                        an IBM developerWorks article.                        Last modified: May/12/2007.                        This file provides CSS rules that are used to style the                        UI controls for the bank teller browser application.                        This application doesn‘t address all the features of                        CSS. However, basic and important aspects of CSS                        are included here in the context of the bank teller                        application.                        ============================================================                        */                        /*                        This is a HTML selector that redefine the body tag with                        font and background attributes.                        */                        body {                        font-family:       Verdana, Geneva, Arial, sans-serif;                        font-size:         medium;                        text-align:        center;                        background:        rgb(220, 220, 220);                        }                        /*                        This is a HTML selector used to style the <h1> element.                        */                        h1 {                        color:             #cc6600;                        border-bottom:     medium double #888888;                        font-size:         1.7em;                        }                        /*                        This CSS ID class is applicable for the DIV element that holds the table in which                        all the available teller operations are listed.                        */                        #tellerOptions {                        margin-left:       3%;                        margin-right:      3%;                        padding-top:       10px;                        padding-bottom:    10px;                        border:            red;                        border-width:      thick;                        border-style:      double;                        border-collapse:   collapse;                        }                        /*                        This qualified dependent selector applies style to the teller option table.                        */                        table.tellerOptionsTable td {                        padding-top:       10px;                        padding-bottom:    10px;                        }                        /*                        This CSS generic class is applicable to style the margins for the                        tables in the teller actions form.                        */                        .tellerOptionsTable,                        .depositActionTable,                        .debitActionTable,                        .portfolioActionTable {                        margin-top:        30px;                        }                        /*                        This CSS generic class is applicable for the SPAN elements that hold the clickable text                        representing various teller operations. User can select an operation to perform from                        this list. Generic class is used here so that inside of JavaScript, we can dynamically                        change the style of the text representing the teller operations as the user mouseover or                        mouseout of those text regions defined within the SPAN elements.                        The following is the default style when there is no user mouse activity or when the user                        moves the mouse out.                        */                        .tellerOptionsLink {                        cursor:            pointer;                        background-color:  rgb(220, 220, 220);                        color:             blue;                        font-weight:       bold;                        font-style:        normal;                        text-decoration:   none;                        border-style:      none;                        }                        .tellerOptionsLinkSelection,                        .goToMainMenuLinkSelection {                        cursor:            pointer;                        background-color:  green;                        color:             yellow;                        font-weight:       normal;                        font-style:        italic;                        text-decoration:   none;                        border-style:      ridge;                        border-width:      7px;                        border-top-width:  7px;                        border-color:      black;                        }                        .depositAction {                        margin-left:       3%;                        margin-right:      3%;                        padding-top:       10px;                        padding-bottom:    10px;                        cursor:            default;                        border:            navy;                        border-width:      thick;                        border-style:      double;                        border-collapse:   collapse;                        }                        .debitAction {                        margin-left:       3%;                        margin-right:      3%;                        padding-top:       10px;                        padding-bottom:    10px;                        cursor:            default;                        border:            lightseagreen;                        border-width:      thick;                        border-style:      double;                        border-collapse:   collapse;                        }                        .portfolioAction {                        margin-left:       3%;                        margin-right:      3%;                        padding-top:       10px;                        padding-bottom:    10px;                        cursor:            default;                        border:            purple;                        border-width:      thick;                        border-style:      double;                        border-collapse:   collapse;                        }                        .tellerActionResult {                        margin-left:       3%;                        margin-right:      3%;                        padding-top:       10px;                        padding-bottom:    10px;                        cursor:            default;                        border:            rosybrown;                        border-width:      thick;                        border-style:      double;                        border-collapse:   collapse;                        }                        /*                        This qualified CSS generic class defines the cell padding for the buttons in the                        teller actions form and others.                        */                        table.depositAmountButtonTable td,                        table.debitAmountButtonTable td,                        table.portfolioValueButtonTable td,                        table.tellerActionResultTable td {                        padding-left:      25px;                        padding-right:     25px;                        }                        /*                        This qualified CSS generic class defines the margin for the tables holding                        the teller actions form and others.                        */                        table.depositAmountButtonTable,                        table.debitAmountButtonTable,                        table.portfolioValueButtonTable,                        table.tellerActionResultTable {                        margin-top:        40px;                        }                        .depositActionFormTitle,                        .debitActionFormTitle,                        .portfolioActionFormTitle,                        .tellerActionResultTitle {                        color:             olive;                        font-weight:       normal;                        font-style:        normal;                        text-decoration:   underline;                        text-align:        center;                        }                        /*                        This qualified CSS generic class is applicable in order to set the cellpadding for                        the table <td> where the footer options are listed.                        */                        table.footerTable td {                        padding-left:      100px;                        padding-right:     100px;                        }                        /*                        This qualified CSS generic class is applicable in order to set the margin for the                        table where the footer options are listed.                        */                        table.footerTable {                        margin-top:        20px;                        }                        /*                        This CSS generic class is applicable for the static display of the current username                        who is logged into the system.                        */                        .currentUserDisplay {                        cursor:            default;                        background-color:  rgb(220, 220, 220);                        color:             darkred;                        font-weight:       normal;                        font-style:        normal;                        }                        /*                        This CSS generic class is applicable for the SPAN elements that hold the clickable text                        representing footer options. User can select to logout from the system.                        Generic class is used here so that inside of JavaScript, we can dynamically                        change the style of the text representing the logout link as the user mouseover or                        mouseout of those text regions defined within the SPAN elements.                        The following is the default style when there is no user mouse activity or when the user                        moves the mouse out.                        */                        .gotoMainMenuLink {                        cursor:            pointer;                        background-color:  rgb(220, 220, 220);                        color:             black;                        font-weight:       bold;                        font-style:        normal;                        text-decoration:   none;                        border-style:      none;                        }                        /*                        This CSS ID class is applicable for the Teller actions button and others.                        */                        #depositAmountActionButton,                        #debitAmountActionButton,                        #portfolioActionButton {                        background-color:  saddlebrown;                        color:             white;                        border:            purple;                        border-width:      thin;                        border-style:      inset;                        font-weight:       bold;                        font-style:        normal;                        font-size:         90%                        }                        /*                        The following overrides a style defined previously in the same class.                        */                        #debitAmountActionButton {                        background-color:  midnightblue;                        }                        /*                        The following overrides a style defined previously in the same class.                        */                        #portfolioActionButton {                        background-color:  teal;                        }                        


清單 6. xhr.js
                        /*                        ============================================================                        Project: End-to-End-Ajax application development                        Purpose: This is an example scenario to be used in                        an IBM developerWorks article.                        Last modified: May/12/2007.                        This JavaScript file provides specific functions related to                        XHR (XML HTTP Request). The logic explained here is a                        generic one which is being used hundreds of other                        Web applications. This logic can be found in any                        Ajax related book or article that describes the inner                        workings of XHR.                        ============================================================                        */                        /*                        ============================================================                        Function: createRequest                        Last Modified: May/12/2007                        This function creates an XHR object that is browser                        agnostic. As of this writing, XHR is somewhat browser                        dependent. We can divide XHR support in two major classes                        of browsers i.e. Internet Explorer and non-IE browsers.                        Then, within IE, there are different implementations of                        XHR in pre-IE6 and the rest. In summary, Microsoft                        supports XHR through its ActiveX. After listening to                        complaints from the Web developer community, Microsoft                        realized the need to expose XHR as a native browser                        object as done in other browsers. The rumor is that                        we will soon see XHR support in IE browsers via                        XMLHttpRequest object. Until then, we have to take care of                        browser dependency as shown in this function.                        ============================================================                        */                        function createRequest() {                        // Define a local variable and set it to null.                        var request = null;                        // Try different things to see which browser is being used.                        try {                        // Non Microsoft browsers (Firefox, Safari etc.)                        request = new XMLHttpRequest();                        } catch(trymicrosoft) {                        try {                        // IE6 and above.                        request = new ActiveXObject("Msxml2.XMLHTTP");                        } catch(othermicrosoft) {                        try {                        // Older versions of IE i.e. pre-IE6.                        request = new ActiveXObject("Microsoft.XMLHTTP");                        } catch(failed) {                        // No support for XHR                        request = null;                        } // End of catch(failed)                        } // End of catch(othermicrosoft)                        } // End of catch(trymicrosoft)                        // Check if we have a valid XHR object.                        if (request == null) {                        alert("Error creating the XMLHttpRequest object!");                        } else {                        // Return the valid XHR object that was created.                        return(request);                        } // End of if (request == null)                        } // End of function createRequest.                        /*                        ============================================================                        Function: sendHttpRequest                        Last Modified: May/12/2007                        This function transmits any arbitrary data to a server URL.                        It takes four arguments:                        1) XHR object                        2) Callback function (if any) to receive the server response                        3) URL to which the content is to be sent.                        4) Data to be sent.                        The depending on the input parameters, it will either                        communicate with the server asynchronously or                        synchronously to do the data interchange. It uses the POST                        verb of HTTP to do the REST-style call.                        ============================================================                        */                        function sendHttpRequest(request, callbackFunction, url, postData) {                        // Initialize a local variable to false.                        // This variable indicates if we need to communicate with the                        // server in an asynchronous mode.                        var async_request = false;                        // Did the caller give us a Callback function?                        if (callbackFunction != null) {                        // We have a callback function.                        // Set that function to XHR object‘s onreadystatechange property.                        request.onreadystatechange = callbackFunction;                        // Set the local variable to indicate that                        // we need to send and receive the response in a non-blocking mode                        // i.e. Async.                        async_request = true;                        }                        //  Open a HTTP connection to the provided URL.                        request.open("POST", url, async_request);                        // Set a HTTP request header.                        request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");                        // Send it now.                        // If async mode was not true, then this call will block until a                        // HTTP response is received from the server.                        // Otherwise, this statement will just send and return without waiting for a                        // server response.                        var response = request.send(postData);                        if (async_request == false) {                        // We sent the request synchronously.                        // Hence, return the response received from the server.                        return(response);                        } else {                        // If the request was made asynchronously, we need not bother to return                        // anything meaningful. The response will be sent directly to the                        // callback function that was provided by the caller.                        return(true);                        }                        } // End of function sendHttpRequest.                        

銀行門(mén)戶(hù)瀏覽器應用程序中的邏輯

我們已經(jīng)創(chuàng )建了 XHTML 和 CSS 文件,以及與 XHR 相關(guān)的實(shí)用程序文件。XHTML 文件(index.html)是這個(gè)應用程序的起點(diǎn)。這是銀行出納員應用程序的用戶(hù)在瀏覽器的地址欄中能夠看到的惟一文件。其他所有文件都從服務(wù)器下載到 index.html 文件的瀏覽器會(huì )話(huà)。如果看一下 index.html 文件的 <HEAD> 部分,可以看到下面的 HTML 標記:

<script language="JavaScript" type="text/javascript" src="xyz.js"></script>                        

script 標記定義一個(gè)或多個(gè)腳本,文檔中的元素可以調用這些腳本。在這個(gè)示例中,它從外部文件加載 JavaScript 代碼。銀行出納員應用程序的 JavaScript 代碼是從三個(gè)不同的 JavaScript 文件加載的。

<link rel="stylesheet" type="text/css" href="xyz.css" media="all" />                        

link 標記鏈接一個(gè)外部文件中定義的樣式表(CSS)規則。這個(gè)標記將指定的 CSS 文件鏈接進(jìn) HTML 文檔,因此影響整個(gè) Web 應用程序的樣式。

與銀行出納員應用程序的表示相關(guān)聯(lián)的所有組件只在啟動(dòng)時(shí)下載一次。這意味著(zhù)需要將應用程序中的各個(gè)屏幕分隔開(kāi),這樣才能根據需要向用戶(hù)顯示不同的屏幕。這很容易實(shí)現,只需將一個(gè)屏幕的所有用戶(hù)界面控件包含在一個(gè)單獨的 <DIV> 元素中。整個(gè)應用程序放在一個(gè)稱(chēng)為 mainPage 的 <DIV> 元素中。這個(gè)瀏覽器應用程序中有另外六個(gè)部分,它們都放在自己的 <DIV> 元素中。這六個(gè) <DIV> 元素嵌套在 mainPage <DIV> 元素中。通過(guò)以這種方式組織這些用戶(hù)界面部分,就更容易通過(guò) DOM 控制它們,本系列的第 3 部分將解釋 DOM 操作。

當加載這個(gè)應用程序時(shí),在 <body> 元素中設置一個(gè)事件處理函數(initOnPageLoad)。在剛啟動(dòng)時(shí)調用這個(gè)事件處理函數,將初始屏幕內容設置為可見(jiàn)。與 <DIV> 標記相似,<SPAN> 標記也用來(lái)劃分文檔;在這個(gè)示例中,將文本包含在 <SPAN> 標記中,從而在初始屏幕上建立菜單式的結構。注意,這些 <SPAN> 元素上設置了與鼠標操作相關(guān)的三個(gè)事件處理函數。這些事件處理函數僅僅使用 CSS 樣式規則改變菜單項的顯示方式。當單擊這些菜單文本項時(shí),對應的 onclick 事件處理函數讓對應的屏幕出現在瀏覽器窗口中。這些操作都不需要訪(fǎng)問(wèn)服務(wù)器,只需在本地操作瀏覽器 DOM。另一個(gè)有意思的用戶(hù)界面控件是頁(yè)腳部分,這個(gè)部分出現在每個(gè)屏幕的底部。在任何時(shí)候,屏幕布局都包含 mainPagepageFooter <DIV> 元素。其他部分(存款、取款、投資組合或銀行出納員操作結果)之一放在這兩個(gè) <DIV> 元素之間 —— 這是另一個(gè)靈活的 Ajax 設計原則。

CSS 文件(BankTeller.css)包含應用于這個(gè)瀏覽器應用程序的用戶(hù)界面元素的 CSS 規則。這些 CSS 規則演示了 CSS 的幾個(gè)特性。尤其是,這個(gè)應用程序中大量使用了 HTML 選擇符、ID 選擇符和類(lèi)選擇符。

例如,在 CSS 文件的頂部,body HTML 選擇符重新定義整個(gè)瀏覽器應用程序頁(yè)面的字體和背景顏色。在 CSS 文件的底部,使用了 portfolioActionButton,這是一個(gè) ID 選擇符。這意味著(zhù),HTML 文件(index.html)中帶有這個(gè) ID 字符串的 HTML 標記將采用 #portfolioActionButton CSS 規則下定義的樣式。在 .tellerOptionsLink CSS 規則中使用了類(lèi)選擇符,所以其中的樣式應用于分配了 tellerOptionsLink 類(lèi)的所有 HTML 標記。還要注意組選擇符,也就是兩個(gè)或更多的選擇符組合在一起,使用相同的樣式聲明。BankTeller.css 文件中的許多地方使用了組選擇符。在這個(gè) CSS 文件的底部,可以看到三個(gè)操作按鈕的 ID 組合在一起(#depositAmountActionButton、#debitAmountActionButton 和 #portfolioActionButton),因此它們采用相同的按鈕樣式屬性。這里還演示了另一個(gè)高級的 CSS 特性,后代選擇符(descendant selector)。通過(guò)使用后代選擇符,可以根據父元素對后代元素應用樣式。例如,對一個(gè)表格中的所有列應用相同的單元格填充(padding)。在這個(gè) CSS 文件中搜索 table.depositAmountButtonTable td,就會(huì )看到后代選擇符的使用方法??梢詤⒖?圖 2,了解 HTML、ID 和類(lèi)選擇符的 CSS 語(yǔ)法。

XHR 文件(xhr.js)包含兩個(gè)函數。一個(gè)函數創(chuàng )建一個(gè) XHR 對象,可以使用這個(gè)對象與中間層服務(wù)交換(發(fā)送和接收)應用程序信息。createRequest 函數準備一個(gè) XHR 對象。到編寫(xiě)本文時(shí),不同的瀏覽器仍然以不同的方式支持 XMLHttpRequest。特別是,兩種最流行的瀏覽器 —— Internet Explorer(IE)和 Mozilla Firefox —— 支持 XHR 的方式是不一致的。

在 IE 的不同版本中,以不同方式實(shí)現 XHR。這個(gè)函數會(huì )嘗試使用瀏覽器特有的技術(shù)創(chuàng )建一個(gè) XHR 對象。在非 IE 瀏覽器中,只需對內置的 XMLHttpRequest 類(lèi)進(jìn)行實(shí)例化,就可以創(chuàng )建 XHR 對象。在 IE 6.0 和更高版本中,使用 ActiveXObject 和 Msxml2 中的 XMLHTTP。在其他所有 IE 版本中,使用 ActiveXObjectXMLHTTP 的不同實(shí)例。Microsoft 正在開(kāi)發(fā)與其他瀏覽器相似的 XHR 支持。在 Microsoft 完成這項工作之前,仍然需要使用這個(gè)函數中的邏輯。另一個(gè)函數 sendHttpRequest 用來(lái)向中間層服務(wù)發(fā)送任意數據。它按照 REST 風(fēng)格的訪(fǎng)問(wèn)機制使用 POST HTTP 方法與中間層服務(wù)進(jìn)行交互。這個(gè)函數接受以下四個(gè)參數:

  • XHR 對象
  • 回調函數(如果不需要回調,就是 null)
  • 數據需要發(fā)送到的目標 URL
  • 數據(發(fā)送給中間層服務(wù)的應用程序數據)

sendHttpRequest 方法使用 XHR 對象將數據發(fā)送給中間層服務(wù)。如果提供了回調,那么這個(gè)函數將 XHR 對象的 onreadystatechange 屬性設置為這個(gè)回調函數。然后,它打開(kāi)一個(gè)到中間層服務(wù)的 HTTP 連接。它設置所需的 HTTP 頭,然后將數據發(fā)送給中間層服務(wù)。如果提供了回調函數,那么 XHR 對象的 send 方法立即返回,并不等待服務(wù)器響應。在這種情況下,當服務(wù)器響應到達瀏覽器時(shí),回調函數會(huì )處理服務(wù)器響應。第 3 部分將討論這個(gè)過(guò)程的細節。如果沒(méi)有提供回調函數,那么 send 函數阻塞,一直等到服務(wù)器響應到達,或者引發(fā) HTTP 錯誤。

清單 4 中的單頁(yè)面瀏覽器應用程序代碼生成一個(gè)簡(jiǎn)單的瀏覽器界面,銀行出納員使用這個(gè)界面執行銀行操作,比如存款、取款和計算投資組合的價(jià)值。代碼提供三個(gè)表單。這三個(gè)表單都提供一個(gè) HTML 下拉框,這個(gè)框中填充帳戶(hù)持有人的姓名。然后,提供一個(gè)編輯框,用戶(hù)可以在其中輸入存款或取款的數量。銀行出納員可以使用三個(gè)操作按鈕執行所需的銀行函數。這個(gè)應用程序中的三個(gè)按鈕訪(fǎng)問(wèn)一個(gè)中間層 REST 服務(wù),我們將在第 3 部分中開(kāi)發(fā)這個(gè)服務(wù)。在開(kāi)發(fā)這個(gè) PHP 模塊之前,這些銀行出納員函數無(wú)法發(fā)揮作用。另外,在第 3 部分中還要開(kāi)發(fā) JavaScript 文件(BankTeller.js)。

在開(kāi)發(fā)這個(gè)銀行場(chǎng)景時(shí),使用了許多新的 Ajax 技術(shù)。如果您是剛入門(mén)的 Web 開(kāi)發(fā)人員,可能不熟悉這里討論的一些領(lǐng)域。您應該全面地分析這些不完整的瀏覽器代碼和中間層代碼,從而充分地理解它們。如果您是有經(jīng)驗的 Web 開(kāi)發(fā)人員,可以嘗試自己完成余下的任務(wù)。如果您無(wú)法完成余下的任務(wù),也不用擔心 —— 本系列的第 3 部分將幫助您完成這些任務(wù)。

結束語(yǔ)

到目前為止,我們已經(jīng)構建了銀行場(chǎng)景的主要部分。盡管我們只討論了端到端 Ajax 應用程序場(chǎng)景的一部分,但是也學(xué)到了不少東西,包括數據庫、PHP 模塊中的核心業(yè)務(wù)邏輯以及用 Ajax 技術(shù)構建的 Web 用戶(hù)界面??纯?第 1 部分 中的銀行場(chǎng)景圖就會(huì )發(fā)現,還需要完成以下任務(wù)才能完成整個(gè)場(chǎng)景:

  • 開(kāi)發(fā)一個(gè) JavaScript 模塊,它包含客戶(hù)端邏輯以及與服務(wù)器進(jìn)行數據交換的異步通信邏輯。
  • 開(kāi)發(fā)一個(gè) PHP 模塊,它包含一個(gè)遠程股票報價(jià) Web 服務(wù)的 SOAP 客戶(hù)機代碼。
  • 開(kāi)發(fā)一個(gè) PHP 模塊,它作為 REST 服務(wù),將調用轉發(fā)給其他 PHP 模塊中的業(yè)務(wù)邏輯。
  • 將所有組件集成起來(lái)。
  • 部署和測試這個(gè)端到端 Ajax-PHP 場(chǎng)景。
  • 使用客戶(hù)端和服務(wù)器端調試器進(jìn)行調試。

學(xué)習了 第 1 部分 和第 2 部分中的內容之后,您現在應該已經(jīng)體會(huì )了在三個(gè)應用程序層上開(kāi)放源碼技術(shù)提供的強大功能,還了解了 Eclipse Ajax-PHP 開(kāi)發(fā)工具的作用。本文提供的 下載文件 包含創(chuàng )建數據庫的 SQL 代碼、用 PHP 編寫(xiě)的服務(wù)器端銀行邏輯以及銀行門(mén)戶(hù)代碼(XHTML、CSS 和 XHR)。請等待本系列的第 3 部分,也就是最后一部分。在此之前,請復習銀行場(chǎng)景中目前已經(jīng)應用的核心 Ajax 和 PHP 概念以及開(kāi)發(fā)技術(shù),盡可能熟悉這些知識。






回頁(yè)首


下載

名字 大小 下載方法
wa-aj-end2end2.zip 14KB HTTP
關(guān)于下載方法的信息


參考資料

學(xué)習

獲得產(chǎn)品和技術(shù)


關(guān)于作者

Senthil Nathan 是位于紐約 Hawthorne 的 IBM T.J. Watson Research Center 的一位高級軟件工程師。在為不同類(lèi)型的企業(yè)應用程序構建軟件方面,他有 22 年經(jīng)驗。他當前感興趣的領(lǐng)域包括 SOA、Web 服務(wù)、Java 2 Platform, Enterprise Edition(J2EE)、PHP、Ruby On Rails、Web 2.0 和 Ajax 開(kāi)發(fā)。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
使用jquery+ajax+php實(shí)現搜索框的功能
PHP V5.2 中的新增功能,第 3 部分: 使用新的 JSON 擴展
史上最詳細的ajax教程(一),不容錯過(guò)
myssqli和mysql的函數
Chrome調試工具developer tool技巧
12個(gè)常規前端面試題及小結
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久