|
第五章 EL ( Language )
簡介:
EL 全名為 Language ,JSP2.0 之后,EL 成為了標(biāo)準(zhǔn)規(guī)范。因此,只要是支持Servlet2.4/JSP2.0 的容器,就都可以在JSP 網(wǎng)頁中直接使用EL 。
除了JSP2.0 建議使用EL 之外,JavaServer Faces(JSF) 也將EL 納入規(guī)范,由此可知,EL 如今已經(jīng)是一項(xiàng)成熟、標(biāo)準(zhǔn)的技術(shù)。
注意:
假若您所用的容器只支持 Servlet2.3/JSP1.2 ,如: Tomcat4.1.29 ,您就不能在 JSP 網(wǎng)頁中直接使用 EL ,必須安裝支持 Servlet2.4/JSP2.0 的容器。
范例:
執(zhí)行后的結(jié)果:
第一節(jié) EL 語法
EL語法簡單,使用方便。EL主要的語法結(jié)構(gòu)如下:
所有EL都是以${為起始、以}為結(jié)尾的。上述EL范例的意思是:從Session的范圍中,取得用戶的性別。假如依照之前JSP的寫法如下:
兩者相比較之下,可以發(fā)現(xiàn)EL 的語法比傳統(tǒng)JSP 更為方便、簡潔。
第二節(jié) . 與[]運(yùn)算符
EL提供.和[]兩種運(yùn)算符來存取數(shù)據(jù)。下列兩者所代表的意思是一樣的:
等于
.和[]也可以同時(shí)混合使用,如下:
不過,以下兩種情況,兩者會(huì)有差異:
(1)當(dāng)要存取的屬性名稱中包含一些特殊字符,如.或-等非字母或數(shù)字的符號(hào),就一定要使用[],例如:
上述是不正確的方式,應(yīng)當(dāng)改為:
(2)我們考慮下列情況:
此時(shí),data是一個(gè)變量,假如data的值為“sex”時(shí),那上述的例子等于${sessionScope.user.sex};因此,如果要?jiǎng)討B(tài)取值時(shí),就可以用上述的方法來做,但.無法做到動(dòng)態(tài)取值。
接下來,我們詳細(xì)地討論一些情況。假設(shè)有一個(gè)EL:
(1)當(dāng)expr-a的值為null時(shí),它會(huì)回傳null。
(2)當(dāng)expr-b的值為null時(shí),它會(huì)回傳null。
(3)當(dāng)expr-a的值為Map類型時(shí):
l 假若!value-a.containsKey(value-b)為真,則回傳null。
l 否則回傳value-a.get(value-b)。
(4)當(dāng)expr-a的值為List或array類型時(shí):
l 將value-b的值強(qiáng)制轉(zhuǎn)型為int,假若不能轉(zhuǎn)型為int時(shí),會(huì)產(chǎn)生error。
l 假若value-a.get(value-b)或Array.get(value-a,value-b)產(chǎn)生ArrayIndexOutOfBoundsException或IndexOutOfBoundsException時(shí),則回傳null。
l 假若value-a.get(value-b)或Array.get(value-a,value-b)產(chǎn)生其他的異常時(shí),則會(huì)產(chǎn)生error。
l 最后都沒有任何異常產(chǎn)生時(shí),回傳value-a.get(value-b)或Array.get(value-a,value-b)。
(5)當(dāng)expr-a的值為JavaBean對象時(shí):
l 將value-b的值強(qiáng)制轉(zhuǎn)型為String。
l 假若 getter產(chǎn)生異常時(shí),則會(huì)產(chǎn)生error。若沒有異常產(chǎn)生時(shí),則回傳getter的結(jié)果。
第三節(jié) EL 變量
EL存取變量數(shù)據(jù)的方法很簡單,例如:${username}。它的意思是取出某一范圍中名稱為username的變量。因?yàn)槲覀儾]有指定哪一個(gè)范圍的username,所以它的默認(rèn)值會(huì)先從Page范圍找,假如找不到,再依序到Request、Session、Application范圍。假如途中找到username,就直接回傳,不再繼續(xù)找下去,但是假如全部的范圍都沒有找到時(shí),就回傳null。
自動(dòng)搜索順序
我們也可以指定要取出哪一個(gè)范圍的變量。
范例:
執(zhí)行后的結(jié)果:
第四節(jié) 自動(dòng)轉(zhuǎn)變類型
EL除了提供方便存取變量的語法之外,它另外一個(gè)方便的功能就是:自動(dòng)轉(zhuǎn)變類型。
假若窗體傳來count的值為10時(shí),那么上面的結(jié)果為30。在JSP1.2之中不能這樣做,原因是從窗體所傳過來的值,它們的類型一律是 String,所以當(dāng)你接收之后,必須再將它轉(zhuǎn)為其他類型,如:int、float等等,然后才能執(zhí)行一些數(shù)學(xué)運(yùn)算,下面是之前的做法:
接下來再詳細(xì)說明EL類型轉(zhuǎn)換的規(guī)則:
(1)將A轉(zhuǎn)為String類型
l 假若A為String時(shí):回傳A
l 否則,當(dāng)A為null時(shí):回傳””
l 否則,當(dāng)A.toString()產(chǎn)生異常時(shí):錯(cuò)誤!
l 否則,回傳A.toString()
(2)將A轉(zhuǎn)為Number類型的N
l 假若A為null或”” 時(shí):回傳0
l 假若A為Character時(shí):將A轉(zhuǎn)為new Short((short)a.charValue())
l 假若A為Boolean時(shí):錯(cuò)誤!
l 假若A為Number類型和N一樣時(shí):回傳A
l 假若A為Number時(shí):
假若N是BigInteger時(shí):
假若A為BigDecimal時(shí):回傳A.toBigInteger()
否則,回傳BigInteger.ValueOf(A.longValue)
假若N是BigDecimal時(shí):
假若A為BigInteger時(shí):回傳A.toBigDecimal()
否則,回傳BigDecimal.valueOf(A.doubleValue())
假若N為Byte時(shí):回傳new Byte(A.byteValue())
假若N為Short時(shí):回傳new Short(A.shortValue())
假若N為Integer時(shí):回傳new Integer(A.intValue())
假若N為Long時(shí):回傳new Long(A.longValue())
假若N為Float時(shí):回傳new Float(A.floatValue())
假若N為Double時(shí):回傳new Double(A.doubleValue())
否則,錯(cuò)誤!
l 假若A為String時(shí):
假若N是BigDecimal時(shí):
假若new BigDecimal(A)產(chǎn)生異常時(shí):錯(cuò)誤!
否則,回傳new BigDecimal(A)
假若N是BigInteger時(shí):
假若new BigInteger(A)產(chǎn)生異常時(shí):錯(cuò)誤!
否則,回傳new BigInteger(A)
假若N.valueOf(A)產(chǎn)生異常時(shí):錯(cuò)誤!
否則,回傳N.valueOf(A)
l 否則,錯(cuò)誤!
(3)將A轉(zhuǎn)為Character類型
l 假若A為null或”” 時(shí):回傳(char)0
l 假若A為Character時(shí):回傳A
l 假若A為Boolean時(shí):錯(cuò)誤!
l 假若A為Number時(shí):轉(zhuǎn)換為Short后,然后回傳Character
l 假若A為String時(shí):回傳A.charAt(0)
l 否則,錯(cuò)誤!
(4)將A轉(zhuǎn)為Boolean類型
l 假若A為null或”” 時(shí):回傳false
l 否則,假若A為Boolean時(shí):回傳A
l 否則,假若A為String,且Boolean.valueOf(A)沒有產(chǎn)生異常時(shí):回傳Boolean.valueOf(A)
l 否則,錯(cuò)誤!
第五節(jié) EL 保留字
EL的保留字如表:
所謂保留字的意思是指變量在命名時(shí),應(yīng)該避開上述的名字,以免程序編譯時(shí)發(fā)生錯(cuò)誤。
第六節(jié) EL 隱含對象
我們在第五章隱含對象中,曾經(jīng)介紹過9個(gè)JSP隱含對象,而EL本身也有自己的隱含對象。EL隱含對象總共有11個(gè)。
這11個(gè)隱含對象,我們將它分成三類:
1.與范圍有關(guān)的隱含對象
l applicationScope
l sessionScope
l requestScope
l pageScope
2.與輸入有關(guān)的隱含對象
l param
l paramValues
3.其他隱含對象
l cookie
l header
l headerValues
l initParam
l pageContext
接下來我們依照次序,介紹這些隱含對象。
第七節(jié) 屬性與范圍
與范圍有關(guān)的EL隱含對象包含以下四個(gè):pageScope、requestScope、sessionScope和 applicationScope,它們基本上就和JSP的pageContext、request、session和application一樣。EL 的這四個(gè)隱含對象只能用來取得范圍屬性值,即JSP中的getAttribute(String name),卻不能取得其他相關(guān)信息。
l pageScope
范圍和JSP的Page相同,也就是當(dāng)前頁面的范圍。
l requestScope
范圍和JSP的request相同,requestScope的范圍是指從一個(gè)JSP網(wǎng)頁請
求到另一個(gè)JSP網(wǎng)頁請求之間,隨后此屬性就會(huì)失效。
l sessionScope
范圍和JSP的session相同,它的屬性范圍就是用戶持續(xù)在服務(wù)器連接的
時(shí)間。
l applicationScope
范圍和JSP的application相同,它的屬性范圍是從服務(wù)器一開始執(zhí)服務(wù),
到服務(wù)器關(guān)閉為止。
范例:
index.jsp
elScope.jsp
執(zhí)行后的結(jié)果:
第八節(jié) 與輸入有關(guān)的隱含對象
與輸入有關(guān)的隱含對象有兩個(gè):param和paramValues,它們是EL中比較特別的隱含對象。一般而言,我們在取得用戶的請求參數(shù)時(shí),可以利用下列方法:
在EL中則可以使用param和paramValues兩者來取得數(shù)據(jù)。
這里param的功能和request.getParameter(String name)相同,而paramValues和request.getParameterValues(String name)相同。如果用戶填了一個(gè)表格,表格名稱為username,則我們就可以使用${param.username}來取得用戶填入的值。
范例:
param.jsp
執(zhí)行后結(jié)果:
第九節(jié) 其他隱含對象
介紹最后五個(gè)隱含對象。
l cookie
所謂cookie是一個(gè)小小的文本文件,它是以key、value的方式將Session的內(nèi)容記錄在這個(gè)文本文件內(nèi),這個(gè)文本文件通常存于瀏覽器的暫存區(qū)內(nèi)。假若我們在cookie中設(shè)定一個(gè)名稱為userCountry的值,那么可以使用${cookie.userCountry}來取得它。
范例:
l header和headerValues
header儲(chǔ)存用戶瀏覽器和服務(wù)器用來溝通的數(shù)據(jù),當(dāng)用戶要求服務(wù)器端的網(wǎng)頁時(shí),會(huì)送出一個(gè)記載要求信息的標(biāo)頭文件。
范例:
l initParam
就像其他屬性一樣,我們可以自行設(shè)定web站臺(tái)的環(huán)境參數(shù)(Context),當(dāng)我們想取得這些參數(shù)時(shí),可以使用initParam隱含對象去取得它。
范例:
index.jsp
web.xml
param.jsp
執(zhí)行后的結(jié)果:
l pageContext
我們可以使用${pageContext}來取得其他有關(guān)用戶要求或頁面的詳細(xì)信息。
范例:
index.jsp
執(zhí)行后的結(jié)果:
第十節(jié) EL 算數(shù)運(yùn)算符
EL算數(shù)運(yùn)算符主要有以下五個(gè)
接下來再詳細(xì)說明EL算數(shù)運(yùn)算符的規(guī)則:
(1)A{+,-,*}B
l 假若A和B為null:回傳(Long)0
l 假若A或B為BigDecimal時(shí),將另一個(gè)也轉(zhuǎn)為BigDecimal,則:
假若運(yùn)算符為+時(shí):回傳A.add(B)
假若運(yùn)算符為-時(shí):回傳A.subtract(B)
假若運(yùn)算符為*時(shí):回傳A.multiply(B)
l 假若A或B為Float、Double或包含e/E的字符串時(shí):
假若A或B為BigInteger時(shí),將另一個(gè)轉(zhuǎn)為BigDecimal,然后依照運(yùn)算符執(zhí)行運(yùn)算
否則,將兩者皆轉(zhuǎn)為Double,然后依照運(yùn)算符執(zhí)行運(yùn)算
l 假若A或B為BigInteger時(shí),將另一個(gè)也轉(zhuǎn)為BigInteger,則:
假若運(yùn)算符為+時(shí):回傳A.add(B)
假若運(yùn)算符為-時(shí):回傳A.subtract(B)
假若運(yùn)算符為*時(shí):回傳A.multiply(B)
l 否則,將A和B皆轉(zhuǎn)為Long,然后依照運(yùn)算符執(zhí)行運(yùn)算
l 假若運(yùn)算結(jié)果產(chǎn)生異常時(shí),則錯(cuò)誤!
(2)A{/,div}B
l 假若A和B為null:回傳(Long)0
l 假若A或B為BigDecimal或BigInteger時(shí),皆轉(zhuǎn)為BigDecimal,然后回傳A.divide(B,BigDecimal.ROUND_HALF_UP)
l 否則,將A和B皆轉(zhuǎn)為Double,然后依照運(yùn)算符執(zhí)行運(yùn)算
l 假若運(yùn)算結(jié)果產(chǎn)生異常時(shí),則錯(cuò)誤!
(3)A{%,mod}B
l 假若A和B為null:回傳(Long)0
l 假若A或B為BigDecimal、Float、Double或包含e/E的字符串時(shí),皆轉(zhuǎn)為Double,然后依照運(yùn)算符執(zhí)行運(yùn)算
l 假若A或B為BigInteger時(shí),將另一個(gè)轉(zhuǎn)為BigInteger,則回傳A.remainder(B)
l 否則,將A和B皆轉(zhuǎn)為Long,然后依照運(yùn)算符執(zhí)行運(yùn)算
l 假若運(yùn)算結(jié)果產(chǎn)生異常時(shí),則錯(cuò)誤!
(4)–A
l 假若A為null:回轉(zhuǎn)(Long)0
l 假若A為BigDecimal或BigInteger時(shí),回傳A.negate()
l 假若A為Sting時(shí):
假若A包含e/E時(shí),將轉(zhuǎn)為Double,然后依照運(yùn)算符執(zhí)行運(yùn)算
否則,轉(zhuǎn)為Long,然后依照運(yùn)算符執(zhí)行運(yùn)算
假若運(yùn)算結(jié)果產(chǎn)生異常時(shí),則錯(cuò)誤!
l 假若A為Byte、Short、Integer、Long、Float或Double時(shí):
直接依原本類型執(zhí)行運(yùn)算
假若運(yùn)算結(jié)果產(chǎn)生異常時(shí),則錯(cuò)誤!
l 否則,錯(cuò)誤!
范例:
index.jsp
執(zhí)行后的結(jié)果:
第十一節(jié) EL 關(guān)系運(yùn)算符
EL關(guān)系運(yùn)算符有以下六個(gè)運(yùn)算符
注意:
在使用EL關(guān)系運(yùn)算符時(shí),不能寫成:
${param.password1}= =${param.password2}
或者
${${param.password1}= =${param.password2}}
而應(yīng)該寫成
${param.password1= =param.password2}
接下來再詳細(xì)說明EL關(guān)系運(yùn)算符的規(guī)則:
(1)A{<,>,<=,>=,lt,gt,le,ge}B
l 假若A== B,運(yùn)算符為<=,le時(shí),回傳true,否則回傳false
l 假若A為null或B為null時(shí),回傳false
l 假若A或B為BigDecimal時(shí),將另一個(gè)轉(zhuǎn)為BigDecimal,然后回傳A.compareTo(B)的值
l 假若A或B為Float、Double時(shí),皆轉(zhuǎn)為Double類型,然后依其運(yùn)算符運(yùn)算
l 假若A或B為BigInteger時(shí),將另一個(gè)轉(zhuǎn)為BigInteger,然后回傳A.compareTo(B)的值
l 假若A或B為Byte、Short、Character、Integer或Long時(shí),皆轉(zhuǎn)為Long類型,然后依其運(yùn)算符運(yùn)算
l 假若A或B為String時(shí),將另一個(gè)轉(zhuǎn)為String,然后做詞匯上的比較
l 假若A為Comparable時(shí),則:
假若A.compareTo(B)產(chǎn)生異常時(shí),則錯(cuò)誤!
l 否則,采用A.compareTo(B)的比較結(jié)果
l 假若B為Comparable時(shí),則:
假若B.compareTo(A)產(chǎn)生異常時(shí),則錯(cuò)誤!
l 否則,采用B.compareTo(A)的比較結(jié)果
l 否則,錯(cuò)誤!
(2)A{==,!=,eq,ne}B
l 假若A== B,依其運(yùn)算符運(yùn)算
l 假若A為null或B為null時(shí),==/eq則回傳false,!=/ne則回傳true
l 假若A或B為BigDecimal時(shí),將另一個(gè)轉(zhuǎn)為BigDecimal,則:
假若運(yùn)算符為==/eq,則回傳A.equals(B)
假若運(yùn)算符為!=/ne,則回傳!A.equals(B)
l 假若A或B為Float、Double時(shí),皆轉(zhuǎn)為Double類型,然后依其運(yùn)算符運(yùn)算
l 假若A或B為BigInteger時(shí),將另一個(gè)轉(zhuǎn)為BigInteger,則:
假若運(yùn)算符為==/eq,則回傳A.equals(B)
假若運(yùn)算符為!=/ne,則回傳!A.equals(B)
l 假若A或B為Byte、Short、Character、Integer或Long時(shí),皆轉(zhuǎn)為Long類型,然后依其運(yùn)算符運(yùn)算
l 假若A或B為Boolean時(shí),將另一個(gè)也轉(zhuǎn)為Boolean,然后依其運(yùn)算符運(yùn)算
l 假若A或B為String時(shí),將另一個(gè)轉(zhuǎn)為String,然后做詞匯上的比較
l 否則,假若A.equals(B)產(chǎn)生異常時(shí),則錯(cuò)誤!
l 否則,然后依其運(yùn)算符運(yùn)算,回傳A.equals(B)
第十二節(jié) EL 邏輯運(yùn)算符
EL邏輯運(yùn)算符只有三個(gè)
EL邏輯運(yùn)算符的規(guī)則很簡單:
(1)A{&&,and,||,or}B
l 將A和B轉(zhuǎn)為Boolean,然后依其運(yùn)算符運(yùn)算
(2){!,not}A
l 將A轉(zhuǎn)為Boolean,然后依其運(yùn)算符運(yùn)算
范例:
第十三節(jié) EL 其他運(yùn)算符
EL除了上述三大類的運(yùn)算符之外,還有下列幾個(gè)重要的運(yùn)算符:
(1)empty運(yùn)算符
(2)條件運(yùn)算符
(3)()括號(hào)運(yùn)算符
1. empty 運(yùn)算符
empty運(yùn)算符主要用來判斷值是否為null或空的。
接下來說明Empty運(yùn)算符的規(guī)則:
(1){empty}A
l 假若A為null時(shí),回傳true
l 否則,假若A為空String時(shí),回傳true
l 否則,假若A為空Array時(shí),回傳true
l 否則,假若A為空Map時(shí),回傳true
l 否則,假若A為空Collection時(shí),回傳true
l 否則,回傳false
2. 條件運(yùn)算符
所謂條件運(yùn)算符如下:
意思是說,當(dāng)A為true時(shí),執(zhí)行B;而A為false時(shí),則執(zhí)行C。
3. 括號(hào)運(yùn)算符
括號(hào)運(yùn)算符主要用來改變執(zhí)行優(yōu)先權(quán),例如:${ A * ( B + C )}
至于運(yùn)算符的優(yōu)先權(quán),如下所示(由高至低,由左至右):
l []、.
l ()
l -(負(fù))、not、!、empty
l *、/、div、%、mod
l +、-(減)
l <、>、<=、>=、lt、gt、le、ge
l ==、!=、eq、ne
l &&、and
l ||、or
l ${A ? B: C}
范例:
執(zhí)行后的結(jié)果:
第十四節(jié) EL 函數(shù)
本節(jié)我們將介紹如何自定義EL的函數(shù)。
EL函數(shù)的語法如下:
其中ns為前置名稱(prefix),它必須和taglib指令的前置名稱一樣。
前置名稱都為my,至于function為EL函數(shù)的名稱,而arg1、arg2等等,都是function的傳入值。
EL函數(shù)主要分為四個(gè)部分
這四個(gè)部分環(huán)環(huán)相扣,都互有關(guān)系。我們將在范例中詳細(xì)描述這四個(gè)部分的制作過程。
范例:
我們自定義三個(gè)EL函數(shù):reverse、countVowels和caps其中:
reverse函數(shù):將傳入的字符串以反向順序輸出。
countVowels函數(shù):計(jì)算傳入的字符串中,和aeiouAEIOU吻合的字符個(gè)數(shù)。
caps函數(shù):將傳入的字符串全部變成大寫。
index.jsp
web.xml
functions-taglib.tld
Functions.java
|
|
|