持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
EL
EL 的全称是表达式语言(Expression Language ),是封装了业务逻辑的页面标签,可以用来替代 JSP 页面中的 Java 代码,使不懂 Java 的开发人员也能写出 JSP 代码。EL 还可以实现自动类型转换等功能,使用起来非常简单。
EL 表达式语法
EL 表达式通常由两部分组成:对象和属性。可以使用 “点操作符” 或 “中括号[]操作符” 来操作对象的属性,其语法格式如下:
${EL表达式}
1. 创建文件
2. 修改pom.xml
修改项目中的 pom.xml 文件如下。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.shiyan</groupId>
<artifactId>ServletProject</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>ServletProject Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- servlet 依赖 jar 包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<!-- jsp 依赖 jar 包 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 端口 -->
<port>8080</port>
<!-- 编码-->
<uriEncoding>UTF-8</uriEncoding>
<!-- 项目的启动路径-->
<path>/</path>
<!-- 项目名称 -->
<finalName>ServletProject </finalName>
<!-- 启动的命令名称-->
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. 在 entity 包下创建两个封装数据的 JavaBean。(这里是student和address)
4. 新建 InitServlet.java用于初始化一些数据,并将此 Servlet 配置进 web.xml。
web.xml 的设置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>org.servlet.InitServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InitServlet</servlet-name>
<url-pattern>/initServlet</url-pattern>
</servlet-mapping>
</web-app>
5. 程序会在 InitServlet 中给 student 对象的各个属性赋值,然后跳转到 info.jsp 中。本次先用传统的 Scriptlet 接收对象,并将对象的属性显示到前台如下。
在 src/main/webapp 下新建 info.jsp:
<%@ page pageEncoding="UTF-8"%>
<%@page import="org.entity.*"%>
<html>
<head>
<title>info</title>
</head>
<body>
<%
Student student = (Student)request.getAttribute("student");
int studentNo = student.getStudentNo();
String studentName = student.getStudentName();
Address address = student.getAddress();
String homeAddress = address.getHomeAddress();
String schoolAddress = address.getSchoolAddress();
out.print("学号:"+studentNo +"<br/>");
out.print("姓名:"+studentName +"<br/>");
out.print("家庭地址:"+homeAddress +"<br/>");
out.print("学校地址:"+schoolAddress +"<br/>");
%>
</body>
</html>
可以发现,程序的确能够正常显示。但如果将 info.jsp 中的代码用 EL 表达式来实现,就会简单许多。
以下代码是使用 EL 修改后的 info.jsp,功能与之前的 info.jsp 相同。
<%@ page pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<html>
<head>
<title>info</title>
</head>
<body>
<%-- 使用 EL 表达式 --%>
学生对象:${requestScope.student}<br/>
学号:${requestScope.student.studentNo } <br/>
姓名:${requestScope.student.studentName } <br/>
家庭地址:${requestScope.student.address.homeAddress } <br/>
学校地址:${requestScope.student.address.schoolAddress } <br/>
</body>
</html>
综上可知使用 EL 可以将 JSP 中的 Java 代码彻底消除,并且不用再做强制的类型转换,整体的 JSP 代码就会简单很多。
EL 表达式操作符示例
1. 点操作符
点操作符 “.” 的用法和在 Java 中的用法相同,都是直接用来调用对象的属性。如 ${requestScope.student},表示在 request 作用域内查找 student 对象。
2. 中括号[]操作符
除了点操作符以外,还可以使用中括号操作符 “[]” 来访问某个对象的属性,例如 ${requestScope.student.studentNo } 可以等价写成 ${requestScope.student["studentNo"] } 或 ${requestScope["student"]["studentNo"] }。除此之外,中括号[]操作符还有以下一些其他独有功能。
- 如果属性名称中包含一些特殊字符,如“.”、“?”、“-”等,就必须使用中括号操作符,而不能用点操作符。
- 如果要动态取值,也必须使用中括号操作符,而不能用点操作符。
- 访问数组。
- 点操作符和中括号操作符还可以用来获取 Map 中的属性值。
3. 关系运算符
EL 表达式还能够进行一些简单的运算,如表所示。
| 关系运算符 | 示 例 | 结 果 | |
|---|---|---|---|
| 大于 | >(或 gt) | ${2>1} 或 ${2 gt 1} | true |
| 大于或等于 | >=(或 ge) | ${2>=1} 或 ${2 ge 1} | true |
| 等于 | ==(或 eq) | ${2==1} 或 ${2 eq 1} | false |
| 小于或等于 | <=(或 le) | ${2<=1} 或 ${2 le 1} | false |
| 小于 | <(或 lt) | ${2<1} 或 ${2 lt 1} | false |
| 不等于 | !=(或 ne) | ${2!=1} 或 ${2 ne 1} | true |
4. 逻辑运算符
EL 表达式能够进行的逻辑运算,如表所示。
| 关系运算符 | 示 例 | 结 果 | |||||
|---|---|---|---|---|---|---|---|
| 逻辑或 | (或 or) | `2>1 | 2<1(或 2>1 or 2<1`) | true | |||
| 逻辑与 | &&(或 and) | 2>1&&2<1(或 2>1 and 2<1) | false | ||||
| 逻辑非 | !(或 not) | !(2>1) (或 not 2>1) | false |
5. Empty 操作符
Empty 操作符用来判断一个值是否为 null 或不存在。
el的隐式对象
“隐式对象” 又称 “内置对象” 。之前在 JSP 里曾提到过,像 request、session、application 等都是 JSP 的隐式对象,这些 “隐式对象” 可以不用实例化就直接使用。同样的,在 EL 表达式中也存在一些隐式对象。按照使用的途径不同,EL 隐式对象分为了作用域访问对象、参数访问对象和 JSP 关联对象,如图所示。
1. 四种作用域对象
在使用 EL 表达式来获取一个变量的同时,可以指定该变量的作用域。EL 表达式提供了四个可选的作用域对象,如表所示。
| 对 象 名 | 作 用 域 |
|---|---|
| pageScope | 把 pageContext 作用域中的数据映射为一个 Map 类的对象 |
| requestScope | 把 request 作用域中的数据映射为一个 Map 类的对象 |
| sessionScope | 把 session 作用域中的数据映射为一个 Map 类的对象 |
| applicationScope | 把 application 作用域中的数据映射为一个 Map 类的对象 |
pageScope、requestScope、sessionScope 和 applicationScope 都可以看成 Map 型变量,要获取其中的数据就可以使用点操作符或中括号操作符。
2. param 对象
在 JSP 中,可以使用 request.getParameter() 和 request.getParameterValues() 来获取表单中的值(或地址栏、超链接中附带的值)。对应的,EL 表达式可以通过 param、paramValues 来获取这些值,如表所示。
| 对 象 名 | 示 例 | 作 用 |
|---|---|---|
| param | ${param.username} | 等价于 request.getParameter("username") |
| paramValues | ${param.hobbies} | 等价于 request. getParameterValues ("hobbies") |
3. pageContext 对象
pageContext 是 JSP 的一个隐式对象,同时也是 EL 表达式的隐式对象。因此,pageContext 是 EL 表达式与 JSP 之间的一个桥梁,是用于关联二者的对象。
在 EL 表达式中,可以通过 pageContext 来获取 JSP 的内置对象和 ServletContext 对象,如表所示。
| EL 表达式 | 获取的对象 |
|---|---|
| ${pageContext.page} | 获取 page 对象 |
| ${pageContext.request} | 获取 request 对象 |
| ${pageContext.response} | 获取 response 对象 |
| ${pageContext.session} | 获取 session 对象 |
| ${pageContext.out} | 获取 out 对象 |
| ${pageContext.exception} | 获取 exception 对象 |
| ${pageContext.servletContext} | 获取 servletContext 对象 |
还可以获取这些对象的 getXxx() 方法:例如 ${pageContext.request.serverPort} 就表示访问 request 对象的 getServerPort() 方法。可以发现,在使用时 EL 去掉了方法中的 get 和 “()”,并将首字母改为了小写。
JSTL 标签库
通用标签库包含了三个标签:赋值标签 <c:set>、输出标签 <c:out>、移除标签 <c:remove>。本实验主要介绍赋值标签 <c:set> 的使用。
赋值标签
<c:set> 标签的作用:给变量在某个作用域内赋值,有两个版本:“var”版和“target”版。
① var 版
用于给 page、request、session 或 application 作用域内的变量赋值。
其语法如下。
<c:set var="elementVar" value=" elementValue" scope="scope" />
各参数的含义如下:
var:需要赋值的变量名。
value:被赋予的变量值。
scope:此变量的作用域,有四个可填项,即 page、request、session 和 application。
其示例如下。
<c:set var="addError" value="error" scope="request"/>
表示在 request 作用域内,设置一个 addError 变量,并将变量值赋值为 error,等价于
request.setAttribute("addError", "error");
② target 版
用于给 JavaBean 对象的属性或 Map 对象赋值。
a.给 JavaBean 对象的属性赋值
其语法如下。
<c:set target="objectName" property="propertyName" value="propertyValue" scope="scope"/>
各参数的含义如下:
target:需要操作的 JavaBean 对象,通常使用 EL 表达式来表示。
property:对象的属性名。
value:对象的属性值。
scope:此属性值的作用域,有四个可填项,即 page、request、session 和 application。
本实验通过以下示例,通过 Servlet 给 JavaBean 对象的属性赋值。
1.编写 Servlet
public class InitJSTLDataServlet extends HttpServlet{
protected void doPost(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
//将一个Address对象赋值后,加入request作用域,并请求转发到JSP
Address address = new Address();
address.setHomeAddress("四川成都");
address.setSchoolAddress("重庆");
request.setAttribute("address", address);
request.getRequestDispatcher("JSTLDemo.jsp").forward(request, response);
}
}
2.编写 JSP
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
使用JSTL赋值之前:${requestScope.address.schoolAddress }
<br/>
<c:set target="${requestScope.address }"
property="schoolAddress" value="**基地" />
<br/>
使用JSTL赋值之后:${requestScope.address.schoolAddress }
</body>
使用 JSTL 为 Map 对象赋值的语法如下所示。
<c:set target="mapName" property="mapKey" value="mapValue" scope="scope"/>
其中各参数的含义如下:
target:需要操作的 Map 对象,通常使用 EL 表达式来表示。
property:表示 Map 对象的 key。
value:表示 Map 对象的 value。
scope:此 Map 对象的作用域,有四个可填项,即 page、request、session 和 application。
以下实验,通过 Servlet 给 Map 对象的属性赋值。
public class InitJSTLDataServlet extends HttpServlet{
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//将一个Map对象赋值后,加入request作用域,并请求转发到JSTLDemo.jsp
Map<String,String> countries = new HashMap<String,String>();
countries.put("cn", "中国");
countries.put("us", "美国");
request.setAttribute("countries", countries);
request.getRequestDispatcher("JSTLDemo.jsp").forward(request, response);
}
}
再使用 <c:set…/> 对 Map 对象的属性赋值,如下。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
使用JSTL赋值之前:${requestScope.countries.cn }、${requestScope.countries.us }
<br/>
<c:set target="${requestScope.countries }" property="cn" value="中华人民共和国" />
<br/>
使用JSTL赋值之后:${requestScope.countries.cn }、${requestScope.countries.us }<br/>
<br/>
</body>
运行结果如图所示。
输出标签
输出标签 <c:out> 类似于 JSP 中的 <%= %>,但功能更加强大。
其语法如下。
<c:out value="value" default="defaultValue" escapeXml="isEscape"/>
各参数的含义如下:
value:输出显示结果,可以使用 EL 表达式。
default:可选项。当 value 表示的对象不存在或为空时,默认的输出值。
escapeXml:可选项,值为 true 或 false。值为 true 时(默认情况),将 value 中的值以字符串的形式原封不动地显示出来;值为 false 时,会将内容以 HTML 渲染后的结果显示。
以下是一个示例,先在 InitJSTLDataServlet 中创建 address 对象,然后给 address 中的 schoolAddress 属性赋值,再把 address 对象放入 request 作用域,之后请求转发到 index.jsp。
1.先编写 Servlet 程序。
public class InitJSTLDataServlet extends HttpServlet{
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Address address = new Address();
address.setSchoolAddress("重庆");
request.setAttribute("address", address);
request.getRequestDispatcher("JSTLDemo.jsp").forward(request, response);
}
}
2.再变写 JSP 页面。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
request作用域中,存放了address对象及schoolAddress属性值:
<c:out value="${requestScope.address.schoolAddress}" />
<br/>
request作用域中,不存在student对象:
<c:out value="${requestScope.student}" default="student对象为空"/>
<br/>
当escapeXml="true"时:
<c:out value="<a href='https://www.baidu.com/'>百度主页</a>"
escapeXml="true"/><br/>
当escapeXml="false"时:
<c:out value="<a href='https://www.baidu.com/'>百度主页</a>" escapeXml="false"/>
</body>
移除标签
可以发现,当 value 中输出的对象不存在或为空时,会输出 default 指定的默认值;当 escapeXml 为 false 时,会将 value 中的内容先渲染成 HTML 样式再输出显示。 <c:remove> 用于移除某个作用域内的变量,其语法如下。
<c:remove var="variableName" scope="scope"/>
各参数的含义如下:
var:等待被移除的变量名。
scope:变量被移除的作用域,有四个可填项:page、request、session 和 application。
以下是 <c:remove> 标签的具体使用方法,基于上一个实验中编写的 InitJSTLDataServlet 。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
并不存在的一个变量varDemo:
<c:out value="${varDemo }" default="不存在"/><br/>
在request作用域内,给varDemo赋值为LanQiao
<c:set var="varDemo" value="LanQiao" scope="request"/><br/>
再次观察varDemo:
<c:out value="${varDemo }" default="不存在"/><br/>
在request作用域内,将varDemo移除:
<c:remove var="varDemo" scope="request"/> <br/>
再次观察varDemo:
<c:out value="${varDemo }" default="不存在"/><br/>
</body>
运行结果如图所示。
单重选择标签 <c:if>
<c:if >类似于 Java 中的 if 选择语句。
其语法如下。
<c:if test="condition" var="variableName" scope="scope">
代码块
</c:if>
各参数的含义如下:
test:判断条件,值为 true 或 false,通常用 EL 表达式表示。当值为 true 时才会执行代码块中的内容。
var:可选项。保存 test 的判断结果(true 或 false)。
scope:可选项。设置此变量的作用域,有四个可填项:page、request、session 和 application。
以下实验是单重选择标签的具体使用方法。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
…
<c:if test="${3>2 }" var="result" scope="request">
3>2结果是:${result }
</c:if>
</body>
程序运行结果如图所示。
多重选择标签 <c:choose>
<c:choose >的功能类似于 Java 中 的多重 if,其语法如下。
<c:choose>
<c:when test="">
代码块1
</c:when>
<c:when test="">
代码块2
</c:when>
...
<c:otherwise>
代码块n
</c:otherwise>
</c:choose>
其中,<c:when test=""> 类似于 Java 中的判断语句:if() 和 else if();<c:otherwise >类似于多重 if 中最后的 else。具体的流程是:当<c:when> 中的 test 为 true 时,执行当前 <c:when> 标签中的代码块;如果所有 when 中的 test 都为 false,则会执行 <c:otherwise> 中的代码块。
以下实验是一个多重选择标签的具体应用。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
<c:set var="role" value="学生" />
<c:choose>
<c:when test="${role eq '老师' }">
老师相关代码
</c:when>
<c:when test="${role eq '学生' }">
学生相关代码
</c:when>
<c:otherwise>
管理员相关代码
</c:otherwise>
</c:choose>
</body>
程序运行结果如图所示。
3.迭代 <c:forEach >标签库
在 Java 之中有两种 for 循环,一种是传统的 for 循环,形式如 for(int i=0;i<10;i++),另一种是增强的 for 循环,形式如 for(String name : names),此处的 names 是字符串数组。类似的,在 JSTL 中也提供了两种 <c:forEach> 标签与之相对应,一种用于遍历集合对象的成员,另一种用于让代码重复的循环执行。
(1)遍历集合对象的成员,其语法如下。
<c:forEach var="variableName" items="collectionName"
varStatus="variableStatusInfo" begin="beginIndex"
end="endIndex" step="step">
迭代集合对象的相关代码
</c:forEach>
各参数的含义如下:
var:当前对象的引用,即表示循环正在遍历的那个对象。例如,当循环遍历到第一个成员时,var 就代表第一个成员;当循环遍历到第二个成员时,var 就代表第二个成员……
items:当前循环的集合名。
varStatus:可选项。存放 var 所引用成员的相关信息,如索引号 (index) 等。
begin:可选项。遍历集合的开始位置,从 0 开始。
end:可选项。遍历集合的结束位置。
step:可选项,默认为 1。遍历集合的步长,比如当 step 为 1 时,会依次遍历第 0 个、第 1 个、第 2 个……;当 step 为 2 时,会依次遍历第 0 个、第 2 个、第 4 个……。
(2)迭代指定的次数,其语法如下。
<c:forEach var="variableName" varStatus="variableStatusInfo"
begin="beginIndex" end="endIndex" step="step">
循环体
</c:forEach>
其中,var、varStatus、begin、end、step 属性的含义,与“遍历集合对象的成员”中对应的属性含义相同,并且能发现此种方式的<c:forEach>缺少了 items 属性。此种方式的 <c:forEach> 主要用来让循环体执行固定的次数。
以下实验是迭代标签的具体应用示例。
a.先编写 Servlet 用于准备数据。
public class InitJSTLForeachDataServlet extends HttpServlet {
…
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//Address类包含家庭地址和学校地址两个属性
Address add1 =new Address("北京朝阳区","北京大兴区");
Address add2 =new Address("陕西西安","广州东莞");
List<Address> addresses = new ArrayList<Address>();
addresses.add(add1);
addresses.add(add2);
//addresses集合放入request作用域内
request.setAttribute("addresses", addresses);
request.getRequestDispatcher("JSTLDemo02.jsp").forward(request, response);
}
}
b.使用迭代标签显示数据。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<body>
<c:forEach var="add" items="${addresses }" varStatus="status" >
${status.index}:
家庭地址:${add.homeAddress } –
学校地址:${add.schoolAddress }<br/>
</c:forEach>
</body>
运行结果如图所示。
本章总结
-
EL 表达式通常由两部分组成:对象和属性。可以使用“点操作符”或“中括号
[]操作符”来操作对象的属性,其语法格式是${EL 表达式}。 -
在 EL 表达式中,除了点操作符以外,还可以使用中括号操作符
[]来访问某个对象的属性。如果属性名称中包含一些特殊字符、要访问的对象本身是一个数组、或者需要动态取值时,那么必须使用中括号操作符。 -
EL 隐式对象又称EL 内置对象。按照使用的途径不同,EL 隐式对象分为了作用域访问对象、参数访问对象和 JSP 关联对象,如图所示。 -
JSTL 包含了开发 JSP 时经常用到的一组标准标签。JSTL 一般要结合 EL 表达式一起使用。使用 JSTL 标签库以前,必须先在
pom.xml文件中引入依赖:taglibs-standard-impl和jstl,然后再在需要使用。 -
JSTL 核心标签库主要包含通用标签库、条件标签库和迭代标签库。通用标签库包括赋值标签
<c:set>、输出标签<c:out>、移除标签<c:remove>。条件标签库包括单重选择标签<c:if>、多重选择标签<c:choose>。