表達式語言 Expression Language


  JSP 2.0最重要的特性之一就是表達式語言 (EL),JSP用戶可以用它來訪問應用程序數據。由於 受到ECMAScript和XPath表達式語言的啟發,EL也設計 成可以輕松地編寫免腳本的JSP頁面。也就是說,頁面 不使用任何JSP聲明、表達式或者scriptlets。 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的變體。后來這兩種語言變體 合二為一。

一.表達式語言的語法

  EL表達式以 ${ 開頭,並以 } 結束。EL表達式的結 構如下:

$ { expression}

  它們的取值將是從左到右進行,計算結果的類型為 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 true instanceof
or ne le false empty
not lt ge null div mod

三. [] 和 . 運算符

  EL表達式可以返回任意類型的值。如果EL表達式 的結果是一個帶有屬性的對象,則可以利用[ ]或者.運 算符來訪問該屬性。“[ ]”和“.”運算符類似; “[ ]”是比較 規范的形式, “.”運算符則比較快捷。 為了訪問對象的屬性,可以使用以下任意一種形 式:

${object["propertyName"]}
${object.propertyName}

 但是,如果propertyName不是有效的Java變量名, 只能使用[ ]運算符。例如,下面這兩個EL表達式就可以用來訪問隱式對象標題中的HTTP標題host:

<body>
hello;
${header.host};
<br />
${header["host"]};
</body>

但是,要想訪問accept-language標題,則只能使 用“[ ]”運算符,因為accept-language不是一個合法的 Java變量名。如果用“.”運算符訪問它,將會導致異常。 

<body>
hello;
<br />
<%-- header.accpt-language 不可用 %-->
${header["accept-language"]};
</body>

 如果對象的屬性碰巧返回帶有屬性的另一個對象, 則既可以用“[ ]” ,也可以用“.”運算符來訪問第二個對象 的屬性。例如,隱式對象pageContext是表示當前JSP的 PageContext對象。它有request屬性,表示 HttpServletRequest。HttpServletRequest帶有servletPath 屬性。下列幾個表達式的結果相同,均能得出 pageContext中HttpServletRequest的servletPath屬性值

<body>
hello;
${pageContext["request"]["servletPath"]}
${pageContext.request["servletPath"]}
${pageContext.request.servletPath}
${pageContext["request"].servletPath}
</body>

要訪問HttpSession,可以使用以下語法:

<body>
hello;
${pageContext.session }
<br />
${pageContext.session.id }
</body>

四,取值規則

EL表達式的取值是從左到右進行的。對於expra[expr-b]形式的表達式,其EL表達式的取值方法如下:

  如果value-a不是一個Map、List或者 array, 那么,value-a必須是一個JavaBean。在這種情況下,必 須強制value-b為String。如果value-b是value-a的一個可 讀屬性,則要調用該屬性的getter方法,從中返回值。 如果getter方法拋出異常,該表達式就是無效的,否 則,該表達式有效。  

五. 訪問JavaBean

利用“.”或“[]”運算符,都可以訪問 bean 的屬性, 其結構如下:

${beanName["propertyName"]}
${beanName.propertyName}

如果該屬性是一個帶屬性的對象,那么同樣也可以 利用“.”或“[]”運算符來訪問第二個對象的該屬性。假如 該屬性是一個Map、List或者array,則可以利用和訪問 Map值或List成員或array元素的同樣規則。

六. EL隱式對象

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

 

1.pageContext

pageContext 對象表示當前頁面的javax.servlet.jsp.PageContext. 它包含了所有的其他的JSP隱式對象

JSP隱式對象
對象 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}

2.initParam

隱式對象initParam用於獲取上下文參數的值,例如,為了獲取名為password的上下文的值,可以使用以下表達式

${initParam.password}

${initParam["password"]

3.Param

隱式對象param用於獲取請求參數值。這個對象表 示一個包含所有請求參數的Map。例如,要獲取 userName參數,可以使用以下任意一種表達式:

${param.userName} //獲取url ? 號后的param的值
${param["userName"]}

4.ParamValues

  利用隱式對象paramValues可以獲取一個請求參數 的多個值。這個對象表示一個包含所有請求參數,並以 參數名稱作為key的Map。每個key的值是一個字符串數 組,其中包含了指定參數名稱的所有值。即使該參數只 有一個值,它也仍然返回一個帶有一個元素的數組。例 如,為了獲得selectedOptions參數的第一個值和第二個 值,可以使用以下表達式: 

${paramValues.selectedOptions[0]}
${paramValues.selectedOptions[1]}

例: url為 http://localhost:8080/jspTest1/NewFile.jsp?text=sss&text=sss2

jsp為 ${paramValues.text[1]}

顯示

 

5. header

隱式對象header表示一個包含所有請求標題的 Map。為了獲取header值,要利用header名稱作為key。 例如,為了獲取accept-language這個header值,可以使 用以下表達式:

${header["accept-language"]

如果header名稱是一個有效的Java變量名,如 connection,那么也可以使用“. ”運算符:

${header.connection}

隱式對象headerValues表示一個包含所有請求 head,並以header名稱作為key的Map。但是,與head不 同的是,隱式對象headerValues返回的Map返回的是一 個字符串數組。例如,為了獲取標題accept-language的 第一個值,要使用以下表達式:

${headerValues["accept-language"][0]}

6. cookie

  隱式對象cookie可以用來獲取一個cookie。這個對 象表示當前HttpServletRequest中所有cookie的值。例 如,為了獲取名為jsessionid的cookie值,要使用以下表 達式:

${cookie.jsessionid.value}

  為了獲取jsessionid cookie的路徑值,要使用以下表 達式:

${cookie.jsessionid.path}

7.applicationScope, sessionScope, requestScope, pageScope

隱式對象applicationScope用於獲取應用程序范圍級 變量的值。假如有一個應用程序范圍級變量myVar,就 可以利用以下表達式來獲取這個屬性:

${applicationScope.myVar}

例:

jsp頁面

<body>
<jsp:useBean id="today" class="java.util.Date" />
${pageScope.today}
</body>

顯示

注意,在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運算符的用處 都很有限。

1. 算術運算符

i)算術運算符有5種:

加法(+) 減法(−) 乘法(*) 除法(/和div) 取余/取模(%和mod)

除法和取余運算符有兩種形式,與XPath和 ECMAScript是一致的。

ii)注意,EL表達式的計算按優先級從高到低、從左 到右進行。下列運算符是按優先級遞減順序排列的:

* 、/、div、%、mod、 //這一級運算符的優先級相同

+ 、-  //這一級的優先級小於第一級

2.邏輯運算符

邏輯運算符: 和(&&和and) 或(|| 和or) 非(!和not)

3.關系運算符

關系運算符列表

  • 等於(=和eq)
  • 不等於(!=和ne)
  • 大於(>和gt)
  • 大於等於(>=和ge)
  • 小於(<和lt)
  • 小於等於(<=和le)

例如,表達式${3==4}返回False,${“b”<“d”}則返 回True。 EL關系運算符的語法如下:

${statement? A:B}  //三目運算符

4.emty運算符

empty運算符用來檢查某一個值是否為null或者 empty。下面是一個empty運算符的使用范例

jsp頁面

<body>
<% java.util.Date today1 = null; %>
${empty today1}
<jsp:useBean id="today" class="java.util.Date" />
</body>

瀏覽器顯示

 八.  應用EL

示例app04a包含了一個JSP頁面,該頁面通過EL訪 問一個JavaBean(Address,詳見清單4.1)並輸出該 bean的屬性。該bean對象是另一個 JavaBean(Employee,詳見清單4.2)的一個屬性,並 用EL訪問一個Map對象的內容,以及HTTP頭部信息和 會話標識。EmployeeServlet 類(詳見清單4.3)創建了 所需的對象,並將這些對象放入到ServletRequest中, 然后通過RequestDispatcher跳轉到employee.jsp頁面。

Address類

package model;

public class Address {
    private String  streetName;
    private String streetNumber;
    private String city;
    private String state;
    private String zipCode;
    private String country;
    
    public String getStreetName() { return this.streetName ;}
    public void setStreetName(String streetName) { this.streetName= streetName;}
    public String getStreetNumber() { return this.streetNumber; }
    public void setStreetNumber(String streetNumber) { this.streetNumber = streetNumber;}
    public String getCity() { return this.city; }
    public void setCity(String city) { this.city = city ; }
    public String getState() { return this.state; }
    public void setState(String state) { this.state = state; } 
    public String getZipCode() { return this.zipCode;}
    public void setZipCode(String zipCode) { this.zipCode = zipCode; }
    public String getCountry() { return this.country; }
    public void setCountry(String country) { this.country = country; }
}

Employee類

package model;

public class Employee  {
    private int id;
    private String name;
    private Address address;
    public int getId() { return this.id; }
    public void setId(int id) { this.id = id ;}
    public String getName() { return this.name; }
    public void setName(String name) { this.name = name; }
    public Address getAddress() { return this.address; }
    public void setAddress(Address address) { this.address = address; }
}

EmployeeServlet類

package servlet;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.*;

@WebServlet(urlPatterns = { "/employee"})
public class EmployeeServlet extends HttpServlet{
    private static final long serialVersionUID = 10L;
    @Override
    public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        Address address  = new Address();
        address.setStreetName("Rue ");
        address.setStreetNumber("509ab");
        address.setCity("Brossard");
        address.setState("Quebec");
        address.setZipCode("A1A B2b");
        address.setCountry("canada");
        
        Employee employee = new Employee();
        employee.setId(1099);
        employee.setName("charles");
        employee.setAddress(address);
        
        request.setAttribute("employee",employee);
        
        Map<String, String> capitals = new HashMap<String,String>();
        capitals.put("China" ,"Beijing");
        capitals.put("Austria","Vienna");
        capitals.put("Australia","Canberra");
        capitals.put("Canada","Ottua");
        
        request.setAttribute("capitals", capitals);
        /*定義一個對象,該對象接收來自客戶端的請求,並將它們發送到服務器上的任何資源(例如servlet,HTML文件或JSP文件)。servlet容器創建RequestDispatcher對象,該對象用作位於特定路徑或由特定名稱給定的服務器資源的包裝器。
        此接口旨在包裝servlet,但servlet容器可以創建RequestDispatcher 對象以包裝任何類型的資源。*/
        RequestDispatcher rd = request.getRequestDispatcher("/employee.jsp"); 
        /* 將來自servlet的請求轉發到服務器上的另一個資源(servlet,JSP文件或HTML文件)。*/
        rd.forward(request,response);        
    }

}

employee.jsp

// employee.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Employee</title>
</head>
<body>
accept-language: ${header['accept-language']}
<br />
session id: ${pageContext.session.id }
<br />
employee: ${requestScope.employee.name}, ${employee.address.city}
<br />
capital: ${capitals["Canada"]}
</body>
</html>

瀏覽器顯示結果

請注意,在app04a中使用一個servlet和JSP頁面來 顯示JavaBean屬性和其他值符合現代Web應用程序的推 薦的設計,在第16章中會進一步討論。 要特別注意在JSP頁面的EL表達式中,對於request 域的employee對象的訪問,可以是顯式的,也可以是隱 式的.

 九.如何在就jsp2.0 及其更高版本中配置EL

  有了EL、JavaBeans和定制標簽,就可以編寫免腳 本的JSP頁面了。JSP 2.0及其更高的版本中還提供了一 個開關,可以使所有的JSP頁面都禁用腳本。現在,軟件架構師們可以強制編寫免腳本的JSP頁面了。 另一方面,在有些情況下,可能還會需要在應用程 序中取消EL。例如,正在使用與JSP 2.0兼容的容器, 卻尚未准備升級到JSP 2.0,那么就需要這么做。在這 種情況下,可以關閉EL表達式的計算。

 1. 實現免腳本的JSP頁面

  為了關閉JSP頁面中的腳本元素,要使用jspproperty-group元素以及url-pattern和scripting- invalid兩 個子元素。url-pattern元素定義禁用腳本要應用的URL 樣式。下面示范如何將一個應用程序中所有JSP頁面的 腳本都關閉:  

web.xml   ---- 主要web.xml修改后要重啟服務器

<jsp-config>
      <jsp-property-group>
          <url-pattern>*.jsp</url-pattern>
          <el-ignored>true</el-ignored>
           <el-ignored>true</el-ignored>  //此項不知到要不要加
          <scripting-invalid>true</scripting-invalid>
      </jsp-property-group>
  </jsp-config>

 注意: 在部署描述符中只能有一個jsp-config元素。如果已經為禁用EL而 定義了一個jsp-property-group,就必須在同一個jsp-config元素下,為禁用腳本而編寫jsp-property- group。

十. 禁用EL計算

  在某些情況下,比如,當需要在JSP 2.0及其更高版 本的容器中部署JSP 1.2應用程序時,可能就需要禁用 JSP頁面中的EL計算了。此時,一旦出現EL架構,就不 會作為一個EL表達式進行計算。目前有兩種方式可以 禁用JSP中的EL計算。 第一種,可以將page指令的isELIgnored屬性設為 True,如下:

<%@ page isELIgnored="true" %>

  第二種,可以在部署描述符中使用jsp-propertygroup元素。jsp-property-group元素是jsp- config元素的 子元素。利用jsp-property-group可以將某些設置應用到 應用程序中的一組JSP頁面中。 為了利用 jsp-property-group 元素禁用EL計算,還 必須有url-pattern 和 el-ignored兩個子元素。url-pattern 元素用於定義EL禁用要應用的URL樣式。el-ignored元 素必須設為True。

  下面舉一個例子,示范如何在名為noEI.jsp的JSP頁 面中禁用EL計算:

<jsp-config>
<jsp-property-group>
<url-pattern>/noEl.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config

  也可以像下面這樣,通過給 url-pattern 元素賦值 *.jsp,來禁用一個應用程序中所有 JSP頁面的EL計算:

<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>

  無論是將其page指令的isELIgnored屬性設為True, 還是將其URL與子元素el-ignored設為True的jspproperty-group元素中的模式相匹配,都將禁用JSP頁面 中的EL計算。假如將一個JSP頁面中page指令的 isELIgnored屬性設為False,但其URL與在部署描述符 中禁用了EL計算的JSP頁面的模式匹配,那么該頁面的 EL計算也將被禁用。 此外,如果使用的是與Servlet 2.3及其更低版本兼 容的部署描述符,那么EL計算已經默認關閉,即便使 用的是JSP 2.0及其更高版本的容器,也一樣


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM