EL(表达式语言)
EL表达式的主要作用
1)获取数据。EL使得获取JavaBean中的数据变得非常简单,也可以替换JSP页面中的脚本元素,从各种类型的web域中获取数据。
2)执行运算。利用EL表达式可以在JSP页面中执行一些基本的算术运算、关系运算、逻辑运算。
3)获取web开发常用对象,EL中定义了11个内置对象可以直接使用。
4)调用Java方法。EL表达式允许用户开发自定义EL函数,从而在JSP页面中通过EL表达式调用Java类的方法。
EL表达式的语法
以“${”开始,以“}”结束。
对于一系列的表达式,其取值将从左向右进行,计算结果的类型为String,并且连接在一起。
如果在定制标签的属性值中使用EL表达式,那么该表达式的取值结果字符串将会强制转换成该属性需要的类型
${标识符} <!-- 如果 a=2,b=6,c=4,d=6 --> ${a+b}and${c+d} <!-- 返回 8and10 -->
EL表达中的关键字
这些关键字不能作为标识符
div mod <!-- 算术运算符 --> eq ne gt ge lt le <!-- 关系运算符 --> and or not <!-- 逻辑运算符 --> true false <!-- 逻辑值 --> instanceof empty null
EL表达式可以返回任意类型的值,包括JavaBean
如果EL表达式的值是一个带有属性的对象,则可以使用“[]”或“.”运算符来访问该属性值。
${Object["propertyName"]} <!-- 规范形式,任何情形下都能使用 --> ${Object.propertyName} <!-- 仅在propertyName是有效的Java变量名时使用(即字母、数字、下划线、$)--> ${header["host"]} <!-- 正确 --> ${header.host} <!-- 正确 --> ${header["accept-language"]} <!-- 正确 --> ${header.accept-language} <!--错误,accept-language不是有效的Java变量名-->
如果对象的属性也是一个对象,则可以继续使用“[]”或“.”访问第二个对象的属性。
${pageContext["request"]["servletPath"]}
${pageContext["request"].servletPath}
${pageContext.request.["servletPath"]}
${pageContext.request.request}
EL的取值规则
EL表达式的取值是从左向右进行的,对于expr-a["expr-b"],其EL表达式的取值方法如下:
首先计算 expr-a 得到 value-a,如果 value-a 为 null,则返回 null
然后计算 expr-b 得到 value-b,如果 value-b 为 null,则返回 null
如果 value-a 是 java.util.Map,则会查看 value-b 是否为 Map 的一个 key,若是则返回 value-a.get(value-b),若不是,则返回 null
如果 value-a 是 java.util.List 或者 array,分一下三种情况:
a、如果 value-b 强制转换为 int 失败,返回 null;
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)
若果 value-a 不是一个 Map、List 或者 array,那么 value-a 必须是一个 JavaBean,此时需要将 value-b 强制转换成 String,如果 value-b 是 value-a 的一个可读属性,则要调用该属性的getter()方法从中返回值。
EL表达式取值的原理
在执行 ${标识符} 时,会调用pageContext.findAtrribute()方法,用标识符作为关键字,分别从page、request、session、application四个域中查找相应的对象并返回,找不到则返回空串""
在获取某个对象(包括JavaBean)的属性时,先将该属性的首字母变成大写,然后加上get前缀,拼凑成getter方法,通过反射将该对象构建出来,再对该对象执行getter方法,故JavaBean的属性名要小些,且要有getter方法。
使用EL运算符
算术运算符
+ - * / div % mod ${1+2*3} <!-- 结果为7 -->
逻辑运算符
&& and <!-- 与 --> || or <!-- 或 --> ! not <!-- 非 -->
关系运算符
== eq <!-- 等于 --> != ne <!-- 不等于 --> > gt <!-- 大于--> >= ge <!-- 大于等于 --> < lt <!-- 小于 --> <= le <!-- 小于等于 -->
条件运算符
${statement ? A : B} <!-- statement为true执行A,false执行B --> ${(sessionScope.loggedIn == null) ? "You have not logged in" : "You have logged in"}
empty 运算符
用来检查某个值是否为null或者empty
${empty X} <!-- 如果X为null、长度为0的空字符串、空Map、空数组、空集合,将返回True,否则返回False -->
禁用EL表达式
第一种方法:在page指令中将的isELignored属性设为True
第二种方法:在部署描述符(web.xml)中修改<jsp-property-group>元素
<!-- 第一种 --> <%@ page isELIgnored="True" %> <!-- 第二种 --> <jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>true</el-ignored> </jsp-property-group> </jsp-config>
实例
一个JavaBean
package app04a.model; public class Address { // 一个JavaBean 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; } }
一个JavaBean
package app04a.model; public class Employee { // 一个JavaBean 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; } }
Servlet作为控制器
package app04a.model; 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; @WebServlet(name = "EmployeeServlet", urlPatterns = { "/","/employee" }) public class EmployeeServlet extends HttpServlet { // Servlet充当控制器 负责处理请求 private static final long serialVersionUID = 1L; public EmployeeServlet() { super(); } @Override protected 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 requestDispatcher = request.getRequestDispatcher("/employee.jsp"); requestDispatcher.forward(request, response); // 将请求转发到JSP页面 } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
JSP页面作为视图
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%-- JSP页面作为视图 负责显示 --%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Employee</title> </head> <body> accept-language: ${header["accept-language"] } <br /> <%-- 使用EL隐式对象 --%> session-id: ${pageContext["session"]["id"] } <br /> <%-- 使用EL隐式对象 --%> employee: ${requestScope["employee"]["name"] }, ${employee["address"]["city"] } <br /> <%-- 访问JavaBean中的属性 --%> capital: ${requestScope.capitals["Canada"] } <%-- 访问JavaBean中的属性 --%> </body> </html>
测试结果
编写EL函数
一般而言,编写EL函数需要以下三个步骤:
第一步:创建一个包含静态方法的public类。每个类的静态方法表示一个EL函数,这个类可以不需要实现任何借口或继承任何函数,这个类必须放在应用中的/WEB-INF/classes目录或者它的子目录下。
第二步:用fucntion节点在标签库描述器中注册这个函数。
第三步:要使用这个函数,必须将taglib指令中的uri属性指向标签库描述器,并指明使用的前缀。然后就可以在JSP页面中使用如下语法来访问该函数
${prefix:functionName(parameterList) }
function节点是taglib节点的下级节点,其有如下子节点
description // 可选 标签说明 display-name // 在XML工具中显示的缩写的名字 icon // 可选,在XML工具中使用的icon节点 name // 函数的唯一名字 function-class // 该函数对应实现的java类的全名 fucntion-signature // 该函数对应实现的Java静态方法 example // 可选,使用该函数的实例说明 function-extension // 可以是一个或者多个节点,在XML工具中使用,用于提供该函数的更多细节
实例
创建一个包含静态方法的public类
package app06a.function; public class StringFunctions { public static String reverseString(String s) { return new StringBuffer(s).reverse().toString(); } }
用fucntion节点在标签库描述器中注册这个函数
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd" > <taglib> <description>Function tag example</description> <tlib-version>1.0</tlib-version> <jsp-version>1.0</jsp-version> <function> <decription>Reverse a String</decription> <name>reverseString</name> <function-class>app06a.function.StringFunctions</function-class> <function-signature>java.lang.String reverseString(java.lang.String)</function-signature> </function> </taglib>
使用这个函数
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/WEB-INF/functions.tld" prefix="f" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Testing EL Function</title> </head> <body> ${f:reverseString("Hello world") } </body> </html>
结果