开发人员:Java
   下载
下载 Oracle 数据库 10g Oracle JDeveloper 10g 与 ADF
下载 Oracle 数据库 10g 示例代码
 
   关键词
ajax, java, All
 

结合使用 EJB3 和 Ajax


作者:Andrei Cioroianu

了解如何构建一个 Java 企业版应用程序,以对 Web 层使用 Ajax、JavaServer Faces 和 ADF Faces,对业务逻辑使用 EJB3。

2007 年 3 月发布

企业应用程序可以使用 Ajax 提供更好的 Web 界面,从而提高用户的生产效率。在许多情况下,可以提交部分完成的表单以从服务器应用程序获得有用信息。例如,服务器可以执行一些早期验证,也可以使用部分用户输入来建议空白表单域的值,从而加快数据输入过程的速度。Ajax 还可用于连接数据馈送,显示其信息但不刷新整个页面。

在本文中,我们将介绍一个简单应用程序,它包含一个使用 Ajax 连接到 ad 馈送的 Web 页面。用户输入提交到一个控制器 servlet,该 servlet 调用一个 EJB 组件的业务方法来选择个性化的 ad。该业务方法使用 DHTML 返回一个在 JSP 页面中用于生成 Ajax 响应的实体,然后将该实体插入 Web 页面中。下图描绘了应用程序的体系结构:



图 1


我将使用 Oracle JDeveloper 向导创建应用程序的组件和用户界面。您将了解如何创建实体、会话 bean、Ajax 控制器 servlet、生成 Ajax 响应的 JSP 页面,以及基于 ADF Faces 的 JSF 表单。在本文的最后一部分,您将发现可用于创建、初始化和删除 XMLHttpRequest 对象的可重用的 JavaScript 函数。您还将学习一些 Ajax 技巧,如使用回调包装、使用 Ajax 提交表单数据,以及在 Web 浏览器中防止内存泄漏。

使用 JDeveloper 创建 EJB 组件

在本部分中,我将使用 JDeveloper 的 EJB 向导创建一个简单的实体和一个 EJB 会话组件,该组件的业务方法将通过 Ajax-EJB 控制器从一个 Ajax 客户端进行调用。启动 JDeveloper 并创建一个新的名为 ajaxejb 的项目。

创建实体

在 Applications 导航器中,右键单击新创建的项目并单击 New。在 New Gallery 窗口的左侧面板中,展开 Business Tier 节点并选择 EJB。然后,在该窗口的右侧面板中选择 Entity (JPA/EJB 3.0) 并单击 OK:



图 2


跳过 Create JPA/EJB 3.0 向导的 Welcome 页面,提供 AdEntity 作为 Entity Class 的名称。该向导还将更改 Entity Name 域:



图 3


该向导的下一步允许您选择一个继承选项。我们将 No inheritance 用于这第一个示例:



图 4


第三步允许您输入一个表名,选择一个模式并提供实体的超类:



图 5


第四步允许您更改默认 id field 和 version field。在本示例中,取消选中 Include @Version field 选项,将 @Id field 的名称更改为 keyword,并为 keyword 域选择 String 类型:



图 6


单击 Next 查看该实体的选定选项,然后单击 Finish。JDeveloper 将在 Application Sources 文件夹的 ajaxejb 程序包中创建 AdEntity:



图 7


现在,您可以使用 JDeveloper 的向导向该实体添加新的域和方法。在 Structure 导航器中,右键单击 Fields 并单击 New Field。提供域的名称,选择其类型并单击 OK:



图 8


添加 url 域之后,重复相同的过程添加另一个名为 content 的域。下面是 AdEntity 的源代码:

                                
package ajaxejb;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Entity
@NamedQuery(name = "AdEntity.findAll", 
            query = "select o from AdEntity o")
public class AdEntity implements Serializable {
    @Id
    private String keyword;
    public String url;
    public String content;

    public AdEntity() {
    }

    public String getKeyword() {
        return keyword;
    }

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

}
                       

在以下子部分中,我将介绍如何创建一个使用 AdEntity 的无状态会话 bean。

创建会话 bean

在 Applications 导航器中,右键单击 ajaxejb 项目并单击 New。在 New Gallery 窗口的左侧面板中,展开 Business Tier 节点并选择 EJB。然后,在该窗口的右侧面板中选择 Session Bean (EJB 1.1/2.x/3.0) 并单击 OK:



图 9


跳过 Create Session Bean 向导的 Welcome 页面,提供 AdSession 作为 EJB 的名称,选择 Stateless 会话类型,选择 Container 事务类型,您可以选择指示 JDeveloper 来 Generate Session Facade Methods:



图 10


接下来,您可以通过外观选择要公开的方法:



图 11


第三步允许您输入 bean 类的名称。输入 ajaxejb.AdSessionBean 并单击 Next:



图 12


第四步允许您选择 EJB 将实施的接口。可以使用本地接口,因为我们将使用单个 OC4J 实例在 JDeveloper 中测试示例应用程序。然而在生产环境中,我们可能希望使用专用的 ad 服务器(也可以是一个集群)来运行会话 bean。调用 bean 的方法的控制器 servlet 可以部署在多台 Web 服务器上,也可用于不同的 Web 应用程序中。通过指示 JDeveloper 生成一个名为 ajaxejb.AdSession 的 Remote Interface,我们仍然能够通过 JDeveloper 的嵌入式 OC4J 服务器运行示例应用程序,并且在生产环境中具有最大的灵活性。然而,如果我们确信我们希望将会话 bean 和控制器 servlet 部署在同一台服务器上,本地接口将提供更好的性能。也可以在同一个 bean 中同时实施远程和本地接口。在本示例中,我们将仅实施远程接口:



图 13


单击 Next 查看该会话 bean 的选定选项,然后单击 Finish。JDeveloper 将在 Application Sources 文件夹的 ajaxejb 程序包中创建 AdSessionBean:



图 14


我们现在使用 JDeveloper 提供的向导添加一个名为 selectAd() 的业务方法。在 Structure 导航器中,右键单击 Methods 并单击 New Method。在 Bean Method Details 对话框中,输入 selectAd 方法名,选择 ajaxejb.AdEntity 返回类型,输入 String userInput 参数并单击 OK:



图 15


JDeveloper 将更新 AdSession 接口和 AdSessionBean 类。下面是 AdSession 接口的源代码:

package ajaxejb;

import java.util.List;

import javax.ejb.Remote;

@Remote
public interface AdSession {
    Object mergeEntity(Object entity);

    Object persistEntity(Object entity);

    List<adentity> queryAdEntityFindAll();

    void removeAdEntity(AdEntity adEntity);

    AdEntity selectAd(String userInput);
}

JDeveloper 生成的 AdSessionBean 类包含会话外观方法,后面跟着一个 selectAd() 方法:

package ajaxejb;

import java.util.List;

import javax.ejb.Stateless;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless(name="AdSession")
public class AdSessionBean implements AdSession {
    @PersistenceContext(unitName="ajaxejb")
    private EntityManager em;

    public AdSessionBean() {
    }

    public Object mergeEntity(Object entity) {
        return em.merge(entity);
    }

    public Object persistEntity(Object entity) {
        em.persist(entity);
        return entity;
    }

    /**  
                              
select o from AdEntity o
*/ public List<adentity> queryAdEntityFindAll() { return em.createNamedQuery("AdEntity.findAll").getResultList(); } public void removeAdEntity(AdEntity adEntity) { adEntity = em.find(AdEntity.class, adEntity.getKeyword()); em.remove(adEntity); } public AdEntity selectAd(String userInput) { ... } }

现在,我们需要编写 selectAd() 方法的主体。

实施业务方法

实际应用程序将使用 AdSession bean 的方法通过 Web 界面来创建、更新和删除 AdEntity 实例。 selectAd() 方法将使用查询方法通过某种算法将用户的兴趣匹配到从数据库检索到的 ad。然而在本文中,我们将进行简化以关注主题。 selectAd() 方法将从用户输入中选择一个随机单词,然后返回一个新的 AdEntity 实例:

package ajaxejb;
...
import java.util.Random;
import java.util.StringTokenizer;
...
public class AdSessionBean implements AdSession {
    ...
    public AdEntity selectAd(String userInput) {
        String keyword = "nothing";
        if (userInput != null && userInput.length() > 0) {
            StringTokenizer st = new StringTokenizer(
                userInput, ",.?!'& \t\n\r\f");
            int n = st.countTokens();
            if (n > 0) {
                int k = new Random().nextInt(n);
                for (int i = 0; i < k; i++)
                    st.nextToken();
                keyword = st.nextToken();
            }
        }
        AdEntity ad = new AdEntity();
        ad.setKeyword(keyword);
        ad.setUrl(keyword + ".com");
        ad.setContent("Buy " + keyword + " from " + ad.getUrl());
        return ad;
    }
}

实施 Ajax-EJB 控制器

在本部分中,我将使用 JDeveloper 创建控制器 servlet。然后,我将介绍如何使用相关性注入,如何调用 EJB 的方法以及如何针对 Ajax 客户端生成响应。

创建控制器 servlet

在 Applications 导航器中,右键单击 ajaxejb 项目并单击 New。在 New Gallery 窗口的左侧面板中,展开 Web Tier 节点并选择 Servlets。然后,在该窗口的右侧面板中选择 HTTP Servlet 并单击 OK:



图 16


跳过 Create HTTP Servlet 向导的 Welcome 页面,选择 Servlet 2.4\JSP 2.0 (J2EE 1.4):



图 17


输入 AdServlet 作为 servlet 类的名称,为 servlet 类选择 ajaxejb 程序包,选择 XML 内容类型并单击 Next:



图 18


向导的下一个页面允许您配置 servlet 映射:



图 19


最后一个页面允许您输入有关请求参数的信息。在本示例中,我们将使用一个名为 userInput 的参数:



图 20


单击 Finish 生成 AdServlet 类:



图 21


现在,我们需要修改 servlet。首先,添加以下注入 AdSession bean 的行,这样我们可以在 servlet 的 doGet() 方法中访问它:

import javax.ejb.EJB;
...
public class AdServlet extends HttpServlet {

    @EJB(name="AdSession")
    private AdSession adSession;
    ...
}

在本示例中,我们希望 doGet() 方法返回一个 Ajax 响应,该响应将包含从 AdEntity 实例中提取的信息。 userInput 参数的值传递给 AdSession bean 的 selectAd() 方法。业务方法返回一个 AdEntity 实例,通过 setAttribute() 将该实例存储到请求作用域中。之后, doGet() 设置 Content-Type 和 Cache-Control 头,并包括由 AdResponse.jsp 页面生成的内容。以下是 AdServlet 类的完整源代码:

package ajaxejb;

import javax.ejb.EJB;

import java.io.IOException;

import javax.servlet.*;
import javax.servlet.http.*;

public class AdServlet extends HttpServlet {

    @EJB(name="AdSession")
    private AdSession adSession;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) 
                throws ServletException, IOException {
        String userInput = request.getParameter("userInput");
        AdEntity adEntity = adSession.selectAd(userInput);
        request.setAttribute("adEntity", adEntity);
        response.setHeader("Cache-Control", "no-cache");
        response.setContentType("text/xml");
        request.getRequestDispatcher("/AdResponse.jsp")
            .include(request, response);
    }
    
}

创建响应页面

在 Applications 导航器中,右键单击 ajaxejb 项目的 Web Content 文件夹并单击 New。在 New Gallery 窗口的左侧面板中,展开 Web Tier 节点并选择 JSP。然后,在该窗口的右侧面板中选择 JSP 并单击 OK:



图 22


跳过 Create JSP 向导的 Welcome 屏幕,输入 AdResponse.jsp 作为 JSP 页面的名称:



图 23


Create JSP 向导的下一步允许您选择一个错误处理选项:



图 24


在第三步中,您可以选择将在本页面中使用的 JSP 库。在本示例中,在左侧面板中选择 JSTL Core 1.1,使用箭头按钮将其移到右侧面板中:



图 25


第四步允许您提供其他页面选项。由于 AdResponse.jsp 页面用于生成一个 Ajax 响应,因此选择 None 作为 HTML Version 并保留 Title 为空:



图 26


单击 Finish 按钮生成 JSP 页面:



图 27


删除 JDeveloper 生成的 HTML 内容,添加以下行以产生一个链接:

<a href='<c:out value="${requestScope.adEntity.url}"/>'>
    <c:out value="${requestScope.adEntity.content}"/>
</a>

上面使用的 AdEntity 实例设置为 AdServlet 类中的一个请求属性。

修改 web.xml 文件

生成 AdServlet 类之后,JDeveloper 还创建了包含 servlet 映射信息的 web.xml 应用程序描述符:

<web-app ...>
    ...
    <servlet>
        <servlet-name>AdServlet</servlet-name>
        <servlet-class>ajaxejb.AdServlet</servlet-class>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>AdServlet</servlet-name>
        <url-pattern>/adservlet</url-pattern>
    </servlet-mapping>
    ...
</web-app>

必须将 Web 应用程序版本从 2.4 更改为 2.5,将模式文件名从 web-app_2_4.xsd 更改为 web-app_2_5.xsd,这样您才可以在 AdServlet 类中使用相关性注入:

    <web-app ...
        xsi:schemaLocation=".../web-app_2_5.xsd"
        version="2.5" ...>
      ...
    </web-app>

如果您不更改 Web 应用程序版本,EJB 将不会注入,应用程序将引发一个 NullPointerException。


使用 JSF 和 ADF Faces 构建 Ajax 客户端

在本部分中,我将创建一个 JSF 页面并将使用 JDeveloper 添加 ADF Faces 组件。之后,我将介绍如何通过传递 ADF Faces 组件的状态来调用控制器 servlet 的 JavaScript 代码。JSF 页面将使用从 Ajax 响应检索到的信息进行更新。

创建 JSF 页面

在 Applications 导航器中,右键单击 ajaxejb 项目的 Web Content 文件夹并单击 New。在 New Gallery 窗口的左侧面板中,展开 Web Tier 节点并选择 JSF。然后,在该窗口的右侧面板中选择 JSF JSP 并单击 OK:



图 28


跳过 Create JSF JSP 向导的 Welcome 屏幕,输入 AdForm.jsp 作为 JSF 页面的名称:



图 29


Create JSF JSP 向导的下一步允许您选择一个组件绑定选项:



图 30


在第三步中,您可以选择将在 JSF 页面中使用的 JSP 库。默认情况下选择 JSF Core 和 JSF HTML。在本示例中,我们还将使用 ADF Faces 组件。因此,在左侧面板中选择 ADF Faces Components 和 ADF Faces HTML,使用箭头按钮将其移到右侧面板中:



图 31


第四步允许您提供其他页面选项。在 Title 域中输入 Ajax-JSF Page:



图 32


单击 Finish 按钮生成 JSF 页面:



图 33


由于这是该应用程序的第一个 JSF 页面,因此 JDeveloper 将创建 faces-config.xml 文件并在 web.xml 文件中配置 Faces Servlet:

<web-app ...
    ...
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    ...
</web-app>

在 Structure 导航器中,右键单击 AdForm.jsp 页面的 h:form 元素并单击 Convert。在 Convert Form 对话框中,选择 ADF Faces Core 库,选择 Form 元素,然后单击 OK:



图 34


JDeveloper 将用 <af:form> 替换 <h:form> 组件。由于这是首次使用 ADF Faces,因此 JDeveloper 将自动用 <afh:html>、 <afh:head> 和 <afh:body> 替换该页面的 HTML 标记。此外,JDeveloper 还将创建 adf-faces-config.xml 文件,并在 web.xml 文件中配置 adfFaces 过滤器和 resources servlet:

<web-app ...>
    <filter>
        <filter-name>adfFaces</filter-name>
        <filter-class>
            oracle.adf.view.faces.webapp.AdfFacesFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>adfFaces</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    ...
    <servlet>
        <servlet-name>resources</servlet-name>
        <servlet-class>
            oracle.adf.view.faces.webapp.ResourceServlet
        </servlet-class>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>resources</servlet-name>
        <url-pattern>/adf/*</url-pattern>
    </servlet-mapping>
    ...
</web-app>

返回 AdForm.jsp 页面,在 Structure 导航器中右键单击 af:form 元素。然后,选择 Insert inside af:form 并单击 JSF HTML:



图 35


在 Insert JSF HTML Item 对话框中,选择 Panel Grid 并单击 OK:



图 36


跳过 Create PanelGrid 向导的 Welcome 屏幕,在 Number of Columns 域中输入 1:



图 37


单击 Finish 在 AdForm.jsp 页面的 <af:form> 元素中插入 <h:panelGrid> 组件。在 Structure 导航器中,右键单击 h:panelGrid 元素,选择 Insert inside h:panelGrid 并单击 ADF Faces Core:



图 38


在 Insert ADF Faces Core Item 对话框中,选择 InputText 并单击 OK:



图 39


JDeveloper 将在 AdForm.jsp 页面的 <h:panelGrid> 元素中插入一个 <af:inputText> 组件。使用 Property Inspector 将标签更改为 User Input,将 rows 属性更改为 4:



图 40


您还可以使用 Component Palette 插入组件。在文本编辑器中,将脱字符光标移到 <af:inputText> 元素后面,在 Component Palette 中选择 ADF Faces Core 库,并单击 Input Text 插入第二个文本域。然后,使用 Property Inspector 将标签更改为 More Input:



图 41


ADF Faces 组件通过以下属性支持部分页面显示 (PPR): autoSubmit、 partialTriggers 和 partialSubmit。如果希望在其他组件(称作触发器)的输入值更改时更新某个组件,您将使用这些属性。如果某个输入组件的 autoSubmit 属性为 true,则当该组件的值在浏览器中变化时,将提交包含的表单。必须更新的组件使用 partialTriggers 属性指定触发器组件的 ID。

您使用上面提到的属性时,ADF Faces 组件将处理通信,您不必担心 JavaScript 事件处理程序和 Ajax 回调。然而,有时您必须在浏览器中使用 JavaScript 和 XMLHttpRequest API。例如,如果您希望在用户键入时提交表单数据,或者您希望访问诸如我们的控制器 servlet 之类的资源,您需要提供自己的 JavaScript 代码。

示例应用程序包含一个名为 AdScript.js 的 JavaScript 文件。必须通过在 <f:verbatim> 组件中使用一个 <script> 元素将该文件导入到页面的头中:

<f:verbatim>
  <script src="" type="text/javascript">
  </script>
</f:verbatim>

AdScript.js 文件包含用于调用控制器 servlet 的 JavaScript 代码。用 AdResponse.jsp 生成的 Ajax 响应将插入到 AdForm.jsp 的 <div> 部分中。 <div> 元素必须包括在 <f:verbatim> 组件中:

<f:verbatim>
  <div id="ad">
  </div>
</f:verbatim>

浏览器加载完成后,表单页面需要进行一些初始化。初始化代码包含在 AdScript.js 文件的 init() 函数中。在 Structure 导航器中,选择 AdForm.jsp 的 afh:body 元素并设置 onload 属性:



图 42


JDeveloper 将修改 <afh:body> 元素:

<afh:body onload="init()">

以下是 AdForm.jsp 页面的完整源代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=windows-1252"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces" prefix="af"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/html" prefix="afh"%>
<f:view>
  <afh:html>
    <afh:head title="Ajax-JSF Page">
      <meta http-equiv="Content-Type"
            CONTENT="text/html;charset=utf-8"/>
      <f:verbatim>
        <script src="" type="text/javascript">
        </script>
      </f:verbatim>
    </afh:head>
    <afh:body onload="init()">
      <af:form>
        <h:panelGrid columns="1">
          <f:verbatim>
            <div id="ad">
            </div>
          </f:verbatim>
          <af:inputText label="User Input" rows="4"/>
          <af:inputText label="More Input"/>
        </h:panelGrid>
      </af:form>
    </afh:body>
  </afh:html>
</f:view>

以下子部分解释了 AdScript.js 文件的代码。

创建 JavaScript 文件

在 Applications 导航器中,右键单击 ajaxejb 项目的 Web Content 文件夹并单击 New。在 New Gallery 窗口的左侧面板中,展开 Web Tier 节点并选择 HTML。然后,在该窗口的右侧面板中选择 JavaScript File 项并单击 OK:



图 43


输入 AdScript.js 作为 JSF 页面的名称,并单击 OK:



图 44


JDeveloper 将创建一个空 JavaScript 文件。接下来,您需要添加将调用 Ajax-EJB 控制器的代码。首先,您需要一个用于创建 XMLHttpRequest 对象的函数。 createRequest() 函数需要三个参数:HTTP 方法、Ajax 控制器的 URL 以及回调函数。 XMLHttpRequest 对象使用其 open() 方法进行初始化,然后 createRequest() 设置 onreadystatechange 属性,该属性将包含到 XMLHttpRequest 对象每次状态更改时都会调用的回调函数的引用。最后, createRequest() 返回稍后将用于发送 Ajax 请求的对象:

function createRequest(method, url, callback) {
    var request;
    if (window.XMLHttpRequest)
        request = new XMLHttpRequest();
    else if (window.ActiveXObject)
        request = new ActiveXObject("Microsoft.XMLHTTP");
    else
        return null;

    request.open(method, url, true);

    function calbackWrapper() {
        callback(request);
    }
    request.onreadystatechange = calbackWrapper;

    return request;
}

当 XMLHttpRequest 对象状态改变时,它不会向所调用的函数传递任何参数,但回调需要该请求对象以获得 Ajax 响应。因此, createRequest() 使用一个充当实际回调的包装的内部函数,从而获得到请求对象的引用。

每个 XMLHttpRequest 对象应该用于一个 Ajax 请求,这样应用程序就可以在所有支持 Ajax 的浏览器中正常工作了。换言之,不应对多个请求重用同一个 XMLHttpRequest 对象。然而,这些对象在用于避免浏览器中的内存泄漏之后应销毁。依据我的经验,销毁 XMLHttpRequest 对象的最安全的方法是:先将其 onreadystatechange 属性设置成一个不执行任何操作的 JavaScript 函数,调用 abort() 方法,然后用 delete 释放内存:

function deleteRequest(request) {
    function doNothing() {
    }
    request.onreadystatechange = doNothing;
    request.abort();
    delete request;
}

adUpdate() 函数是传递给 createRequest() 的回调。如果该请求完成(就绪状态为 4)并且成功(状态为 200), adUpdate() 就会从请求对象的 responseText 属性获得 Ajax 响应的内容。然后, adUpdate() 将 responseText 存储到 id 为 ad 的元素的 innerHTML 属性中。这与将 Ajax 响应插入 AdForm.jsp 页面的 <div id="ad"></div> 元素中是等效的:

var debug = true;

function adUpdate(request) {
    if (request.readyState == 4) {
        if (request.status == 200) {
            var adSection = document.getElementById("ad");
            adSection.innerHTML = request.responseText;
        } else if (debug) {
            if (request.statusText)
                alert(request.statusText);
            else
                alert("HTTP Status: " + request.status);
        }
    }
}

在本文的示例应用程序中,用户的输入必须传递给 Ajax-EJB 控制器 servlet。 getUserInput() 函数获得所有文本域的值并将这些值连接起来,返回一个字符串:

function getUserInput() {
    var userInput = "";
    var forms = document.forms;
    for (var i = 0; i < forms.length; i++) {
        var elems = forms[i].elements;
        for (j = 0; j < elems.length; j++) {
            var elemType = elems[j].type.toLowerCase();
            if (elemType == "text" || elemType == "textarea") {
                var elemValue = elems[j].value;
                userInput += " " + elemValue;
            }
        }
    }
    return userInput;
}

sendAdRequest() 函数将销毁以前的 XMLHttpRequest 对象(如果有的话),将 userInput 参数添加到 URL,创建一个新的请求对象,并调用其 send() 方法向控制器 servlet 提交 Ajax 请求。URL 以 .. 开头,这是因为该 servlet 是从其 URL 包含 /faces 前缀的 JSF 页面调用的:

var adURL = "../adservlet"
var adRequest = null;

function sendAdRequest() {
    if (adRequest)
        deleteRequest(adRequest);
    var url = adURL + "?userInput=" + escape(getUserInput());
    adRequest = createRequest("GET", url, adUpdate);
    adRequest.send(null);
}

init() 函数将调用 sendAdRequest() 初始化该页面的 ad 部分。然后, setInterval() 用于指示浏览器每秒调用一次 sendAdRequest():

function init() {
    sendAdRequest();
    setInterval("sendAdRequest()", 1000);
}

运行应用程序

右键单击 Web Content 文件夹的 AdForm.jsp 页面,单击 Run。JDeveloper 将启动嵌入式 OC4J 服务器,并将在浏览器窗口中打开 JSF 页面。如果您开始在表单的一个文本域中键入信息,就会注意到 ad 每秒钟是如何变化的。

总结

在本文中,您了解了如何构建 Java 企业版 Ajax 应用程序,方法是:使用 JDeveloper 的可视化编辑器以及用于创建 EJB3 组件、Ajax-EJB 控制器 servlet 和基于 ADF Faces 的 JSF 页面的向导。您还学习了几种 Ajax 技巧,从而可以正确地管理 XMLHttpRequest 对象。


Andrei Cioroianu (devtools@devsphere.com) 是 Devsphere (www.devsphere.com) 的创始人,该公司主要提供 Java 企业版开发和 Ajax/JSF 咨询服务。Cioroianu 撰写了许多 Java 文章,分别发表在 Oracle 技术网、ONJava (www.onjava.com)、JavaWorld (www.javaworld.com) 和 Java Developer’s Journal。他还与别人合著了 Java XML Programmer's Reference 和 Professional Java XML 两书(均由 Wrox Press 出版)。