技术开发 频道

ASP 开发人员的 J2EE 基础

        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 页面中的状态管理

1 <%@ page contentType="text/html; charset=iso-8859-1" language="java" session="true" %>
2 <%
3 String foo = "I am a Foo";
4 // Place object in session scope
5 session.setAttribute("Foo", foo);  
6 // Retrieve from session scope
7 String sessionFoo = (String) session.getAttribute("Foo");
8 // Place object in application scope
9 application.setAttribute("Foo", foo);  
10 // Retrieve from application scope
11 String applicationFoo = (String) application.getAttribute("Foo");
12 // Place object in page scope
13 pageContext.setAttribute("Foo", foo);
14 // Retrieve from page scope
15 String pageFoo = (String) application.getAttribute("Foo");
16 // Place object in request scope
17 request.setAttribute("Foo", foo);
18 // Retrieve from request scope
19 String requestFoo = (String) request.getAttribute("Foo");
20 %>
21 ....
22

  清单 31 中的例子的第一行是 page 指令,它允许您定义整个页面的属性。请注意 session 属性的使用,它决定了该页面是否要使得会话可用。如果将它设置为 true 却还没有建立会话,那么新的会话就会为您创建。如果将它设置为 false,那么会话范围将在该 JSP 页面中不可用。(这个属性的面默认设置是 true,因此这里使用它是多余的,只是出于说明目的。)

  清单 32 是使用各种可用范围来存储和检索数据的 servlet 的一个例子。

  清单 32. servlet 中的状态管理

1 public class MyServlet extends HttpServlet {
2    public void doGet(
3       HttpServletRequest request, HttpServletResponse response)
4       throws ServletException, IOException {
5       performTask(request, response);
6    }
7    public void doPost(HttpServletRequest request, HttpServletResponse response)
8       throws ServletException, IOException {
9       performTask(request, response);
10    }
11    /**
12     * Handles all HTTP GET and POST requests
13     *
14     * @param request Object that encapsulates the request to the servlet
15     * @param response Object that encapsulates the response from the servlet
16     */
17    public void performTask(
18       javax.servlet.http.HttpServletRequest req,
19       javax.servlet.http.HttpServletResponse res)
20       throws ServletException, IOException {
21       try {
22            // This is how you create a session if is has not been created yet
23           // Note that this will return the existing session if you've
24           // already created it
25             HttpSession session = req.getSession();
26         
27          //This is how the application context is retrieved in a servlet
28          ServletContext application = getServletContext();
29         
30             String foo = "I am a Foo";
31             session.setAttribute("Foo", foo);
32             
33          // Place object in session scope
34 session.setAttribute("Foo", foo);  
35        // Retrieve from session scope
36 String sessionFoo = (String) session.getAttribute("Foo");
37        // Place object in application scope
38 application.setAttribute("Foo", foo);  
39        // Retrieve from application scope
40 String applicationFoo = (String) application.getAttribute("Foo");
41       // Place object in request scope
42 request.setAttribute("Foo", foo);  
43      // Retrieve from request scope    
44 String requestFoo = (String) request.getAttribute("Foo");          
45           
46             ...
47             
48       } catch (Throwable t) {
49          // All errors go to error page
50          throw new ServletException(t.getMessage());
51       }
52    }
53

  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 页面中的编程式导航

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

  清单 34 展示了 servlet 中这些导航方法的一些例子。

  清单 34. servlet 中的编程式导航

1 public void doGet(HttpServletRequest request, HttpServletResponse response)
2    throws ServletException, IOException {
3   ...
4     // Redirecting to another resource
5 response.sendRedirect("anotherResource.jsp");
6   ...
7 }
8 // This code snippet shows the use of a RequestDispatcher to forward to another resource
9 public void doGet(HttpServletRequest request, HttpServletResponse response)
10    throws ServletException, IOException {
11   ...
12   // Get a RequestDispatcher instance
13   RequestDispatcher rd = getServletContext().getRequestDispatcher("anotherResource.jsp");
14   // Forward the request
15   rd.forward(request, response);
16   ...
17 }
18 // This code snippet shows the use of a RequestDispatcher to include another resource
19 public void doGet(HttpServletRequest request, HttpServletResponse response)
20    throws ServletException, IOException {
21   ...
22   // Get a RequestDispatcher instance
23   RequestDispatcher rd = getServletContext().getRequestDispatcher("anotherResource.jsp");
24   // Forward the request
25   rd.include(request, response);
26   // Continue processing the request
27   ...
28 }
29

  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

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

  结束语

  感谢您使用这个关于 J2EE 开发的入门教程。我们已尽力提供足够的信息使您走上 J2EE 之路,并且使您的开放标准编程之旅尽可能的顺利。

0
相关文章