程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 走上開放之路: ASP開發人員的J2EE基礎(下)

走上開放之路: ASP開發人員的J2EE基礎(下)

編輯:關於JAVA

相關文章:走上開放之路: ASP 開發人員的 J2EE 基礎(上)

ASP/COM 和 J2EE 應用程序模型

接下來研究不同的應用程序體系結構,您可以使用這些體系結構開發 J2EE 應用程序並將 其與相應的 ASP/COM 應用程序體系結構關聯起來。

使用 Java Servlets 編程:基礎知識

編寫 Java Servlets 就可以對來自 URL 的請求進行可編程控制。典型的 servlet 調用 類似於以下步驟:

客戶機向 Web 服務器發出請求,將 servlet 命名為 URL 的一部分 ―― 例如, <FORM action="/myWebApp/LoginServlet" method="POST"> 。

Web 服務器將該請求轉發給應用程序服務器,該服務器查找 servlet 類的實例。

Web 容器調用 servlet。(servlet 的一個實例被加載到內存中,每個請求都調用不同線 程上的一個實例。)

注意,HTML 表單中 servlet 的 URL 包括 servlet 的名字和稱為 上下文根(在上例中 是 /myWebApp )的前綴。上下文根大致等價於 IIS 虛擬目錄。

圖 2 說明了這些步驟。

圖 2. Servlet 調用

Servlets 擴展 HttpServlet 類。如有需要,可以覆蓋 下列 HttpServlet 類的方法:

init() :在應用程序服務器加載 servlet 時調用

destroy() :在應用程序服務器卸載 servlet 時調用

doGet() :通過 HTTP GET 調用 servlet 時調用

doPost() :通過 HTTP POST 調用 servlet 時調用

編寫 servlet 涉及編寫代碼來處理 HTTP 請求,處理任何參數並直接返回任何內容,或 委派另一種資源(如 JSP 頁面)來處理響應。不建議直接從 servlet 返回 HTML,因為管理 Java 類內的 HTML 代碼很不靈活。

當應用程序服務器調用 doGet() 或 doPost() 方法時,以下兩個對象將作為參數傳遞進 來:

HttpServletRequest 允許訪問任何請求參數以及 HTTP 請求中引發 servlet 調用的其他 信息。

HttpServletResponse 充當返回到客戶機的溝通渠道,允許 servlet 直接返回內容或返 回其他 HTTP 返回代碼(錯誤、重定向等)。

清單 20 和 21 展示了兩個 Hello World servlet。清單 20 直接返回內容,清單 21 使 用 JSP 頁面返回內容。

清單 20. HelloWorld servlet:直接返回內容

public class HelloWorldServlet extends HttpServlet {
/**
  * Handles all HTTP POST requests
  *
  * @param request Object that encapsulates the request to the servlet
  * @param response Object that encapsulates the response from the servlet
  */
public void doPost(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws ServletException, IOException {
try {
  PrintWriter out = response.getWriter();
  out.println("<html>");
  out.println("Hello World");
  out.println("</html>");
} catch (Throwable t) {
  ...
}
}
}

注意,您從響應對象獲得 PrintWriter ,並一次一行將 HTML 輸出到客戶機。

清單 21. HelloWorld servlet:使用 JSP 頁面返回內容

public class HelloWorldServlet extends HttpServlet {
/**
  * Handles all HTTP POST requests
  *
  * @param request Object that encapsulates the request to the servlet
  * @param response Object that encapsulates the response from the servlet
  */
public void doPost(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws ServletException, IOException {
try {
       RequestDispatcher rd = getServletContext().getRequestDispatcher ("helloworld.jsp");
       rd.forward(request, response);
} catch (Throwable t) {
  ...
}
}
}

RequestDispatcher 是您希望將請求轉發給的資源的包裝器。注意,要同時包括原始請求 和響應對象,以便目標資源可以訪問它們。從 getServletContext() 返回的 ServletContext 允許服務器與底層應用程序進行通信來獲得 RequestDispatcher 。注意, 所有 servlet 都通過 etServletContext() 方法訪問其 ServletContext 。

使用 JSP 技術編程:基礎知識

使用 JSP 技術您就具有使用 Java 語言編寫服務器端腳本的能力。在 JSP 頁面返回到客 戶機前,它是一個組合頁面,由 HTML 和應用程序服務器處理的 Java 代碼組成。在頁面返 回到客戶機前,應用程序服務器處理嵌入代碼以生成靜態內容。與 .aspx 文件類似,JSP 頁 面通常與 HTML 文件很相似,只是增加了一些額外的標簽和 Java 代碼片斷。

在第一次請求 JSP 頁面時,應用程序服務器將每個 JSP 頁面轉換為特殊的 servlet。該 servlet 編譯並加載到內存中。只要 JSP 源未被修改,這個 servlet 就對要獲得該頁面的 請求提供服務。在源修改後,此過程再次開始,並生成一個新版本的 servlet。

您可以在 JSP 頁面中使用幾種特殊的 JSP 標簽,用戶還可以定義自己開發的標簽的行為 。您還可以將大段的 Java 代碼添加到頁面的不同部分。J2EE 運行時環境創建了許多變量, 稱為 隱含變量―― 可用於這些 Java 代碼的片斷。隱含變量的例子有:

request:與頁面的特定調用相關的 HttpServletRequest

response:與頁面的特定調用相關的 HttpServletResponse

out:與 HttpServletResponse 相關的 PrintWriter

清單 22 展示了 JSP 頁面的一個例子,該頁面既包含 HTML 也包含 Java.代碼。<% and the %> 標簽之間的 Java 代碼部分稱為 scriptlet。

清單 22. HelloWorld servlet:使用 JSP 頁面返回內容

<html>
<title>JSP page example</title>
The date is:
<%
Date date = new Date();
out.println(date);
%>
Some more HTML
The value of <em>e</em> is:
<%
double e = Math.exp(1.0);
out.println(e);
%>
Yet even more HTML
The value of PI is:
<%
double pi = 22.0/7.0;
out.println(pi);
%>
</html>

注意,JSP 隱含變量 out 的用途是將內容寫回到客戶機,還要注意 HTML 和 Java 代碼 的交織。

一個示例場景

為了說明各種體系結構選項,我們將使用一個簡單的用戶登錄場景,它包含:

一個具有 HTML 表單的登錄頁面,它從用戶那裡獲得用戶名和密碼

驗證用戶憑證(可能使用數據庫)並重定向站點主頁的應用邏輯

使用這個簡單的例子可以說明各種應用程序體系結構。

“意大利面條式”代碼

在 ASP 端,“意大利面條式”代碼方法使用單個 .aspx 文件來同時包含應用邏輯和 HTML 表單。(不建議對現實中的例子采用這種方法,因為這樣所有表示邏輯和應用邏輯都將 是單個文件,從而您就不能重用用於驗證用戶憑證的代碼。)該代碼的輪廓看起來類似清單 23 中所示的代碼。(為簡單起見,我們省略了所有錯誤處理代碼。)

清單 23. ASP 中的“意大利面條式”代碼

'--FUNCTION TO VALIDATE USER ENTERED LOGIN DATA FUNCTION ValidateUser (username,password)
  '--Code to validate users credentials goes here
  ...
END FUNCTION %>
<html>
<head>
<title>Login example</title>
</head>
<body>
<% IF (REQUEST.SERVERVARIABLES("REQUEST_METHOD") = "GET") THEN %>
  <form action="login.asp" method="post">

  <!-- login form fields go here -->

  </form>
<% ELSE userName = REQUEST.FORM("username") password = REQUEST.FORM ("password")
    IF (ValidateUser(userName, password)) THEN 
          RESPONSE.REDIRECT("mainpage.asp") ELSE ... END IF END IF % >
  <font color="red"><b><%=LoginMessage% ></b></font>
</body>
</html>

正如清單 24 所示,您可以在 J2EE 中采用相同的方法,使用單個 JSP 頁面來同時包含 表單和應用邏輯。

清單 24.J2EE 中的“意大利面條式”代碼

<html>
<head>
<title>Login example</title>
<%!
private boolean validateUser(String userName, String password) {
    ...
}
%>
...
</head>
<body>
<%
  if (request.getMethod().equals("GET") ) { %>
  <form method="POST" target="login.jsp">
  <!-- login form fields go here -->
  </form> <% }
  else {
    String userName = request.getParameter("username");
    String password = request.getParameter("password");
    if (validateUser(userName, password)) {
      response.sendRedirect("mainpage.jsp");
    }
    ...
  } %>
</body>
</html>

與 ASP 模型類似,JSP 模型不是事件驅動的,因此您需要檢查表單是否被發送回去了, 方法是檢查該請求,並且如果不是 POST 請求時則添加表單的 HTML。如果它是 POST 請求, 您將使用在 JSP 中聲明的一個方法來驗證登錄。注意,使用 <%! 表明該代碼是一個方法 。Scriptlet 代碼將在 JSP 頁面處理期間遇到它們的時候執行,因此用於 scriptlet 的標 簽( <% %> )對方法無效。還要注意如何使用 if/then/else 編程結構來方便地添加 或去除較大的 HTML 塊。與在 ASP 例子中一樣,不推薦將此方法用於 J2EE 開發。表示代碼 (HTML)和應用邏輯的混合僅允許很少的重用,並且使得代碼難於維護。

改進的“意大利面條式”代碼

在 ASP 端,可以以前一個例子為基礎建立一種更好的方法,不過除了 login.asp 文件外 ,還使用只包含驗證邏輯的一個 include ASP 文件。這樣您就可以重用其他 ASP 文件中的 代碼。

J2EE 端的一種更好方法是將應用邏輯轉移到一個 Java Servlet,從而使 JSP 頁面僅限 於使用 HTML 組件。現在驗證邏輯獨立於顯示表單的頁面,這是一種改進,而 JSP 頁面僅限 於使用 HTML 組件也是一種改進。清單 25 顯示了如何將應用邏輯放到 servlet 中從而簡化 JSP 頁面。

清單 25. J2EE:JSP 頁面中改進的“意大利面條式”代碼

<html>
<head>
<title>Login example</title>
...
</head>
<body>
<form method="POST" target="LoginServlet">
<!-- login form fields go here -->
</form>
</body>
</html>

清單 26 顯示了 servlet 中的驗證代碼和導航邏輯。

清單 26. J2EE:Java Servlet 中改進的“意大利面條式”代碼

public class LoginServlet extends HttpServlet {
/**
  * Handles all HTTP POST requests
  *
  * @param request Object that encapsulates the request to the servlet
  * @param response Object that encapsulates the response from the servlet
  */
public void doPost(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws ServletException, IOException {
try {
      String userName = request.getParameter("username");
      String password = request.getParameter("password");
      if (validateUser(userName, password)) {
       response.sendRedirect("mainpage.jsp");
      }
       ...
} catch (Throwable t) {
  ...
}
}
private boolean validateUser(String userName, String password) {
    ...
   }
}

清單 26 中的 servlet 是表單提交的目標,並且充當一個控制器――處理用戶輸入並基 於該輸入調出適當的頁面。注意 HttpServlet 父類允許您通過提供可重載的方法( doGet() 和 doPost() )來同時處理 GET 和 POST 請求。

這種方法的主要缺點在於,憑證驗證代碼(它很可能要訪問數據庫)是 J2EE 例子中 servlet 的一部分。如果不同的頁面需要使用這個邏輯,您就必須重復它。重復的代碼更難 於維護和更易於出錯,因為您必須跟蹤多個副本。

模型-視圖-控制器(MVC)方法

下面我們將展示如何對這個例子使用更純的 MVC 方法。在 ASP 端,這體現為將憑證驗證 邏輯轉移到一個單獨 COM 組件,然後您在 ASP 文件中進行訪問。在 J2EE 端,憑證驗證代 碼將轉移到一個單獨的類中,然後從 servlet 訪問該類。清單 27 中的代碼片斷顯示了該 servlet 的外觀。

清單 27. J2EE: Java Servlet 中的 MVC

import com.ibm.businessobjects.UserValidation
public class LoginServlet extends HttpServlet {
/**
  * Handles all HTTP POST requests
  *
  * @param request Object that encapsulates the request to the servlet
  * @param response Object that encapsulates the response from the servlet
  */
public void doPost(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws ServletException, IOException {
try {
      String userName = request.getParameter("username");
      String password = request.getParameter("password");
      UserValidation user = new UserValidation();
      if (user.validate(userName, password)) {
       response.sendRedirect("mainpage.jsp");
      }
       ...
} catch (Throwable t) {
  ...
}
}
}

清單 28 顯示了位於一個單獨的類中的憑證驗證代碼。

清單 28. J2EE:用戶驗證類中的 MVC

package com.ibm.businessobjects;
public class UserValidation {
  public boolean validate(String username, String password) {
   ...
  }
}

憑證驗證在 servlet 使用的類中進行。現在該 servlet 不必直接了解驗證如何進行。只 要您保持相同的公共接口不變,就可以隨意更改 UserValidation 而不需改變 servlet 代碼 。您還可以在非 Web 應用程序中重用該代碼。

其他 J2EE 組件

前面的例子展示了如何將業務邏輯分離到一個或一組單獨的類中。這樣允許您以各種不同 的方式實現業務邏輯,而不會影響 servlet 和 JSP 頁面。與使用一個需要訪問數據庫(使 用 JDBC)的業務對象不同,您可以通過各種不同的方式實現這個邏輯。例如:

使用 JCA 來訪問諸如大型機等遺留系統:JCA 是一個 J2EE API,它允許 J2EE 應用程序 使用標准接口與遺留系統(比如 CICS 或者 IMS)交互。

使用 Web 服務客戶端 API 來訪問 Web 服務:這種方法涉及使用 Apache Axis 或其他某 種 Java Web 服務客戶端 API 來訪問 Web 服務。

使用 JMS 將消息作為驗證請求來發送:這種方法涉及使用標准 API 來訪問 JMS 相容的 消息中間件(比如 WebSphere MQ)。

使用 EJB 技術來實現驗證邏輯:這種方法涉及使用 EJB 組件(而不是簡單的 Java 類) 來實現業務邏輯。EJB 組件能夠使用應用服務器中的服務來管理(數據庫或其他)事務,管 理方法級的安全,以及提供群集和高速緩存。將此類任務委托給應用服務器,您可以把精力 集中在業務邏輯上,而不必擔心系統級的問題。

J2EE 數據訪問

下面我們將介紹 JDBC API,這是 J2EE 下的行業標准接口集,它允許 Java 程序使用統 一的 API 調用集來訪問關系數據庫。JDBC 允許您開發應用程序一次,然後針對任何 JDBC 相容的數據庫部署它們 ―― DB2、Oracle、SQL Server、Sybase、mySQL、Informix 以及其 他數據庫。

JDBC API 允許任何 Java 組件(包括 Java Servlets 和 JSP 頁面)無縫地訪問關系數 據庫中的數據。JDBC 由兩部分組成:用於訪問數據庫的 API,以及數據庫廠商為各自的數據 庫提供的可嵌入 JDBC 驅動程序。JDBC API 最便利的特性之一在於,您不必使用任何特定於 廠商的類。您可以在運行時使用一個字符串常量來指定適當的驅動程序,以後就可以使用相 同的編程接口,而不管所使用的是哪種數據庫。這樣您就可以切換數據庫,而不必更改代碼 (只要您在運行時提供字符串常量以指定驅動程序)。

一個 JDBC 例子

典型的 JDBC 應用程序必須完成以下步驟才能與數據庫交互:

識別驅動程序。(每個應用程序只需執行這個步驟一次。)

識別數據庫並與之建立連接(在需要時提供身份驗證信息)。

執行查詢和/或更新。

處理結果。

斷開與數據庫的連接。

清單 29 說明了上述步驟。

清單 29. 一個 JDBC 例子

// Step 1. SPECIFY THE APPROPRIATE DRIVER TO USE
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver");
// Step 2. Identify the database and connect to it
Connection conn = DriverManager.getConnection ("jdbc:db2:SAMPLE","userid","password");
// Step 3. Execute query
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM USERID.EMPLOYEE");
// Step 4. Get the results
ResultSet rs = stmt.getResultSet();
while (rs.next()) {
  String firstCol = rs.getString(1);
  int secondCol  = rs.getInt(2);
  ...
}
// Step 5. Disconnect from the database
conn.close();

清單 29 中的 Step 1 動態地加載適當的驅動程序。這個例子使用的是 DB2;其他 JDBC 驅動程序具有不同的完全限定名稱。Step 2 提供特定於驅動程序的 String 指出要連接到哪 個數據庫。每種 JDBC 驅動程序都有自己的 String 格式。DB2 使用的格式是 "jdbc:db2:DBNAME" ,因此在此例中系統要連接到一個名為 SAMPLE 的數據庫。例子中還提 供了身份驗證信息,以便數據庫服務器能夠對連接請求進行身份驗證。在 Step 4 中,注意 例子中如何循環遍歷結果集,直到 next() 方法返回 false 。您還必須知道每列的類型,並 對每列和每種類型調用適當的 getXXXX(n) 方法。還要注意您傳遞給 getXXXX(n) 方法的整 數是列編號。

在 ASP 頁面使用 ADO 但沒有連接池時,以上方法與典型的 ASP 頁面采用的方法很相似 ,因為程序員負責打開和關閉數據庫連接。

連接池

連接池通過對可以同時打開的數據庫連接數目規定上限,可以增加應用程序的可伸縮性, 因而防止由於過多的連接請求而造成數據庫服務器的過度運行。對於 ASP 來說,如果您選擇 的數據庫(如 DB2、SQL Server 或 Oracle)有 OLEDB 提供程序,則可以利用連接池,從而 就不必直接管理數據庫連接。

有了 JDBC,您可以將自己從直接管理連接的工作中解放出來。J2EE 應用程序服務器被要 求為它們支持的所有數據庫提供連接池。它們不使用某些高級的 JDBC API 調用來完成該任 務。當您的代碼在應用程序服務器的監控下運行時,您就不必直接與數據庫服務器交互,以 便為每個配置的數據庫維護連接池。然後,應用程序從該池中請求連接,並在使用完這些連 接之後,將其返回到該池。大多數應用程序服務器都有相當高級的選項對池進行管理,包括 “收回”連接的能力,即從出錯的應用程序(沒有在給定時間內將連接返回池中)取回連接 。

使用連接池的應用程序的典型流程如下:

查找應用服務器資源庫中的 DataSource (用於訪問特定的連接池)。(每個應用服務器 都有一個資源庫,其中包含所有已配置的連接和其他資源,比如消息隊列和 SMTP 提供程序 。您可以使用名為 JNDI 的標准 J2EE API 來訪問資源庫。)(這個步驟只需執行一次。)

從池中獲得連接(在需要時提供身份驗證信息)。

執行查詢和/或更新。

處理結果。

將連接返回池中。

清單 30 展示了使用連接池的一個例子。

清單 30. 一個連接池例子

// Step 1. Look up the DataSource
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup("jdbc/MyDS");
// Step 2. Get a connection from the pool
Connection conn = ds.getConnection();
// Step 3. Execute query
Statement stmt = conn.createStatement();
stmt.execute("SELECT * FROM USERID.EMPLOYEE");
// Step 4. Get the results
ResultSet rs = stmt.getResultSet();
while (rs.next()) {
  String firstCol = rs.getString(1);
  int secondCol  = rs.getInt(2);
  ...
}
// Step 5. Return connection to the pool
conn.close();

Step 1 假設應用服務器已經配置了名為 "jdbc/MyDS" 的 DataSource 。這樣就封裝了一 個特定的 JDBC 驅動程序和數據庫。您還可以向 DataSource 定義添加身份驗證信息,這樣 應用程序就不必提供該信息。您可以使用 InitialContext 類(它是 JNDI API 的一部分) 來查找應用服務器控制的各種資源。Step 3 至 Step 5 與前一個例子相同,不過要注意 Step 5 中對 close() 方法的調用僅把連接返回池中,而不是關閉該數據庫連接。

J2EE 應用程序狀態管理

在編寫 J2EE Web 應用程序時,要管理應用程序的狀態,有一組豐富的類和接口可供選擇 。我們將介紹這些類和接口,並討論如何在 Java Servlets 和 JSP 頁面中使用這些類和接 口。不過,我們將首先介紹 范圍的概念,它是理解 J2EE 中的應用程序狀態管理的關鍵。

范圍

從程序員的角度看,狀態管理涉及臨時存儲數據和在需要時檢索它們。在 J2EE 中,您可 以選擇多個“存儲位置”,每個位置具有它自己規則,這些規則控制任何存儲的數據得有效 時間。持續時間從處理某個特定頁面所需的時間(臨時存儲一些數據),到應用程序運行生 命期(長期存儲數據)不等。J2EE 中的“存儲位置”選擇稱為特定存儲請求或檢索的 范圍 。該范圍決定了您將把數據附加到哪些 J2EE 對象,以及那些數據將在多長時間內可用。可 用的范圍是:

會話:這類似於 ASP 中的會話范圍。只要會話還是活動的,您就可以在該用戶會話范圍 內放置任何 Java 對象並檢索它。J2EE 應用程序使用 HttpSession 接口(類似於 ASP 中的 SESSION )。可以使用 String 作為標簽將對象添加到會話中,並使用相同的標簽來檢索它 。

請求:在 J2EE 中,HttpServletRequest 對象允許您向它附加數據,這非常類似 HttpSession interface 接口。當多個資源處理單個請求時,這是很有用的。例如,某個 Java Servlet 可能是一個 HTML 表單提交的目標,然後它將請求轉發給一個 JSP 頁面以完 成它。在這個例子中,該 sevlet 能夠向 HttpRequest 對象附加數據,並且 JSP 頁面能夠 訪問它。注意在這種場景中,該 servlet 和 JSP 頁面都使用相同的 HttpRequest 對象。

應用程序:所有 J2EE Web 應用程序在部署之前都打包到一個具有 .war 擴展名的文件中 。該文件的格式是標准的,因此您可以把同一個應用程序部署到不同的應用服務器。單個 .war 文件中的所有 J2EE 組件都被認為是同一個應用程序的組成部分,並且共享共同的應用 程序上下文。這是通過 ServletContext 接口向開發人員公開的,這個接口(就像 HttpSession 和 HttpRequest 口一樣)允許您附加和刪除任何 Java 對象。只要應用程序還 在運行,添加到 ServletContext 的項就可用,並且會在單獨會話的創建和銷毀過程中保留 下來。這類似於 ASP 中的 APPLICATION 對象。

頁面:頁面上下文在處理單個頁面的過程中可用。如,JSP 頁面頂部的 Java scriptlet 能夠在 PageContext 中放置對象,然後相同頁面中的其他 scriptlet 就可以訪問它。

管理應用程序狀態

現在您已經對范圍有了更好的了解,下面我們可以深入地討論管理 J2EE Web 應用程序中 的狀態的機制。最佳實踐是,對於任何臨時的狀態存儲,您都應該確定需要存儲該數據多長 時間,然後使用滿足需要的、具有最短生存時間的范圍。例如,假設您需要某個 JSP 頁面中 的數據,該 JSP 頁面是從某個 servlet 轉發的請求的目標。雖然會話狀態和應用程序狀態 也滿足您的需要,但是在這兩種情況下,數據都會在使用完之後懸置在那裡。這樣不必要地 增加了當前應用程序的資源需求。對於這個例子,請求范圍能夠滿足需要,卻不會在您不需 要之後還將數據懸置在那裡。

管理 JSP 頁面中的狀態

在 JSP 腳本環境中,所有范圍對象都是用隱含變量來表示的。您可以在自己的 sciptlet 中使用這些變量,而不需要顯式地聲明它們。可以使用的隱含變量有:

session: 實現 HttpSession 接口的類的一個實例。

application:實現 HttpSession 接口的類的一個實例。

request:實現 HttpServletRequest 接口的類的一個實例。

pageContext: PageContext 類的一個實例。

清單 31 展示了如何在 JSP scriptlet 中針對不同的范圍添加和刪除對象。

清單 31. JSP 頁面中的狀態管理

<%@ page contentType="text/html; charset=iso-8859-1" language="java" session="true" %>
<%
String foo = "I am a Foo";
// Place object in session scope
session.setAttribute("Foo", foo);
// Retrieve from session scope
String sessionFoo = (String) session.getAttribute("Foo");
// Place object in application scope
application.setAttribute("Foo", foo);
// Retrieve from application scope
String applicationFoo = (String) application.getAttribute("Foo");
// Place object in page scope
pageContext.setAttribute("Foo", foo);
// Retrieve from page scope
String pageFoo = (String) application.getAttribute("Foo");
// Place object in request scope
request.setAttribute("Foo", foo);
// Retrieve from request scope
String requestFoo = (String) request.getAttribute("Foo");
%>
....

清單 31 中的例子的第一行是 page 指令,它允許您定義整個頁面的屬性。請注意 session 屬性的使用,它決定了該頁面是否要使得會話可用。如果將它設置為 true 卻還沒 有建立會話,那麼新的會話就會為您創建。如果將它設置為 false,那麼會話范圍將在該 JSP 頁面中不可用。(這個屬性的面默認設置是 true,因此這裡使用它是多余的,只是出於 說明目的。)

清單 32 是使用各種可用范圍來存儲和檢索數據的 servlet 的一個例子。

清單 32. servlet 中的狀態管理

public class MyServlet extends HttpServlet {
  public void doGet(
    HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    performTask(request, response);
  }
  public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    performTask(request, response);
  }
  /**
   * Handles all HTTP GET and POST requests
   *
   * @param request Object that encapsulates the request to the servlet
   * @param response Object that encapsulates the response from the servlet
   */
  public void performTask(
    javax.servlet.http.HttpServletRequest req,
    javax.servlet.http.HttpServletResponse res)
    throws ServletException, IOException {
    try {
      // This is how you create a session if is has not been created yet
      // Note that this will return the existing session if you've
      // already created it
       HttpSession session = req.getSession();

     //This is how the application context is retrieved in a servlet
     ServletContext application = getServletContext();

       String foo = "I am a Foo";
       session.setAttribute("Foo", foo);

     // Place object in session scope
session.setAttribute("Foo", foo);
    // Retrieve from session scope
String sessionFoo = (String) session.getAttribute("Foo");
    // Place object in application scope
application.setAttribute("Foo", foo);
    // Retrieve from application scope
String applicationFoo = (String) application.getAttribute("Foo");
    // Place object in request scope
request.setAttribute("Foo", foo);
   // Retrieve from request scope  
String requestFoo = (String) request.getAttribute("Foo");

       ...

    } catch (Throwable t) {
     // All errors go to error page
     throw new ServletException(t.getMessage());
    }
  }

JSP 頁面和 sevlet 中的會話之間的區別在於,在 sevlet 中,您必須顯式地創建和檢索 它,而在 JSP 頁面中,這是自動為您完成的。注意 pageContext 僅適用於 JSP 頁面,而不 適用於 servlet;還要注意 servlet API 如何提供了兩個要覆蓋的方法來處理 GET 和 POST HTTP 請求。這個例子提供了一個名為 performTask() 的通用方法來同時處理這兩種類型的 請求,不過您可以基於觸發 servlet 調用的 HTTP 類型而使用不同的處理。

編程式導航

在代碼中從一個資源導航到另一個資源的情況在 Web 應用程序中是相當普遍的。導航與 應用程序狀態密切相關,因為當您在一系列資源中導航時,可能需要維護狀態信息。與 ASP 比較而言,J2EE 提供更多的選項進行編程式導航。

ASP 使用 RESPONSE.REDIRECT() 函數支持編程式導航。J2EE 支持以下形式的編程式導航 :

使用 HttpServletResponse.sendRedirect() 方法 :這會導致向客戶端浏覽器返回一個 特殊的 HTTP 返回代碼(連同要重定向的頁面),然後客戶端浏覽器又對重定向的目標發出 新的請求。如果需要在這兩個請求之間共享數據,那就必須將數據存儲在會話或應用程序范 圍中。這類似於 ASP 中的 RESPONSE.REDIRECT() 函數。

使用 servlet 中的 RequestDispatcher.forward() 方法或 JSP 頁面中的特殊標簽: 這 會導致調用此方法的資源終止,同時終止對作為轉發目標的資源的調用。對客戶端浏覽器來 說,這看起來就像是單個請求。例如,如果將請求從 servlet 轉發到 JSP 頁面,則您可能 要附加該 servlet 中的某些處理結果,以便這些結果可以在 JSP 頁面中顯示出來。

使用 RequestDispatcher.include() 方法或 JSP 頁面中的特殊標簽 :這會導致調用此 方法的資源掛起,同時掛起對目標資源的調用。當目標資源完成時,掛起的資源又繼續處理 。對客戶端浏覽器來說,這看起來就像是單個請求。

清單 33 包括了 JSP 頁面中這些導航方法的一些例子。

清單 33. JSP 頁面中的編程式導航

<!-- This scriptlet shows how you can redirect to another resource - ->
<%
response.sendRedirect("anotherPage.jsp");
%>
<!-- This special JSP tag allows you to forward the request to another resource -->
<jsp:forward page="anotherPage.jsp"/>
<!-- This special JSP tag allows you to include another resource
               as part of the processing of this page -->
<jsp:include page="anotherPage.jsp" flush="true"/>

清單 34 展示了 servlet 中這些導航方法的一些例子。

清單 34. servlet 中的編程式導航

public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  ...
   // Redirecting to another resource
response.sendRedirect("anotherResource.jsp");
  ...
}
// This code snippet shows the use of a RequestDispatcher to forward to another resource
public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  ...
  // Get a RequestDispatcher instance
  RequestDispatcher rd = getServletContext().getRequestDispatcher ("anotherResource.jsp");
  // Forward the request
  rd.forward(request, response);
  ...
}
// This code snippet shows the use of a RequestDispatcher to include another resource
public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
  ...
  // Get a RequestDispatcher instance
  RequestDispatcher rd = getServletContext().getRequestDispatcher ("anotherResource.jsp");
  // Forward the request
  rd.include(request, response);
  // Continue processing the request
  ...
}

Cookie

在 ASP 中,cookie 的處理使用了 REQUEST 和 RESPONSE 對象的 Cookies 屬性。 RESPONSE 對象用於創建 cookie,而 REQUEST 對象用於檢索 cookie 值。為方面起見,在代 碼中使用了多值 cookie,盡管多值 cookie 被編碼到 HTTP 響應表頭時,但是可以轉換為單 值 cookie。

在 J2EE 中,cookie 由 Cookie 類表示,並通過 HttpServletRequest 和 HttpServletResponse 接口來訪問。您可以使用 HttpServletRequest 接口訪問現有的 cookie,使用 HttpServletResponse 接口來創建 cookie。

清單 35 演示了如何在 J2EE 應用程序中使用 cookie。您可以在 Java Servlet 或 JSP 頁面的 scriptlet 中使用這些代碼片斷。

清單 35. 在 J2EE Web 應用程序使用 cookie

// Create a cookie using the HttpServletResponse interface
// The first parameter of the constructor is the name of the cookie
// and the second parameter is the cookie's value
Cookie myCookie = new Cookie("myCookie", "someValue");
// Set the age of the cookie - by default cookies will be stored in memory
// by the browser and will be destroyed when the user closes the browser
// The setMaxAge() methods takes an integer as its parameter which represents
// the age in seconds. In this example we're specifying an age of 24 hours for
// the cookie
myCookie.setMaxAge(86400);
// Add cookie to the response
response.addCookie(myCookie);
// Here's an example of retrieving cookies from the HttpServletRequest interface
// Note that the cookies are returned as an array of Cookie objects
Cookies[] myCookies = request.getCookies();
// The getCookies method will return null if there are no cookies
if (myCookies != null) {
  for (int i = 0; i < myCookies.length; i++) {
    Cookie eachCookie = myCookies[i];
    // Do something w/each cookie
    ....
  }
}

結束語

感謝您使用這個關於 J2EE 開發的入門教程。我們已盡力提供足夠的信息使您走上 J2EE 之路,並且使您的開放標准編程之旅盡可能的順利。我們鼓勵您利用本文的 參考資料小節以 繼續接受 J2EE 教育。祝旅途愉快。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved