能夠在伺服器和用戶端上運行同一段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 作為屬性名稱。