JSP 網頁會轉譯為 Servlet 類別,轉譯後的 Servlet 類別應該包括哪些類別成員、方法宣告或是哪些陳述句,在撰寫 JSP 時,可以使用宣告(Declaration)元素、Scriptlet 元素及運算式(Expression)元素來指定。
首先來看到宣告元素的語法:
<%! 類別成員宣告或方法宣告 %>
在 <%!
與 %>
之間宣告的程式碼,都將轉譯為 Servlet 中的類別成員或方法,之所以稱為宣告元素,是指它用來宣告類別成員與方法。舉個例子來說,如果在 JSP 中撰寫以下的片段:
<%!
String name = "caterpillar";
String password = "123456";
boolean checkUser(String name, String password) {
return this.name.equals(name) &&
this.password.equals(password);
}
%>
則轉譯後的 Servlet 程式碼,將會有以下的內容:
package org.apache.jsp;
// 略...
public final class index_jsp
extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
String name = "caterpillar";
String password = "123456";
boolean checkUser(String name, String password) {
return this.name.equals(name) &&
this.password.equals(password);
}
// 略….
}
所以使用 <%!
與 %>
宣告變數時,必須小心資料共用與執行緒安全的問題。先前曾經談過,容器預設會使用同一個 Servlet 實例來服務不同使用者的請求,每個請求是一個執行緒,而 <%!
與 %>
間宣告的變數對應至類別變數成員,因此會有執行緒共用存取的問題。
先前曾經提過,如果你有一些初始動作,想要在 JSP 載入時執行,則可以重新定義 jspInit()
方法,或是在 jspDestroy()
中定義結尾動作。定義 jspInit()
與 jspDestroy()
的方法,就是在 <%!
與 %>
之間進行,如此轉譯後的 Servlet 原始碼,就會有相對應的方法片段出現。例如:
<%!
public void jspInit() {
// 初始化動作
}
public void jspDestroy() {
// 結尾動作
}
%>
再來談到 Scriptlet 元素,先看看其語法:
<% Java陳述句 %>
注意到 <%
後沒有驚嘆號(!
)。在宣告元素中可以撰寫 Java 陳述句,就如同你在 Java 的方法中撰寫陳述句一樣。事實上,<%
與 %>
之間所包括的內容,將被轉譯為 Servlet 原始碼 _jspService()
方法中的內容。舉個例子來說:
<%
String name = request.getParameter("name");
String password = request.getParameter("password");
if(checkUser(name, password)) {
%>
<h1>登入成功</h1>
<%
}
else {
%>
<h1>登入失敗</h1>
<%
}
%>
這段 JSP 中的 Scriptlet,在轉譯為Servlet後,會有以下對應的原始碼:
package org.apache.jsp;
// 略...
public final class login_jsp
extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
// 略...
public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException, ServletException {
// 略…
String name = request.getParameter("name");
String password = request.getParameter("password");
if(checkUser(name, password)) {
out.write("\n");
out.write(" <h1>登入成功</h1>\n");
}
else {
out.write("\n");
out.write(" <h1>登入失敗</h1>\n");
}
// 略...
}
}
直接 JSP 中撰寫的 HTML,都會變成 out
物件所輸出的內容。Scriptlet 出現的順序,也就是在轉譯為 Servlet 後,陳述句出現在 _jspService()
中的順序。
再來談到運算式元素,其語法如下:
<%= Java運算式 %>
你可以在運算式元素中撰寫 Java 運算式,運算式的運算結果將直接輸出為網頁的一部份。例如之前看過的範例中,有使用到一段運算式元素:
現在時間: <%= LocalTime.now() %>
注意!運算式元素中不用加上分號(;
)。這個運算式元素在轉譯為 Servlet 之後,會在 _jspService()
中產生以下的陳述句:
out.print(LocalTime.now());
簡單地說,運算式元素中的運算式,會直接轉譯為 out
物件輸出時的指定內容(這也是為什麼運算式元素中不用加上分號的原因)。
下面這個範例綜合了以上的說明,實作了一個簡單的登入程式,當中使用了宣告元素、Scriptlet 元素與運算式元素。
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%!
String name = "caterpillar";
String password = "123456";
boolean checkUser(String name, String password) {
return this.name.equals(name) &&
this.password.equals(password);
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登入頁面</title>
</head>
<body>
<%
String name = request.getParameter("name");
String password = request.getParameter("password");
if(checkUser(name, password)) {
%>
<h1><%= name %> 登入成功</h1>
<%
} else {
%>
<h1>登入失敗</h1>
<%
}
%>
</body>
</html>
如果請求參數驗證無誤就會顯示使用者名稱及登入成功的字樣,否則顯示登入失敗。
<%
與 %>
用來在 JSP 中會用來作為一些元素的開頭與結尾符號,如果你要在 JSP 網頁中輸出 <%
符號或 %>
符號,不能直接寫下 <%
或 %>
,以免轉譯時被誤為是某個元素的起始或結尾符號。例如若 JSP 網頁中包括下面這段,就會發生錯誤:
<%
out.println("JSP 中 Java 語法結束符號 %>");
%>
如果你要在 JSP 中輸出 <%
或 %>
符號,要將角括號置換為替代字元。例如想輸出 <%
時可使用 <%
;而輸出 %>
時,可以使用 %>
或使用 %\>
。例如:
<%
out.println("<%與%\>被用來作為 JSP 中 Java 語法的部份");
%>
如果您想禁用 JSP 上的 Scriptlet,則可以在 web.xml 中設定:
<web-app …>
…
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
</web-app>
會想禁用 Scriptlet 的情況,是在你不想讓 Java 程式碼與 HTML 標記混合的時候,一個網頁經由適當的規畫,切割商務邏輯與呈現邏輯的話,JSP網頁可以藉由標準標籤、EL 或 JSTL 自訂標籤等,徹底消除網頁上的 Scriptlet。