内容關鍵詞:EL 表達式、JSP 頁面、表達式語言文法、【】和.運算符、取值規則、通路java bean、el隐式對象、使用其他el運算符、引用靜态屬性和靜态方法、建立set list 和map、通路清單元素和map條目、操作集合
格式化集合、使用html注解、格式化數字、格式化日期
知識來源: 720科技(張森鵬)、Spring MVC學習指南(第2版)
JSP 2.0 最重要的特性之一就是表達式語言(EL),JSP 使用者可以用它來通路應用程式資料。由于受到 ECMAScript 和 XPath 表達式語言的啟發,EL 也設計成可以輕松地編寫免腳本的 JSP 頁面。也就是說,頁面不使用任何 JSP 聲明、表達式或者 scriptlet。
表達式語言簡史:JSP 2.0 最初是将 EL 應用在 JSP 标準标簽庫(JSTL)1.0 規範中。JSP 1.2 程式員将标準庫導入到他們的應用程式中,就可以使用EL。JSP 2.0 及其更高版本的使用者即使沒有 JSTL, 也能使用 EL,但在許多應用程式中,還是需要 JSTL 的,因為它裡面還包含了與 EL 無關的其他标簽。
JSP 2.1 和JSP 2.2 中的 EL 要将JSP 2.0 中的EL 與 JSF(JavaServer Faces)中定義的 EL 統一起來。JSF 是在 Java 中快速建構 Web 應用程式的架構,并且是建構在 JSP 1.2 之上。由于JSP 1.2 中缺乏整合式的表達式語言,并且JSP 2.0 EL 也無法滿足JSF 的所有需求,是以為JSF 1.0 開發出了一款 EL 的變體。後來這兩種語言變體合二為一。
2013 年 5 月釋出了EL 3.0 版本(JSR 341),EL 不再是 JSP 或任何其他技術的一部分,而是一個獨立的規範。EL 3.0 添加了對 lambda 表達式的支援,并允許集合操作。其 lambda 支援不需要 Java SE 8,Java SE 7 即可。
表達式語言的文法:
EL 表達式以 ${ 開頭,并以 } 結束。EL 表達式的結構如下:
${expression} #{expression}
例如,表達式 x+y,可以寫成:
${x+y}
或
#{x+y}
兩個表達式可以連接配接在一起。對于一系列的表達式,它們的取值将是從左到右進行,計算結果的類型為 String,并且連接配接在一起。假如 a+b 等于 8,c+d 等于 10,那麼這兩個表達式的計算結果将是 810:
${a+b}${c+d}
表達式${a+b}and${c+d}的取值結果則是 8and10。
如果在定制标簽的屬性值中使用 EL 表達式,那麼該表達式的取值結果字元串将會強制變成該屬性需要的類型:
<my:tag someAttribute="${expression}"/>
像${這樣的字元順序就表示是一個 EL 表達式的開頭。如果需要的隻是文本${,則需要在它前面加一個轉義符,如\${。
關鍵字:
以下是關鍵字,它們不能用作辨別符:
and eq gt trueinstanceof
or ne le false empty
not lt ge null div mod
[ ]和.運算符:
EL 表達式可以傳回任意類型的值。如果 EL 表達式的結果是一個帶有屬性的對象,則可以利用[ ]或者.運算符來通路該屬性。[ ]和.運算符類似;[ ]是比較規範的形式,.運算符則比較快捷。
為了通路對象的屬性,可以使用以下任意一種形式:
${object["propertyName"]}
${object.propertyName}
但是,如果 propertyName 不是有效的 Java 變量名,隻能使用[ ]運算符。
要想通路 accept-language 标題,隻能使用[ ]運算符,因為 accept-language 不是一個合法的Java 變量名。如果用. 運算符通路它,将會導緻異常。
如果對象的屬性碰巧傳回帶有屬性的另一個對象,既可以用[ ],也可以用. 運算符來通路第二個對象的屬性。例如,隐式對象 pageContext 是表示目前 JSP 的 PageContext 對象。它有 request 屬性,表示 HttpServletRequest。HttpServletRequest 帶有 servletPath 屬性。那麼, 下列幾個表達式的結果相同, 均能得出 pageContext 中 HttpServletRequest 的
servletPath 屬性值:
${pageContext["request"]["servletPath"]}
${pageContext.request["servletPath"]}
${pageContext.request.servletPath}
${pageContext["request"].servletPath}
要通路 HttpSession,可以使用以下文法:
${pageContext.session}
例如,以下表達式會得出 session 辨別符。
${pageContext.session.id}
取值規則:
EL 表達式的取值是從左到右進行的。對于expr-a[expr-b]形式的表達式,其 EL 表達式的取值方法如下:
(1)先計算 expr-a 得到 value-a。
(2)如果 value-a 為 null,則傳回 null。
(3)然後計算 expr-b 得到 value-b。
(4)如果 value-b 為 null,則傳回 null。
(5)如果 value-a 為 java.util.Map,則會檢視 value-b 是否為 Map 中的一個 key。若是,則傳回 value-a.get(value-b),若不是,則傳回 null。
(6)如果 value-a 為 java.util.List,或者假如它是一個 array,則要進行以下處理: a.強制 value-b 為 int,如果強制失敗,則抛出異常。
b.如果 value-a.get(value-b)抛出 IndexOutOfBoundsException,或者假如 Array.get (value-a, value-b)抛出 ArrayIndexOutOfBoundsException,則傳回 null。
c.否則,若 value-a 是個 List,則傳回 value-a.get(value-b);若 value-a 是個 array, 則傳回 Array.get(value-a, value-b)。
(7)如果 value-a 不是一個 Map、List 或者 array,那麼,value-a 必須是一個 JavaBean。在這種情況下,必須強制 value-b 為 String。如果 value-b 是 value-a 的一個可讀屬性,則要調用該屬性的 getter 方法,從中傳回值。如果 getter 方法抛出異常,該表達式就是無效的,否則, 該表達式有效。
通路JavaBean:
利用. 或[]運算符,都可以通路 bean 的屬性,其結構如下:
${beanName["propertyName"]}
${beanName.propertyName}
例如,通路 myBean 的 secret 屬性,可以使用以下表達式:
${myBean.secret}
如果該屬性是一個帶屬性的對象,那麼同樣也可以利用.或[]運算符來通路第二個對象的該屬性。假如該屬性是一個 Map、List 或者 array,則可以利用 通路 Map 值或 List 成員或 array 元素的同樣規則。
EL隐式對象:
對象 | 描述 |
pageContext | 這是目前 JSP 的 javax.servlet.jsp.PageContext |
initParam | 這是一個包含所有環境初始化參數并用參數名作為 key 的 Map |
param | 這是一個包含所有請求參數并用參數名作為 key 的 Map。每個 key 的值就是指定名稱的第一個參數值。是以,如果兩個請求參數同名,則隻有第一個能夠利用 param 擷取值。要想通路同名參數的所有參數值,可用 params 代替 |
paramValues | 這是一個包含所有請求參數并用參數名作為 key 的 Map。每個 key 的值就是一個字元串數組,其中包含了指定參數名稱的所有參數值。就算該參數隻有一個值,它也仍然會傳回一個帶有一個元素的數組 |
header | 這是一個包含請求标題并用标題名作為 key 的 Map。每個 key 的值就是指定标題名稱的第一個标題。換句話說,如果一個标題的值不止一個,則隻傳回第一個值。要想獲得多個值的标題,得用 headerValues 對象代替 |
headerValues | 這是一個包含請求标題并用标題名作為key 的Map。每個 key 的值就是一個字元串數組, 其中包含了指定标題名稱的所有參數值。就算該标題隻有一個值,它也仍然會傳回一個帶有一個元素的數組 |
cookie | 這是一個包含了目前請求對象中所有 Cookie 對象的 Map。Cookie 名稱就是 key 名稱, 并且每個 key 都映射到一個 Cookie 對象 |
applicationScope | 這是一個包含了 ServletContext 對象中所有屬性的 Map,并用屬性名稱作為 key |
sessionScope | 這是一個包含了 HttpSession 對象中所有屬性的 Map,并用屬性名稱作為 key |
requestScope | 這是一個 Map,其中包含了目前 HttpServletRequest 對象中的所有屬性,并用屬性名稱作為 key |
pageScope | 這是一個 Map,其中包含了全頁面範圍内的所有屬性。屬性名稱就是 Map 的 key |
pageContext:pageContext 對象表示目前 JSP 頁面的 javax.servlet.jsp.PageContext。
對象 | EL 中的類型 |
request | javax.servlet.http.HttpServletRequest |
response | javax.servlet.http.HttpServletResponse |
out | javax.servlet.jsp.JspWriter |
session | javax.servlet.http.HttpSession |
application | javax.servlet.ServletContext |
config | javax.servlet.ServletConfig |
PageContext | javax.servlet.jsp.PageContext |
page | javax.servlet.jsp.HttpJspPage |
exception | java.lang.Throwable |
例如,可以利用以下任意一個表達式來擷取目前的ServletRequest:
${pageContext.request}
${pageContext["request"]
并且,還可以利用以下任意一個表達式來擷取請求方法:
${pageContext["request"]["method"]}
${pageContext["request"].method}
${pageContext.request["method"]}
${pageContext.request.method}
pageContext.request中一些有用的屬性
屬性 | 說明 |
characterEncoding | 請求的字元編碼 |
contentType | 請求的 MIME 類型 |
locale | 浏覽器首先 locale |
locales | 所有 locale |
protocol | HTTP 協定,例如:HTTP/1.1 |
remoteAddr | 用戶端 IP 位址 |
remoteHost | 用戶端 IP 位址或主機名 |
scheme | 請求發送方案,HTTP 或 HTTPS |
serverName | 伺服器主機名 |
serverPort | 伺服器端口 |
secure | 請求是否通過安全連結傳輸 |
initParam:
隐式對象 initParam用于擷取上下文參數的值。例如,為了擷取名為 password 的上下文參數值,可以使用以下表達式:
${initParam.password}
或者
${initParam["password"]
param:
隐式對象 param 用于擷取請求參數值。這個對象表示一個包含所有請求參數的 Map。例如,要擷取 userName 參數,可以使用以下任意一種表達式:
${param.userName}
${param["userName"]}
paramValues:利用隐式對象 paramValues 可以擷取一個請求參數的多個值。這個對象表示一個包含所有請求參數,并以參數名稱作為 key 的 Map。每個 key 的值是一個字元串數組,其中包含了指定參數名稱的所有值。即使該參數隻有一個值,它也仍然傳回一個帶有一個元素的數組。例如, 為了獲得 selectedOptions 參數的第一個值和第二個值,可以使用以下表達式:
${paramValues.selectedOptions[0]}
${paramValues.selectedOptions[1]}
header:隐式對象 header 表示一個包含所有請求标題的 Map。為了擷取 header 值,要利用 header名稱作為 key。例如,為了擷取 accept-language 這個 header 值,可以使用以下表達式:
${header["accept-language"]}
如果 header 名稱是一個有效的Java 變量名,如 connection,那麼也可以使用.運算符:
${header.connection}
headerValues:隐式對象 headerValues 表示一個包含所有請求 head 并以 header 名稱作為 key 的 Map。但是,與 head 不同的是,隐式對象 headerValues 傳回的 Map 傳回的是一個字元串數組。例如, 為了擷取标題 accept-language 的第一個值,要使用以下表達式:
${headerValues["accept-language"][0]}
cookie:隐式對象 cookie 可以用來擷取一個 cookie。這個對象表示目前 HttpServletRequest 中所有
cookie 的值。例如,為了擷取名為 jsessionid 的 cookie 值,要使用以下表達式:
${cookie.jsessionid.value}
為了擷取 jsessionid cookie 的路徑值,要使用以下表達式:
${cookie.jsessionid.path}
applicationScope、sessionScope、requestScope 和pageScope:隐式對象 applicationScope 用于擷取應用程式範圍級變量的值。假如有一個應用程式範圍級變量 myVar,就可以利用以下表達式來擷取這個屬性:
${applicationScope.myVar}
注意,在 servlet/JSP 程式設計中,有界對象是指在以下對象中作為屬性的對象:PageContext、
ServletRequest 、HttpSession 或者 ServletContext 。隐式對象 sessionScope 、requestScope 和
pageScope 與 applicationScope 相似。但是,其範圍分别為 session、request 和 page。
有界對象也可以通過沒有範圍的 EL 表達式擷取。在這種情況下,JSP 容器将傳回
PageContext、ServletRequest、HttpSession 或者 ServletContext 中第一個同名的對象。執行順序是從最小範圍(PageContext)到最大範圍(ServletContext)。例如,以下表達式将傳回 today引用的任意範圍的對象。
${today}
使用其他EL運算符:除了.和 [] 運算符外,EL 還提供了其他運算符:算術運算符、關系運算符、邏輯運算符、條件運算符,以及 empty 運算符。使用這些運算符時,可以進行不同的運算。但是,由于 EL 的目的是友善免腳本 JSP 頁面的程式設計,是以,除了關系運算符外,這些 EL 運算符的用處都很有限。
算術運算符:算術運算符有 5 種。
加法(+)。
減法(−)。
乘法(*)。
除法(/和 div)。
取餘/取模(%和 mod)。
除法和取餘運算符都有兩種形式,與 XPath 和 ECMAScript 是一緻的。
注意,EL 表達式的計算按優先級從高到低、從左到右進行。下列運算符是按優先級遞減順序排列的:
*/div%mod
+-
這表示*、/、div、%以及 mod 運算符的優先級相同,+與−的優先級相同,但第二組運算符的優先級小于第一組運算符。是以,表達式
${1+2*3}
的運算結果是 7,而不是 9。
關系運算符:面是關系運算符清單:
等于(==和 eq)。
不等于(!=和 ne)。
大于(>和 gt)。
大于或等于(>=和 ge)。
小于(<和 lt)。
小于或等于(<=和 le)。
例如,表達式${3==4}傳回 False,${“b”<“d”}則傳回 True。
邏輯運算符:下面是邏輯運算符清單:
和(&&和 and)。
或(|| 和 or)。
非(!和 not)。
條件運算符:EL 條件運算符的文法如下:
${statement? A:B}
如果 statement 的計算結果為 True,那麼該表達式的輸出結果就是 A,否則為 B。
例如,利用下列 EL 表達式可以測試 HttpSession 中是否包含名為 loggedIn 的屬性。如果找到這個屬性,就顯示“You have logged in(您已經登入)”。否則顯示“You have not logged in
(您尚未登入)”。
${(sessionScope.loggedIn==null)? "You have not logged in" : "You have logged in"}
empty 運算符:empty 運算符用來檢查某一個值是否為 null 或者 empty。下面是一個 empty 運算符的使用範例:
${empty X}
如果X 為 null,或者說 X 是一個長度為 0 的字元串,那麼該表達式将傳回 True。如果 X
是一個空 Map、空數組或者空集合,它也将傳回 True。否則,将傳回 False。
字元串連接配接運算符:+ =運算符用于連接配接字元串。 例如,以下表達式列印 a + b 的值。
$ {a + = b}
分号操作符:操作符用于分隔兩個表達式。
引用靜态屬性和靜态方法:您可以引用在任何 Java 類中定義的靜态字段和方法。 但是,在可以在 JSP 頁面中引用靜态字段或方法之前,必須使用 page 僞指令導入類或類包。 java.lang 包是一個例外,因為它是自動導入的。
建立Set、List 和Map:可以動态的建立 Set、List 和 Map。建立一個 Set 的文法如下:
{ comma-delimited-elements }
通路清單元素和 Map 條目:可以通過索引來通路 List,如下表達傳回 Cities 的第一個元素
${cities[0]}
可以通過如下方式通路 Map
${map[key]}
操作集合:
toList:toList 方法傳回一個 List,它包含與目前流相同的成員。調用此方法的主要目的是輕松地列印或操作流元素。
toArray:與 toList 類似,但傳回一個 Java 數組。同樣,在數組中呈現元素通常是有用的,因為許多Java 方法将數組作為參數。
limit:limit方法限制流中元素的數量。如果傳遞給 limit方法的參數大于元素的數量,則傳回所有元素。
sort:此方法對流中的元素進行排序。
average:此方法傳回流中所有元素的平均值。其傳回值是一個 Optional 對象,它可能為 null。需要調用 get()擷取實際值。
sum:此方法計算流中所有元素的總和。
count:此方法傳回流中元素的數量。
min:此方法傳回流的元素中的最小值。同 average 方法一樣,其傳回值是一個Optional 對象,是以你需要調用 get 方法來擷取實際值。
max:此方法傳回流的元素中的最大值。同 average 方法一樣,其傳回值是一個 Optional 對象, 是以你需要調用 get 方法來擷取實際值。
map:此方法将流中的每個元素映射到另一個流中的另一個元素,并傳回該流。此方法接受一個 lambda 表達式。
filt:此方法根據 lambda 表達式過濾流中的所有元素,并傳回包含結果的新流。
forEach:此方法對流中的所有元素執行操作。它傳回 void。
格式化集合:
使用 HTML 注釋、使用 String.join()
格式化數字:要格式化數字,你可以再次利用EL 3.0 允許引用靜态方法的能力。String 類的 format 靜态方法可以用來格式化數字。
格式化日期:可以通過 String.format()來格式化一個 date 或 time。
相關參考材料:Spring MVC學習指南(第2版)