JSP 指示(Directive)元素的主要目的,在於指示容器將 JSP 轉譯為 Servlet 原始碼時,一些必須遵守的資訊。指示元素的語法如下所示:
<%@ 指示類型 [屬性="值"]* %>
在 JSP 中有三種常用的指示類型:page
、include
與 taglib
。
page
指示類型告知容器如何轉譯目前的 JSP 網頁。include
指示類型告知容器將別的 JSP 頁面包括進來進行轉譯。taglib
指示類型告知容器如何轉譯這個頁面中的標籤庫(Tag Library)。
在這邊將先說明 page
與 include
指示類型的使用,taglib
則會在之後進行說明。
指示元素中可以有多對的屬性/ 值,必要時,同一個指示類型可以用數個指示元素來設定。直接以實際的例子來說明比較清楚。首先說明 page
指示類型:
<%@page import="java.time.*" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Page 指示元素</title>
</head>
<body>
<h1>現在時間: <%= LocalTime.now() %> </h1>
</body>
</html>
page
指示類型的 import
屬性告知容器轉譯 JSP 時,必須在原始碼中包括的 import
陳述,範例中的 import
屬性的在轉譯後的 Servlet 原始碼會產生:
import java.time.*;
你也可以在同一個 import
屬性中,使用逗號分隔數個 import
的內容:
<%@page import="java.time.*,cc.openhome.*" %>
page
指示類型的 contentType
屬性告知容器轉譯 JSP 時,必須使用 HttpServletResponse
的 setContentType()
,呼叫方法時傳入的參數就是 contentType
的屬性值。pageEncoding
屬性則告知容器這個 JSP 網頁中的文字編碼,以及內容類型附加的 charset
設定。如果你的網頁中包括非 ASCII 編碼範圍中的字元(如中文),就要指定正確的編碼格式,才不會出現亂碼。根據 contentType
與 pageEncoding
屬性的設定,轉譯後的 Servlet 原始碼必須包括這行程式碼:
response.setContentType("text/html;charset=UTF8");
可以在使用 page
類型時一行一行撰寫,也可以撰寫在同一個元素之中,例如:
<%@page import="java.time.*"
contentType="text/html" pageEncoding="UTF-8" %>
import
、contentType
與 pageEncoding
大概是你最常用到的三個屬性。page
指示類型還有一些可以設定的屬性,以下稍微作個說明,你不一定會全部用到,大致了解有這些屬性的存在即可。
info
用於設定目前 JSP 頁面的基本資訊,這個資訊最後會轉換為 Servlet 程式中使用
getServletInfo()
所取得的資訊。autoFlush
用於設定輸出串流是否要自動出清,預設是
true
。如果設定為false
,而緩衝區滿了卻還沒呼叫flush()
資料送出至客戶端,將會產生例外。buffer
用於設定至客戶端的輸出串流緩衝區大小,設定時必須指定單位,例如
buffer="16kb"
,預設是 8kb。errorPage
用於設定當 JSP 執行錯誤而產生例外時,該轉發哪一個頁面處理這個例外,這在之後介紹「錯誤處理」時會加以說明。
extends
用來指定 JSP 網頁轉譯為 Servlet 程式之後,該繼承哪一個類別。以 Tomcat 為例,預設是繼承自
HttpJspBase
(HttpJspBase
又繼承自HttpServlet
)。基本上你不會使用到這個屬性。isErrorPage
設定 JSP 頁面是否為處理例外的頁面,這個屬性要與
errorPage
配合使用,這在之後介紹「錯誤處理」時會加以說明。language
指定容器使用哪種語言的語法來轉譯 JSP 網頁,言下之意是 JSP 基本上可使用其它語言來轉譯,不過事實上目前只能使用 Java 的語法且是預設。
session
設定是否在轉譯後的 Servlet 原始碼中具有建立
HttpSession
物件的陳述句。預設是true
,若某些頁面不需作 Session 追蹤,設成false
可以增加一些效能。isELIgnored
設定 JSP 網頁中是否忽略運算式語言(Expression Language),預設是
false
,如果設定為true
,則不轉譯運算式語言。這個設定會覆蓋 web.xml 中的<el-ignored>
設定,運算式語言將於之後介紹。isThreadSafe
告知容器你撰寫 JSP 時是否注意到執行緒安全,預設值是
true
。如果設定為false
,則轉譯之後的 Servlet 會實作SingleThreadModel
介面,每次請求時將建立一個 Servlet 實例來服務請求,雖然可以避免執行緒安全問題,這會引起效能問題,極度不建議設定為false
。
接著介紹 include
指示類型,它用來告知容器包括另一個網頁的內容進行轉譯。直接來看個範例:
includeDemo.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@include file="/WEB-INF/jspf/header.jspf"%>
<h1>include 示範本體</h1>
<%@include file="/WEB-INF/jspf/foot.jspf"%>
上面這個程式在第一次執行時,將會把 header.jspf 與 foot.jspf 的內容包括進來作轉譯。假設這兩個檔案的內容分別是:
header.jspf
<%@ page pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>include 示範開頭</title>
</head>
<body>
foot.jspf
<%@ page pageEncoding="UTF-8" %>
</body>
</html>
實際執行時,容器會組合 includeDemo.jsp、header.jspf 與 foot.jspf 的內容後,再轉譯為 Servlet,也就是說,相當於轉譯這個 JSP:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>include 示範開頭</title>
</head>
<body>
<h1>include 示範本體</h1>
</body>
</html>
所以最後會生成一個 Servlet(而不是三個),也就是說,使用指令元素 include
來包括其它網頁內容時,會在轉譯時期就決定轉譯後的 Servlet 內容,是一種靜態的指定方式。之後會介紹 <jsp:include>
標籤的使用,則是執行時期動態將別的網頁包括進來進行回應的方式,使用 <jsp:include>
的網頁與被 <jsp:include>
包括的網頁,各自都生成一個獨立的 Servlet。
你可以在 web.xml 中統一預設的網頁編碼、內容類型、緩衝區大小等,例如:
<web-app …>
…
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF8</page-encoding>
<default-content-type>text/html</default-content-type>
<buffer>16kb</buffer>
</jsp-property-group>
</jsp-config>
</web-app>
也可以宣告指定的 JSP 開頭與結尾要包括的網頁:
<web-app …>
…
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<include-prelude>/WEB-INF/jspf/prelude1.jspf</include-prelude>
<include-coda>/WEB-INF/jspf/coda1.jspf</include-coda>
</jsp-property-group>
</jsp-config>
</web-app>
另外,注意到指示元素如果如下撰寫:
<%@page import="java.time.*" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
Hello!
則產生的HTML會是:
Hello!
因為在撰寫 JSP 指示元素時,換行了兩次,這兩次換行的字元也會輸出,一般來說這不會有什麼問題,但如果想要忽略這樣的換行,則可以在 web.xml 中設定:
<web-app …>
…
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>