JavaScript EE,第 3 部分: 结合使用 Java Scripting API 和 JSP

构建可以在 Web 服务器或 Web 浏览器中运行的 JavaScript 代码

在本系列文章的前两个部分中,我们介绍了如何在服务器上运行 JavaScript 文件,以及如何使用 Ajax 调用远程 JavaScript 函数。本文介绍如何使用服务器端 JavaScript 代码和 Java™Server Pages (JSP) 技术,以及如何构建在 Web 浏览器中禁用 JavaScript 时仍然能使用的 Asynchronous JavaScript and XML (Ajax) 用户界面。本文的样例代码包含一个小型 JSP 标记库,您可以在自己的应用程序和动态 Web 表单中重用它们。Web 表单可以使用能够在 Web 服务器和 Web 浏览器中执行的一段 JavaScript 代码生成。

Andrei Cioroianu, 高级 Java 开发人员和顾问, Devsphere

Andrei Cioroianu 是 Devsphere 公司的创始人,该公司专门提供 Java EE 开发和 Web 2.0/Ajax 顾问服务。他自 1997 年就开始使用 Java 和 Web 技术,具有 10 多年解决复杂技术问题和管理商业产品的整个生命周期以及定制应用程序和开源框架的专业经验。您可以通过 www.devsphere.com 上的联系列表与 Andrei 联系。



2009 年 7 月 30 日

能够在服务器和客户端上运行同一段 JavaScript 代码有明显的优势;它使您能够对 Ajax 和非 Ajax 客户端使用同一个代码库,并且还能提供更多的灵活性。例如,如果您开发了一些不想让其他人查看的 JavaScript 代码,那么可以在服务器上运行它,这样可以保护您的知识产权并最小化安全风险。如果以后您不再注重代码保护,则可以将 JavaScript 代码移动到客户端,以提高应用程序性能。

页面上下文和脚本上下文

Java Scripting API 和 JavaServer Pages 是两个相互独立并且可以轻松集成的 Java 技术。它们都可以在定义良好的上下文中执行代码。使用 JSP 技术,您可以访问一组 JSP 隐式对象:pageContextpagerequestresponseoutsessionconfigapplication。在 第 1 部分 中,您已经了解了如何将这些对象导入 servlet 可以执行的 JavaScript 文件。在本文中,您将了解如何对 JSP 页面可以执行的代码应用这些操作。

JavaScript 引擎使用不同类型的上下文维护应用程序代码中定义的脚本变量和函数。如果您运行设置变量或包含函数的脚本,以及在同一个上下文中执行的后续脚本,那么可以使用前一个脚本的变量和函数。因此,在处理 HTTP 请求时,应该使用单个脚本上下文,如下一节中所示。

使用 JavaScript 语言编写的脚本可以访问公共字段并调用任何 Java 对象。此外,您可以使用 object.property 语法(而不是使用 get 和 set 方法)获取和修改 JavaBean 属性的值。因为在 JavaScript 代码中使用 Java 对象很容易,唯一缺失的是一组在 JSP 页面上下文和 JavaScript 上下文之间交换对象的定制标记。从本文中可以看到,只需几行代码就可以实现它们。

在 Web 页面中使用服务器端 JavaScript 代码

本节展示如何在整个 Ajax/HTTP 请求中管理 JavaScript 上下文,以及如何在 JSP 页面上下文和 JavaScript 上下文之间交换变量。

在 JavaScript 中使用 JSP 对象

本系列的第 1 部分展示了基于 Java Scripting API 的 Java servlet,Java Scripting API 可以用来在服务器上执行 JavaScript 文件。本节描述一个名为 JSUtil 的类,该类在执行 JSP 页面时使用相同的 Java Scripting API 运行 JavaScript 代码片段。首先,您需要创建一个 ScriptEngineManager 对象,然后获取 ScriptEngine 实例,如清单 1 中所示。

清单 1. JSUtil 的 getScriptEngine() 方法
package jsee.util;

import javax.script.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.io.*;

public class JSUtil {
    private static ScriptEngine engine;
    
    public static synchronized ScriptEngine getScriptEngine() {
        if (engine == null) {
            ScriptEngineManager manager = new ScriptEngineManager();
            engine = manager.getEngineByName("JavaScript");
        }
        return engine;
    }
    ...
}

清单 2 包含 createScriptContext() 方法,该方法初始化 ScriptContext 实例,从页面上下文获取 JSP 隐式对象并作为脚本上下文的变量设置这些对象。该操作允许通过在脚本上下文中执行的 JavaScript 代码访问隐式对象:

  • pageContext 对象是用于页面范围变量的存储库,它包含获取所有其他隐式对象的方法。
  • page 对象是处理当前请求的 servlet 类实例。
  • request 对象允许您获取 HTTP 请求参数和请求头。
  • response 对象允许您设置 HTTP 响应头并提供一个写入程序,该程序使用 JSP 代码中的 out 标识。
  • out 对象用于 JSP 页面的输出。
  • session 对象维护请求之间与用户相关的状态。
  • config 对象表示使用 JSP 的 servlet 的配置。
  • application 对象用于存储所有用户共享的 bean 实例,并获取 Web.xml 文件中指定的初始化参数。
清单 2. JSUtil 的 createScriptContext() 方法
public class JSUtil {
    ...
    public static ScriptContext createScriptContext(PageContext pageContext) {
        ScriptContext scriptContext = new SimpleScriptContext();
        int scope = ScriptContext.ENGINE_SCOPE;
        scriptContext.setAttribute("pageContext", pageContext, scope);
        scriptContext.setAttribute("page", pageContext.getPage(), scope);
        scriptContext.setAttribute("request", pageContext.getRequest(), scope);
        scriptContext.setAttribute("response", pageContext.getResponse(), scope);
        scriptContext.setAttribute("out", pageContext.getOut(), scope);
        scriptContext.setAttribute("session", pageContext.getSession(), scope);
        scriptContext.setAttribute("config", pageContext.getServletConfig(), scope);
        scriptContext.setAttribute("application",
                pageContext.getServletContext(), scope);
        scriptContext.setWriter(pageContext.getOut());
        return scriptContext;
    }
    ...
}

在处理 HTTP 请求的过程中,您需要使用一个脚本上下文,以便 JavaScript 片段能够使用上次执行的脚本中定义的变量和函数。满足该请求的简单方式是将脚本上下文存储为 request 对象的属性。getScriptContext() 方法(见清单 3)使用 jsee.ScriptContext 作为属性名称。

清单 3. JSUtil 的 getScriptContext() 方法
public class JSUtil {
    ...
    public static ScriptContext getScriptContext(PageContext pageContext)
            throws IOException {
        ServletRequest request = pageContext.getRequest();
        synchronized (request) {
            ScriptContext scriptContext
                = (ScriptContext) request.getAttribute("jsee.ScriptContext");
            if (scriptContext == null) {
                scriptContext = createScriptContext(pageContext);
                request.setAttribute("jsee.ScriptContext", scriptContext);
            }
            return scriptContext;
        }
    }
    ...
}

runScript() 方法(见清单 4)在当前 HTTP 请求的上下文中执行给定的 JavaScript 片段,它使用脚本引擎中的 eval() 方法。如果抛出脚本异常,runScript() 将输出源代码,其后是堆栈跟踪,然后抛出 ServletException 终止执行 JSP 页面。

清单 4. JSUtil 的 runScript() 方法
public class JSUtil {
    ...
    public static void runScript(String source, PageContext pageContext)
            throws ServletException, IOException {
        try {
            getScriptEngine().eval(source, getScriptContext(pageContext));
        } catch (ScriptException x) {
            ((HttpServletResponse) pageContext.getResponse()).setStatus(500);
            PrintWriter out = new PrintWriter(pageContext.getOut());
            out.println("<pre>" + source + "</pre>");
            out.println("<pre>");
            x.printStackTrace(out);
            out.println("</pre>");
            out.flush();
            throw new ServletException(x);
        }
    }

}

使用定制标记执行 JavaScript 代码片段

script.tag 文件(见清单 5)允许您在服务器或客户端(具体取决于 runat 属性的值)执行 JavaScript 代码片段。如果 runatclientboth,那么标记文件将输出一个 HTML <script> 元素,该元素中包含可以放在 Web 页面内 <js:script></js:script> 之间的代码。如果 runat 属性是 serverboth,那么将以 JSP 变量(名为 source)的形式获取 JavaScript 代码片段,该变量的值将传递给 JSUtil 类的 runScript()

清单 5. script.tag 文件
<%@ attribute name="runat" required="true" rtexprvalue="true" %>
<%@ tag body-content="scriptless" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:if test="${runat == 'client' or runat == 'both'}">
    <script type="text/javascript">
        <jsp:doBody/>
    </script>
</c:if>

<c:if test="${runat == 'server' or runat == 'both'}">
    <jsp:doBody var="source"/>
    <%
        jsee.util.JSUtil.runScript(
                (String) jspContext.getAttribute("source"),
                (PageContext) jspContext);
    %>
</c:if>

理解 <js:script> 标记工作方式的最简单方法是查看示例。清单 6 包含 ScriptDemo.jsp 页面,该页面定义一个名为 link() 的函数,该函数返回 <a> 元素。该函数在 Web 服务器和 Web 浏览器中执行,因为 runat 属性是 both

在服务器端处理 JSP 页面时,println(link(request.requestURL)) 调用向当前页面输出一个链接。request 对象可以通过服务器上的 JavaScript 代码访问,因为上下文初始化由 JSUtil 类执行,而该类的 runScript() 方法可以通过标记文件调用。当 JavaScript 引擎计算 request.requestURL 表达式时,它实际上调用 HttpServletRequest 实例的 getRequestURL() 方法。

在客户端,document.writeln(link(location)) 调用将向 ScriptDemo.jsp 页面输出另一个链接,该页面的 URL 可从 location 属性中获取,该属性仅在 Web 浏览器中可用。

清单 6. ScriptDemo.jsp 示例
<%@ taglib prefix="js" tagdir="/Web-INF/tags/js" %>

<js:script runat="both">
    function link(url) {
        return '<a href="' + url + '">' + url + '</a>';
    }
</js:script>

<js:script runat="server">
    println(link(request.requestURL));
</js:script>

<br>

<js:script runat="client">
    document.writeln(link(location));
</js:script>

清单 7 显示了 ScriptDemo.jsp 页面生成的 HTML 输出,该页面包含 link() 函数、服务器端生成的 <a> 元素,以及在客户端上生成第二个链接的 JavaScript 代码。

清单 7. ScriptDemo.jsp 生成的输出
<script type="text/javascript">
    function link(url) {
        return '<a href="' + url + '">' + url + '</a>';
    }
</script>
    
<a href="http://localhost:8080/jsee/ScriptDemo.jsp">
http://localhost:8080/jsee/ScriptDemo.jsp</a>

<br>

<script type="text/javascript">
    document.writeln(link(location));
</script>

获取并设置变量

在 Web 页面中使用服务器端的 JavaScript 代码时,您需要在 JSP 上下文和脚本上下文之间交换变量。get.tag 文件(见清单 8)实现名为 <js:get> 的定制标记,该标记导出一个脚本变量作为 JSP 变量,该变量的名称通过 var 属性提供。

变量名称可以通过 JSP 上下文获取,因为它作为 JSP 属性传递到标记文件。通过脚本上下文的 getAttribute() 方法检索脚本变量的值。然后,通过 jspContext.setAttribute() 在标记文件的页面范围内创建一个名为 varAlias 的 JSP 变量。在标记文件中使用的 <%@variable%> 指令指示 JSP 容器(例如,Tomcat)向调用标记文件的页面输出 varAlias 变量,并使用 var 属性指定的变量名称。该技术允许调用的标记文件能使用 <js:get> 标记定义 page 范围内中的 JSP 变量。

清单 8. get.tag 文件
<%@ attribute name="var" required="true" rtexprvalue="false" %>
<%@ variable name-from-attribute="var" alias="varAlias" scope="AT_END"
    variable-class="java.lang.Object" %>
<%@ tag body-content="empty" %>

<%
    String var = (String) jspContext.getAttribute("var");
    Object value = jsee.util.JSUtil.getScriptContext(
            (PageContext) jspContext).getAttribute(var);
    jspContext.setAttribute("varAlias", value);
%>

<js:set> 标记使用 set.tag 文件(见清单 9)实现,该文件带有两个变量,用于使用脚本上下文的 setAttribute() 方法设置 JavaScript 变量。如果没有提供可选的 value 属性,那么标记文件将使用 <jsp:doBody var="value"/> 执行 JSP 页面中 <js:set></js:set> 之间的代码。

清单 9. set.tag 文件
<%@ attribute name="var" required="true" rtexprvalue="false" %>
<%@ attribute name="value" required="false" rtexprvalue="true"
    type="java.lang.Object"%>
<%@ tag body-content="scriptless" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:if test="${empty value}">
    <jsp:doBody var="value"/>
</c:if>

<%
    String var = (String) jspContext.getAttribute("var");
    Object value = jspContext.getAttribute("value");
    jsee.util.JSUtil.getScriptContext((PageContext) jspContext)
        .setAttribute(var, value, javax.script.ScriptContext.ENGINE_SCOPE);
%>

清单 10 包含的 VarDemo.jsp 样例使用 <js:set> 标记初始化两个脚本变量,借助 <js:script> 可以在在服务器上执行的 JavaScript 代码片段中修改这两个变量。然后,可以使用 <js:get> 标记包含两个变量的值,它们也包含在页面输出中且带有 JSTL 的 <c:out> 标记。

清单 10. VarDemo.jsp 样例
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="js" tagdir="/Web-INF/tags/js" %>

<js:set var="x" value="1"/>
<js:set var="y">2</js:set>

<js:script runat="server">
    x++;
    y--;
</js:script>

<js:get var="x"/>
<js:get var="y"/>

<c:out value="x = ${x}"/> <br>
<c:out value="y = ${y}"/>

构建可在浏览器中运行的 Ajax UI

本节展示一个基于 Ajax 和 DHTML 的动态表单。如果在 Web 浏览器中禁用了 JavaScript,只要在服务器端运行脚本化代码,DynamicForm.jsp 页面生成的用户界面仍然可以正常运行。可以使用名为 BackendScript.jss 的服务器端 JavaScript 文件处理提交的表单数据。

为了代码易于理解,这里使用一个很简单的表单。本例的主要目的是演示几种可以在实际的复杂应用程序中使用的 Web 技术。

开发动态表单

图 1 中的屏幕截屏展示了样例表单,该表单包含许多输入字段和三个按钮,按钮标签分别为 Add、Remove 和 Send。Add 按钮将新的输入字段附加到表单,Remove 按钮删除上一个字段,Send 向服务器提交表单数据。

图 1. 简单的动态表单
展示三个变量输入字段以及 Add、Remove 和 Send 按钮的屏幕截图

当在服务器上执行 DynamicForm.jsp 时,名为 outputForm() 的 JavaScript 函数生成初始输入字段。如清单 11 所示,这些字段都放入 <div> 元素,元素内容可以使用 updateForm() 函数进行修改,当用户单击 Add 或 Remove 时,将在 Web 浏览器中调用该函数。用户单击 Send 时,用户输入将使用 submitForm() 函数(该函数使用 XMLHttpRequest)提交到服务器。

如果禁用 JavaScript,那么用户按钮按钮时将不调用任何函数,在这种情况下,Web 浏览器将数据发送到服务器。启用 JavaScript 时不会发生这种情况,因为 updateForm()submitForm() 函数就返回 false

清单 11. DynamicForm.jsp 表单
<html>
<head>
<title>Dynamic Form</title>
    ...
</head>
<body>
    <b>Dynamic Form</b><br>
    <form name="dynamicForm" method="POST" action="DynamicForm.jsp">
        <div id="inputDiv">
            <js:script runat="server">
                outputForm();
            </js:script>
        </div>
        <input type="submit" name="add" value="Add"
                onclick="return updateForm('add')">
        <input type="submit" name="remove" value="Remove"
                onclick="return updateForm('remove')">
        <input type="submit" name="send" value="Send"
                onclick="return submitForm()">
    </form>
</body>
</html>

DynamicForm.jsp 页面包含几个可以在 Web 服务器或 Web 浏览器中运行的函数。htmlEncode()buildInput() 例程(见清单 12)用于生成一个 <input> 元素。

清单 12. DynamicForm.jsp 的 htmlEncode() 和 buildInput() 函数
<%@ taglib prefix="js" tagdir="/Web-INF/tags/js" %>
...
<js:script runat="both">
    function htmlEncode(value) {
        return value ? value.replace(/&/g, "&amp;").replace(/"/g, "&quot;")
            .replace(/</g, "&lt;").replace(/>/g, "&gt;") : "";
    }

    function buildInput(name, value) {
        var content = '<input type="text"';
        if (name)
            content += ' name="' + htmlEncode(name) + '"';
        if (value)
            content += ' value="' + htmlEncode(value) + '"';
        content += ' size="30">';
        return content;
    }
    ...
</js:script>

buildForm() 函数(见清单 13)带有两个参数:一列值和一个命令。当给定命令是 remove 时,将忽略上一个值。如果 cmd 参数为 add,则在返回的 HTML 字符串的尾部添加一个空字段。

清单 13. DynamicForm.jsp 的 buildForm() 函数
<js:script runat="both">
    ...
    function buildForm(values, cmd) {
        var n = values.length;
        if (cmd == 'remove' && n > 1)
            n--;
        var content = '';
        for (var i = 0; i < n; i++)
            content += buildInput("inputField", String(values[i])) + '<br>';
        if (cmd == 'add')
            content += buildInput("inputField") + '<br>';
        return content;
    }
</js:script>

实现服务器端代码

DynamicForm.jsp 页面还包含两个只能在 Web 服务器执行的 JavaScript 函数。清单 14 展示了 getInputValues() 例程,如果 HTTP 方法为 POST,则该例程返回 inputField 参数的值。

清单 14. DynamicForm.jsp 的 getInputValues() 函数
<js:script runat="server">
    function getInputValues() {
        if (request.getMethod().toUpperCase().equals("POST"))
            return request.getParameterValues("inputField");
        else
            return null;
    }
    ...
</js:script>

另一个服务器端函数是 outputForm()(见清单 15)。如上文所述,如果用户单击按钮时禁用了 JavaScript,那么 Web 浏览器则将表单数据提交到服务器。在这种情况下,outputForm() 检测单击的是哪个按钮并设置 cmd 变量。

如果命令是 send,则 DynamicForm.jsp 页面包含名为 BackendScript.jss 的脚本的输出,该脚本由 JSServlet 类执行,我们已经在本系列的第一部分介绍过该类。该脚本返回一列使用 JSON 格式编码的值。

BackendScript.jss 的输出将成为服务器端执行的 JavaScript 代码片段的一部分,因为 <jsp:include page="BackendScript.jss"/> 放在 <js:script runat="server"></js:script> 之间。

最后,outputForm() 函数生成一列带有 buildForm() 的 HTML 输入字段,并打印生成的字符串。

清单 15. DynamicForm.jsp 的 outputForm() 函数
<js:script runat="server">
    ...
    function outputForm() {
        var cmd = "";
        if (request.getParameter("add") != null)
            cmd = "add";
        else if (request.getParameter("remove") != null)
            cmd = "remove";
        else if (request.getParameter("send") != null)
            cmd = "send";
        var values = null;
        if (cmd == "send") {
            values = <jsp:include page="BackendScript.jss"/>;
        } else {
            values = getInputValues();
            if (!values)
                values = ["", "", ""]; // default input values
        }
        println(buildForm(values, cmd));
    }
</js:script>

清单 16 展示了 BackendScript.jss,该文件使用 paramValues.inputField 获取输入值并存储数组,然后使用 toSource() 将其转换为 JSON。正如本系列第 1 部分解释的那样,使用由 JSServlet 执行的 init.jss 脚本的请求参数值初始化 paramValues 变量。

清单 16. BackendScript.jss 文件
var values = paramValues.inputField;
if (values)
    println(values.sort().toSource());
else
    println("[]");

在客户端使用 JavaScript

DynamicForm.jsp 页面包含几个只在 Web 浏览器中运行的例程。getInputValues() 函数(见清单 17)使用 document.forms.dynamicForm.inputField 表达式获取表示输入字段的 DOM 对象数组。如果只有一个输入字段,那么该表达式可以返回一个 DOM 对象。因此,getInputValues() 验证 fields 是否是一个数组 —— 通过测试 length 属性的可用性来实现。输入字段的值作为字符串数组返回。

清单 17. DynamicForm.jsp 的 getInputValues() 函数
<js:script runat="client">
    function getInputValues() {
        var values = new Array();
        var fields = document.forms.dynamicForm.inputField;
        if (typeof fields.length == "number")
            for (var i = 0; i < fields.length; i++)
                values[i] = fields[i].value;
        else if (fields)
            values[0] = fields.value;
        return values;
    }
    ...
</js:script>

setInputValues() 函数(见清单 18)设置表单输入字段的值。调用该函数之后,用户将在 Web 浏览器中看到新值。

清单 18. DynamicForm.jsp 的 setInputValues() 函数
<js:script runat="client">
    ...
    function setInputValues(values) {
        var fields = document.forms.dynamicForm.inputField;
        if (typeof fields.length == "number")
        for (var i = 0; i < fields.length; i++)
            fields[i].value = values[i];
        else if (fields)
            fields.value = values[0];
    }
    ...
</js:script>

用户单击 Add 或 Remove 时,Web 浏览器将调用 updateForm() 函数(见清单 19),该函数使用这些按钮的 onclick 属性。使用 buildForm() 函数生成输入字段列表,该函数保留字段的当前值,新的 HTML 内容通过 inputDiv 元素的 innerHTML 属性插入到 Web 页面中。

清单 19. DynamicForm.jsp 的 updateForm() 函数
<js:script runat="client">
    ...
    function updateForm(cmd) {
        document.getElementById('inputDiv').innerHTML
            = buildForm(getInputValues(), cmd);
        return false;
    }
    ...
</js:script>

如果启用 JavaScript,那么当用户单击 onclick 属性包含 return submitForm() 的 Send 按钮时,Web 浏览器将调用 submitForm() 函数(见清单 20)。该 JavaScript 函数使用本系列第二部分使用的小型 Ajax 库。您可以在 xhr.js 文件中找到这个库的源代码。

在 DynamicForm.jsp 页面,创建了一个 XHR 对象并存储在 xhr 变量中。XHR() 构造器带有三个参数:

  • HTTP 方法,本例中为 POST
  • HTTP 请求的 URL,为 BackendScript.jss
  • 指示请求是否同步的布尔值参数。本例中是同步的,这意味着函数在返回控件之前等待 HTTP 响应。
清单 20. DynamicForm.jsp 的 submitForm() 函数
<script src="xhr.js" type="text/javascript">
</script>
...
<js:script runat="client">
    ...
    var xhr = new XHR("POST", "BackendScript.jss", false);

    function submitForm() {
        var request = xhr.newRequest();
        if (!request)
            return true;
        var values = getInputValues();
        for (var i = 0; i < values.length; i++)
            xhr.addParam("inputField", values[i]);
        function processResponse() {
            if (xhr.isCompleted()) {
                var newValues = eval(request.responseText);
                setInputValues(newValues);
            }
        }
        xhr.sendRequest(processResponse);
        return false;
    }
</js:script>

submitForm() 函数使用 xhr.newRequest() 创建新的 XMLHttpRequest 实例。如果无法创建该对象(即 Web 浏览器不支持 Ajax),那么 submitForm() 将返回 true,因此 Send 按钮的 onclick 表达式可以返回 true,这意味着 Web 浏览器将把表单数据提交到服务器。

如果成功创建了新的 XMLHttpRequest 对象,则下一步是获取输入字段的值,在 xhr.addParam() 的帮助下,该字段值将作为请求参数添加。

processResponse() 内部函数可以用作一个回调。如果 HTTP 请求完成且状态代码为 200,则计算文本响应,并且将获得的数组传递到 setInputValues() 函数,该函数将更新输入字段的值。

xhr.sendRequest() 调用将调用 XMLHttpRequest 实例的 send() 方法。然后,submitForm() 返回 false,因此 Send 按钮的 onclick 表达式返回 false,指示 Web 浏览器不要将表单数据提交到服务器。该行为是正确的,因为在启用 JavaScript 时使用 XMLHttpRequest 发送输入值,浏览器不应该重复提交相同的数据。

结束语

在本文中,您学习了如何运行嵌入到 JSP 页面的服务器端 JavaScript 代码,以及如何在 JSP 页面上下文和 JavaScript 上下文之间交换变量。您还学习了如何构建一个在 Web 浏览器禁用 JavaScrip 时仍然能够运行的 Ajax 用户界面。当应用程序必须支持除 Ajax Web 浏览器之外的非 Ajax 客户端设备时,同样可以使用本文介绍的技术。


下载

描述名字大小
本文的示例应用程序jsee_part3_src.zip26KB

参考资料

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, Java technology
ArticleID=417402
ArticleTitle=JavaScript EE,第 3 部分: 结合使用 Java Scripting API 和 JSP
publish-date=07302009