指示元素


JSP 指示(Directive)元素的主要目的,在於指示容器將 JSP 轉譯為 Servlet 原始碼時,一些必須遵守的資訊。指示元素的語法如下所示:

<%@ 指示類型 [屬性="值"]* %>

在 JSP 中有三種常用的指示類型:pageincludetaglib

  • page 指示類型告知容器如何轉譯目前的 JSP 網頁。
  • include 指示類型告知容器將別的 JSP 頁面包括進來進行轉譯。
  • taglib 指示類型告知容器如何轉譯這個頁面中的標籤庫(Tag Library)。

在這邊將先說明 pageinclude 指示類型的使用,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 時,必須使用 HttpServletResponsesetContentType(),呼叫方法時傳入的參數就是 contentType 的屬性值。pageEncoding 屬性則告知容器這個 JSP 網頁中的文字編碼,以及內容類型附加的 charset 設定。如果你的網頁中包括非 ASCII 編碼範圍中的字元(如中文),就要指定正確的編碼格式,才不會出現亂碼。根據 contentTypepageEncoding 屬性的設定,轉譯後的 Servlet 原始碼必須包括這行程式碼:

response.setContentType("text/html;charset=UTF8");

可以在使用 page 類型時一行一行撰寫,也可以撰寫在同一個元素之中,例如:

<%@page import="java.time.*"
         contentType="text/html" pageEncoding="UTF-8" %>

importcontentTypepageEncoding 大概是你最常用到的三個屬性。page 指示類型還有一些可以設定的屬性,以下稍微作個說明,你不一定會全部用到,大致了解有這些屬性的存在即可。

  • info

    用於設定目前 JSP 頁面的基本資訊,這個資訊最後會轉換為 Servlet 程式中使用 getServletInfo() 所取得的資訊。

  • autoFlush

    用於設定輸出串流是否要自動出清,預設是 true。如果設定為 false,而緩衝區滿了卻還沒呼叫 flush() 資料送出至客戶端,將會產生例外。

  • buffer

    用於設定至客戶端的輸出串流緩衝區大小,設定時必須指定單位,例如 buffer="16kb",預設是 8kb。

  • errorPage

    用於設定當 JSP 執行錯誤而產生例外時,該轉發哪一個頁面處理這個例外,這在之後介紹「錯誤處理」時會加以說明。

  • extends

    用來指定 JSP 網頁轉譯為 Servlet 程式之後,該繼承哪一個類別。以 Tomcat 為例,預設是繼承自 HttpJspBaseHttpJspBase 又繼承自 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>