屬性處理與輸出標籤


JSP 的 <jsp:setProperty> 功能有限,只能用來設定 JavaBean 的屬性。如果想要在 pagerequestsessionapplication 等範圍設定一個屬性,或者想要設定 Map 物件的鍵與值,則可以使用 <c:set> 標籤。

例如使用者登入後,想要在 session 範圍中設定一個 "login" 屬性,代表使用者已經登入,則可以如下撰寫:

<c:set var="login" value="caterpillar" scope="session"/>

var 用來設定屬性名稱,而 value 用來設定屬性值。這段標籤設定的作用,相當於:

<% session.setAttribute("login", "caterpillar"); %>

也可以使用EL來進行設定,例如:

<c:set var="login" value="${user}" scope="session"/>

如果 ${user} 運算的結果是 User 類別的實例,則儲存的屬性就是 User 物件,也就是相當於以下這段程式碼:

<%
    // user 是 User 所宣告的參考名稱,參考至 User 物件
    session.setAttribute("login", user); 
%>

<c:set> 標籤也可以將 value 的設定改為本體的方式,在所要設定的屬性值冗長時,採用本體的方式會比較容易撰寫。例如:

<c:set var="details" scope="session">
    caterpillar,openhome.cc,caterpillar.onlyfun.net
</c:set>

<c:set> 不設定 scope 時,則會以 pagerequestsessionapplication 的範圍尋找屬性名稱,如果在某個範圍找到屬性名稱,則在該範圍設定屬性。如果所有範圍都沒有找到屬性名稱,則會在 page 範圍中新增屬性。如果要移除某個屬性,則可以使用 <c:remove> 標籤。例如:

<c:remove var="login" scope="session"/>

<c:set> 也可以直接用來設定 JavaBean 的屬性或是 Map 物件的鍵╱值,要設定 JavaBean 或 Map 物件,必須使用 target 屬性進行設定。例如:

<c:set target="${user}" property="name" value="${param.name}"/>

如果 ${user} 運算出來的結果是個 JavaBean,則上例就如同呼叫 setName() 並將請求參數 name 的值傳入。如果 ${user} 運算出來的結果是個 Map,則上例就是以 property 屬性作為鍵,而 value 屬性作為值來呼叫 Map 物件的 put() 方法。

下面這個範例改寫自〈使用 HttpSession〉的問卷網頁,把 Servlet 改為 JSP 實作,並且使用 JSTL 來設置屬性:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<c:set target="${pageContext.request}" property="characterEncoding" value="UTF-8"/>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Questionnaire</title>
    </head>
    <body>
        <form action="question.jsp" method="post">
            <c:choose>
                <c:when test="${param.page == 'page1'}">
                    問題一:<input type="text" name="p1q1"><br>
                    問題二:<input type="text" name="p1q2"><br>
                    <input type="submit" name="page" value="page2">
                </c:when>
                <c:when test="${param.page == 'page2'}">
                    <c:set var="p1q1" value="${param.p1q1}" scope="session"/>
                    <c:set var="p1q2" value="${param.p1q2}" scope="session"/>
                    問題三:<input type="text" name="p2q1"><br>
                    <input type="submit" name="page" value="finish">
                </c:when>
                <c:when test="${param.page == 'finish'}">
                    ${sessionScope.p1q1}<br>
                    ${sessionScope.p1q2}<br>
                    ${param.p2q1}<br>
                </c:when>
            </c:choose>
        </form>
    </body>
</html> 

因為問卷的答案可能是用中文填寫,為了順利取得中文,必須設定 request 的字元編碼處理方式,也就是呼叫 setCharacterEncoding() 方法設定編碼。在這邊使用 ${pageContext.request} 取得 request 物件,並透過 <c:set> 來進行設定。程式中需要判斷顯示哪些問題時,則使用之前學習過的 <c:choose><c:when> 標籤。問卷過程中需儲存至 session 的答案,則使用 <c:set> 來進行設定。

再來介紹 <c:out> 物件,它可以讓你輸出指定的文字。例如:

<c:out value="${param.message}"/>

你也許會想這有什麼意思?為什麼不直接寫 ${param.message} 就好,還要加上 <c:out> 標籤,這不是多此一舉嗎?如果 ${param.message} 是來自使用者於留言版所發送的訊息,而使用者故意打了 HTML 在訊息,則 <c:out> 會自動將角括號、單引號、雙引號等字元用替代字元取代。這個功能是由 <c:out>escapeXml 屬性來控制,預設是 true,如果設定為 false,就不會作替代字元的取代。

EL 運算結果為 null 時,並不會顯示任何值,這原本是使用 EL 的好處,但如果你希望在 EL 運算結果為 null 時,可以顯示一個預設值,就目前你所學習到的 JSTL 標籤,你可能會這麼作:

<c:choose>
    <c:when test="${param.a != null}">
        ${param.a}
    </c:when>
    <c:otherwise>
        0
    </c:otherwise>
</c:choose>

如果使用 <c:out> 的話,則可以更簡潔地達到這個目的,可以使用 default 屬性設置 EL 運算結果為 null 時的預設顯示值:

<c:out value="${param.a}" defalut="0"/>