天天看點

【720科技SpringMVC】---20180420 SpringMVC 表達式語言

内容關鍵詞: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版)