JSP 的 <jsp:setProperty>
功能有限,只能用來設定 JavaBean 的屬性。如果想要在 page
、request
、session
、application
等範圍設定一個屬性,或者想要設定 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
時,則會以 page
、request
、session
、application
的範圍尋找屬性名稱,如果在某個範圍找到屬性名稱,則在該範圍設定屬性。如果所有範圍都沒有找到屬性名稱,則會在 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"/>