能够在服务器和客户端上运行同一段JavaScript代码有明显的优势;它使您能够对Ajax和非Ajax客户端使用同一个代码库,并且还能提供更多的灵活性。例如,如果您开发了一些不想让其他人查看的JavaScript代码,那么可以在服务器上运行它,这样可以保护您的知识产权并最小化安全风险。如果以后您不再注重代码保护,则可以将JavaScript代码移动到客户端,以提高应用程序性能。
页面上下文和脚本上下文
Java Scripting API和JavaServer Pages 是两个相互独立并且可以轻松集成的Java 技术。它们都可以在定义良好的上下文中执行代码。使用JSP技术,您可以访问一组JSP隐式对象:pageContext、page、request、response、out、session、config和application。在第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 作为属性名称。