Servlet,JSP(6)(JSP表达式语言(EL访问javabean,11个EL隐式对象))

1,表达式语言

JSP 2.0最重要的特性之一就是表达式语言(EL),JSP用户可以用它来访问应用程序数据。
由于受到ECMAScript和XPath表达式语言的启发,EL也设计成可以轻松地编写免脚本的JSP页面。
也就是说,页面不使用任何JSP声明、表达式或者scriptlets。

ps:总结:

1,也就是说el是为了替代jsp中出现java脚本
2,el借鉴于js等脚本

版本:

JSP 2.0最初是将EL应用在JSP标准标签库(JSTL)1.0规范中。
JSP 1.2程序员将标准库导入到他们的应用程序中,就可以使用EL。
JSP 2.0及其更高版本的用户即使没有JSTL,也能使用EL,但在许多应用程序中,还是需要JSTL的,因为它里面还包含了与EL无关的其他标签。

JSP 2.1/ 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的变体。
后来这两种语言变体合二为一。
本章着重介绍非JSF用户的EL。

ps:总结:

1,之前的EL的属于JSTL标签库,现在的jsp版本属于单独存在。
2,EL出现2个分支一个属于JSP一个属于JSF,最终统一。

2,表达式语言的语法

EL表达式以“ ${ ” 开头,并以 “ } ” 结束。EL表达式的结构如下:
${expression}
例如,大括号里面是表达式x+y,可以写成:${x+y}

用来连接两个表达式(相当于将2个结果作为字符串连接)

${a+b}${c+d}
或者
{a+b}and${c+d}

3,关键字

关键字,它们不能用作标识符:
and eq  gt true  instanceof
or  ne  le false  empty
not  lt  ge null  div mod

4,运算符:“ [ ] ”和 “ . ” 

EL表达式可以返回任意类型的值。
如果EL表达式的结果是一个带有属性的对象,则可以利用[ ]或者.运算符来访问该属性。

“[ ]”和“.”运算符类似;
“[ ]”是比较规范的形式,“.”运算符则比较快捷。
${object["propertyName"]}
${object.propertyName}

“[ ]”,和 “.” 运算符区别

对于访问可能的无效属性必须用“【】”
如果用“.”运算符访问不存在的属性,将会导致异常。

中括号可以取代点的所有场景并且具有特定应用:

1)当属性名包含了特殊字符如“.”或“-”等的情况下,就不能使用点操作符来访问,这时只能使用“[]”操作符。
(2)访问数组,如果有一个对象名为array的数组,那么可以根据索引值来访问其中的元素,如${array[0]}等。
(3)“[]”操作符中可以使用变量实现动态访问。

ps:
1,特殊符号的属性名称
2,数组
3,动态变量
(1) 当要存取的属性名称中包含一些特殊字符,如. 或 – 等并非字母或数字的符号,就一定要使用 [ ],
例如:${user.My-Name }不正确的方式,
应当改为:${user["My-Name"] }

(2) 我们来考虑下列情况:
${sessionScope.user[data]}
此时,data 是一个变量,假若data的值为"sex"时,那上述的例子等于${sessionScope.user.sex};
假若data 的值为"name"时,它就等于${sessionScope.user.name}。
因此,如果要动态取值时,就可以用上述的方法来做。

这种情况中括号里面相当于一个占位符,data可以是任意属性名称的字符串,可以用双引号包好;
如果是点后面必须是属性的名字

取值运算符可以迭代使用

例如,以下表达式会得出session标识符:
${pageContext.session.id}

5,取值规则

EL表达式的取值是从左到右进行的。
对于expr-a[expr-b]形式的表达式,其EL表达式的取值方法如下:
计算expr-a得到value-a,计算expr-b得到value-b
1,先计算expr-a,然后计算expr-b,如果value-a或value-b为null,都返回null
2,如果value-a为Map,返回key对应的值,找不到key返回null
3,如果value-a为List或Array,value-b必须是为int类型下标,可能出数组越界异常
4,要获取对象或javabean的属性都必须有对应的get方法。
(ps:el获取值虽然简写了,但只是把调用过程交给系统自动调用)

6,EL隐式对象

在JSP页面中,可以利用JSP脚本来访问JSP隐式对象。
但是,在免脚本的JSP页面中,则不可能访问这些隐式对象。
EL允许通过提供一组它自己的隐式对象来访问不同的对象。

隐式对象的类型:

(ps: el隐式对象,其实就是servlet中的一些对象的属性!!!并非特意新添加!

EL隐式对象

1,pageContext 
这是当前JSP的javax.servlet.jsp.PageContext
2,initParam
这是一个包含所有环境初始化参数,并用参数名作为key的Map
3,param 这是一个包含所有请求参数,并用参数名作为key的Map。
每个key的值就是指定名称的第一个参数值。
因此,如果两个请求参数同名,则只有第一个能够利用param获取值。
要想访问同名参数的所有参数值,就得用params代替
4,paramValues 这是一个包含所有请求参数,并用参数名作为key的Map。
每个key的值就是一个字符串数组,其中包含了指定参数名称的所有参数值。
就算该参数只有一个值,它也仍然会返回一个带有一个元素的数组
5,header 这是一个包含请求标题,并用标题名作为key的Map。
每个key的值就是指定标题名称的第一个标题。
换句话说,如果一个标题的值不止一个,则只返回第一个值。
要想获得多个值的标题,得用headerValues对象代替
6,headerValues 这是一个包含请求标题,并用标题名作为key的Map。
每个key的值就是一个字符串数组,其中包含了指定标题名称的所有参数值。
就算该标题只有一个值,它也仍然会返回一个带有一个元素的数组
7,cookie 这是一个包含了当前请求对象中所有Cookie对象的Map。
Cookie名称就是key名称,并且每个key都映射到一个Cookie对象
8,applicationScope 这是一个包含了ServletContext对象中所有属性的Map,并用属性名称作为key
9,sessionScope 这是一个包含了HttpSession对象中所有属性的Map,并用属性名称作为key
10,requestScope 这是一个Map,其中包含了当前HttpServletRequest对象中的所有属性,并用属性名称作为key
11,pageScope 这是一个Map,其中包含了全页面范围内的所有属性。属性名称就是Map的key

ps总结:11个对象,数据格式都是map

4个请求相关:2个请求参数,2个请求头
4个域对象:页面,请求,会话,应用 ;(与jsp对象区别是,只有域相关的部分)
最后3个:页面上下文,配置初始值,cookie

el隐式对象更加具体化,应该说是与数据相关的具体化,更加mvc模式的view.

6.1,pageContext

pageContext对象表示当前JSP页面的上下文(javax.servlet.jsp.PageContext)。
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

ps总结:9个隐式对象

2个不常用的:page,exception
page:当前页面对象
exception:异常

其他7个对象
4个有域的对象:pagecontex, request, session, application
其他3个:响应,输出,配置

例如

${pageContext.request}
${pageContext["request"]

${pageContext["request"]["method"]}
${pageContext["request"].method}
${pageContext.request["method"]}
${pageContext.request.method}

 6.2,initParam

隐式对象initParam用于获取上下文参数的值。
例如,为了获取名为password的上下文参数值,可以使用以下表达式:
${initParam.password}
或者
${initParam["password"]

6.3,param

隐式对象param用于获取请求参数值。
这个对象表示一个包含所有请求参数的Map。
例如,要获取userName参数,可以使用以下任意一种表达式:
${param.userName}
${param["userName"]}

6.4,paramValues

利用隐式对象paramValues可以获取一个请求参数的多个值。
这个对象表示一个包含所有请求参数,并以参数名称作为key的Map。
每个key的值是一个字符串数组,其中包含了指定参数名称的所有值。
即使该参数只有一个值,它也仍然返回一个带有一个元素的数组。
例如,为了获得selectedOptions参数的第一个值和第二个值,可以使用以下表达式:
${paramValues.selectedOptions[0]}
${paramValues.selectedOptions[1]}

 6.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.6,cookie

隐式对象cookie可以用来获取一个cookie。
这个对象表示当前HttpServletRequest中所有cookie的值。
例如,为了获取名为jsessionid的cookie值,要使用以下表达式: ${cookie.jsessionid.value} 为了获取jsessionid cookie的路径值,要使用以下表达式: ${cookie.jsessionid.path}

6.7,applicationScope、sessionScope、requestScope和pageScope

这4个EL域对象,对应jsp中的PageContext、ServletRequest、HttpSession,ServletContext中的域
如果想获取特定域中的值,通过指定的域获取值:
${applicationScope.myVar}

如果不指定域获取值,那么将自动从小域到大范围域查找,匹配一个停止查找:
${myVar}
(会从 pageScope -> requestScope -> sessionScope -> applicationScope域依次查找)

7,使用其他EL运算符

除了“.”和“[]”运算符外,EL还提供了其他运算符:
算术运算符、关系运算符、逻辑运算符、条件运算符以及empty运算符。
由于EL的目的是方便免脚本JSP页面的编程,因此,除了关系运算符外其他EL运算符的用处都很有限

7.1,算术运算符

算术运算符有5种:
加法(+)
减法(−)
乘法(*)
除法(/和div)
取余/取模(%和mod)

注意,EL表达式的计算按优先级从高到低、从左到右进行。

(*、/、div、%、mod )优先于( + − )
括号中每个运算符优先级同级
表达式:${1+2*3} 的运算结果是7,而不是9。

7.2,逻辑运算符

和(&&和and)
或(|| 和or)
非(!和not)

7.3,关系运算符

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

EL关系运算符的语法如下:

${statement? A:B}
${(sessionScope.loggedIn==null)? "You have not logged in" :"You have logged in"}

7.4,empty运算符

empty运算符用来检查某一个值是否为null或者empty。(不管是null还是空对象都是ture)
下面是一个empty运算符的使用范例:
${empty X}

如果X为null,或者说X是一个长度为0的字符串,那么该表达式将返回True。
如果X是一个空Map、空数组或者空集合,它也将返回True,否则,将返回False。

8,应用例子:

示例包含了一个JSP页面,该页面通过EL访问一个JavaBean并输出该bean的属性。
该bean对象是另一个JavaBean(Employee)的一个属性,并用EL访问一个Map对象的内容,以及HTTP头部信息和会话标识。
EmployeeServlet 类创建了所需的对象,并将这些对象放入到ServletRequest中,
然后通过RequestDispatcher跳转到employee.jsp页面。
清单4.1 Address类
package app04a.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 streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public String getStreetNumber() {
return streetNumber;
}
public void setStreetNumber(String streetNumber) {
this.streetNumber = streetNumber;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}

清单4.2 Employee类
package app04a.model;
public class Employee {
private int id;
private String name;
private Address address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}

清单4.3 EmployeeServlet类
package app04a.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 app04a.model.Address;
import app04a.model.Employee;

@WebServlet(urlPatterns = {"/employee"})
public class EmployeeServlet extends HttpServlet {
private static final int serialVersionUID = -5392874;

@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Address address = new Address();
address.setStreetName("Rue D'Anjou");
address.setStreetNumber("5090B");
address.setCity("Brossard");
address.setState("Quebec");
address.setZipCode("A1A B2B");
address.setCountry("Canada");
Employee employee = new Employee();
employee.setId(1099);
employee.setName("Charles Unjeye");
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", "Ottawa");
request.setAttribute("capitals", capitals);
RequestDispatcher rd =
request.getRequestDispatcher("/employee.jsp");
rd.forward(request, response); }
}
}

清单4.4 employee.jsp
<html>
<head>
<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>
View Code
使用一个servlet和JSP页面来显示JavaBean属性和其他值符合现代Web应用程序的推荐的设计

9,如何在JSP 2.0及其更高版本中配置EL

有了EL、JavaBeans和定制标签,就可以编写免脚本的JSP页面了。
JSP 2.0及其更高的版本中还提供了一个开关,可以使所有的JSP页面都禁用脚本。

另一方面,在有些情况下,可能还会需要在应用程序中取消EL。
例如,正在使用与JSP 2.0兼容的容器,却尚未准备升级到JSP 2.0,那么就需要这么做。
在这种情况下,可以关闭EL表达式的计算。

9.1,实现免脚本的JSP页面

为了关闭JSP页面中的脚本元素,要使用jsp-property-group元素以及url-patternscripting- invalid两个子元素。
url-pattern元素定义禁用脚本要应用的URL样式。
下面示范如何将一个应用程序中所有JSP页面的脚本都关闭:
<jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group> </jsp-config> 注意: 在部署描述符中只能有一个jsp-config元素。 如果已经为禁用EL而定义了一个jsp-property-group,
就必须在同一个jsp-config元素下,为禁用脚本而编写jsp-property- group。

9.2,禁用EL计算

在某些情况下,比如,当需要在JSP 2.0及其更高版本的容器中部署JSP 1.2应用程序时,
可能就需要禁用JSP页面中的EL计算了。 此时,一旦出现EL架构,就不会作为一个EL表达式进行计算。 目前有两种方式可以禁用JSP中的EL计算。

第一种,可以将page指令的isELIgnored属性设为True,如下:

<%@ page isELIgnored="true" %>

isELIgnored属性的默认值为False。
如果想在一个或者几个JSP页面中关闭EL表达式计算,建议使用isELIgnored属性。

第二种,可以在部署描述符中使用jsp-property-group元素。

在名为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>

注意:一二只要一个满足一个就禁止EL

无论是将其page指令的isELIgnored属性设为True,
还是将其URL与子元素el-ignored设为True,都将禁用JSP页面中的EL计算。

此外,如果使用的是与Servlet 2.3及其更低版本兼容的部署描述符,
那么EL计算已经默认关闭,即便使用的是JSP 2.0及其更高版本的容器,也一样。

 

posted @ 2018-11-06 22:49  假程序猿  阅读(589)  评论(0)    收藏  举报