EL表达式 | 深入学习EL表达式
目录
一:深入学习EL表达式
1、什么是EL表达式
2、EL表达式的主要作用
3、EL表达式的使用
4、面试题 :${abc} 和 ${"abc"}的区别
5、EL表达式读取数据的顺序
6、EL表达式对null进行了预处理
7、EL表达式取数据的时候有两种形式
8、从Map集合中取数据
9、从数组和List集合中取数据
10、设置忽略EL表达式
11、通过EL表达式获取应用的根
12、常用的隐式对象
13、EL表达式的运算符
一:深入学习EL表达式
1、什么是EL表达式
①EL表达式:Expression Language(表达式语言) 。
②EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观。
③JSP中夹杂着各种java代码,例如、等,导致JSP文件很混乱,不好看,不好维护!所以才有了后期的EL表达式。
④EL表达式可以算是JSP语法的一部分,EL表达式归属于JSP。
2、EL表达式的主要作用
从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器。这就是EL表达式的功效;三大功效:
①第一功效:从某个域中取数据。 四个域:pageContext、request、session、application
②第二功效:将取出的数据转成字符串。如果是一个java对象,也会自动调用java对象的toString方法将其转换成字符串。
③第三功效:将字符串输出到浏览器。和效果一样,将其输出到浏览器。
3、EL表达式的使用
${表达式}
①注意:EL表达式只负责取,不负责存。
②我们来看下面一个例子,调用 request的setAttribute("username","zhangsan");方法存入数据;以前取的话是使用这种方式取;但是现在使用EL表达式只需要简介的一句话:${username}。
${username}
①创建一个完整的javabean对象
package com.bjpowernode.javaweb.jsp;import java.util.Objects;/** * * @Author:朗朗乾坤 * @Package:com.bjpowernode.oa.bean * @Project:JavaWeb * @name:Dept * @Date:2022/11/28 10:59 */public class Dept { private String deptno; private String dname; private String loc; // 构造方法 public Dept() { } public Dept(String deptno, String dname, String loc) { this.deptno = deptno; this.dname = dname; this.loc = loc; } // setter and getter public String getDeptno() { return deptno; } public void setDeptno(String deptno) { this.deptno = deptno; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } // 重写toString方法 @Override public String toString() { return "Dept{" + "deptno='" + deptno + '\'' + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + '}'; } // 重写equals方法 和 hashCode方法 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Dept dept = (Dept) o; return Objects.equals(deptno, dept.deptno) && Objects.equals(dname, dept.dname) && Objects.equals(loc, dept.loc); } @Override public int hashCode() { return Objects.hash(deptno, dname, loc); }}
②把这个java对象放入到request域当中,并使用EL表达式取出
😊如果没有重写toString方法:com.bjpowernode.javaweb.jsp.Dept@38039c48
😊如果重写了toString方法:Dept{deptno='10', dname='研发部', loc='北京'}
${userObj}
那如果想取每个特定的属性呢?
😊不需要调用Dept类的对应get方法去获取得;而是直接调用属性名(暂时这样理解);实际上直接调用属性名,底层自己会调用对应的get方法!
😊${userObj} 底层是怎么做的?从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器。
${userObj.deptno} 10 ${userObj.dname} 研发部 ${userObj.loc} 北京
😊注:实际上和属性名并没有太大的关系,只和get方法有关,例如:getDeptno()是把get和()都去掉,Deptno换成全小写的deptno,下面通过一个例子进行验证:
// 在Dept类中新增加一个getEmail()方法,但是没有声明email属性 public String getEmail() { return "123.com"; }// 使用.email也是能访问到的${userObj.email} // 123.com
😊所以如果想输出对象的属性值:
{userObj.deptno} 使用这个语法的前提是:User对象有getDeptno()方法。
${userObj.dname} 使用这个语法的前提是:User对象有getDname()方法。
${userObj.loc} 使用这个语法的前提是:User对象有geLoc()方法。
${userObj.email} 使用这个语法的前提是:User对象有getEmail()方法。
😊EL表达式中的. 这个语法,实际上调用了底层的getXxx()方法。😊所以可以通过EL表达式${userObj.addr.zipcode}猜测对应的java代码
dept.getAddr().getZipcode()😊注意:如果没有对应的get方法,则出现异常。报500错误。
4、面试题 :${abc} 和 ${"abc"}的区别
①${abc}表示从某个域中取出数据,并且被取的这个数据的name是"abc",之前一定有这样的代码: 域.setAttribute("abc", 对象);
②${"abc"} 表示直接将"abc"当做普通字符串输出到浏览器,不会从某个域中取数据了。
5、EL表达式读取数据的顺序
①EL表达式优先从小范围中读取数据。
②pageContext < request < session < application
<%--pageContext < request < session ${data}
③在EL表达式中可以指定范围来读取数据;EL表达式有4个隐含的隐式的范围对象:
😊pageScope 对应的是 pageContext范围。
😊requestScope 对应的是 request范围。
😊sessionScope 对应的是 session范围。
😊applicationScope 对应的是 application范围。
${pageScope.data}
${requestScope.data}
${sessionScope.data}
${applicationScope.data}
6、EL表达式对null进行了预处理
①EL表达式主要任务是做页面展示,要求最终页面展示上是友好的。
②所以EL表达式对null进行了处理。如果是null,则在浏览器上显示空白。
③EL表达式表面上是这种写法,实际上运行的时候,还是要翻译生成java代码的。
④${usernam} 这个EL表达式等同于三目运算符这一段java代码:
采用EL表达式:${username}采用EL表达式:${usernam}
7、EL表达式取数据的时候有两种形式
①前面我们已经学习了"."的形式取出数据;
例如:${dept.dname}就等于${dept["dname"]},注意以"[]"形式取,一定要加上双引号[""]
②对于存在特殊字符的变量名,只能使用[""]的方式取
${requestScope.abc.def} 这样是无法取值的${requestScope["abc.def"]} 可以正常取值
8、从Map集合中取数据
语法格式:${map.key}
①创建一个Map集合,直接放入对应的数据后,在把Map集合放入request域
<% // 创建一个Map集合 Map map = new HashMap(); // 存入数据到map集合 map.put("username", "zhangsan"); map.put("password", "123"); // 将Map集合存储到request域当中。 request.setAttribute("userMap", map);%>${userMap.username}${userMap["username"]}
②先创建一个Map集合;在创建一个User类,给对应的属性赋值后把User类放入Map集合,最后在把Map集合放入request域,怎么取数据?
// 创建map集合 Map userMap = new HashMap(); // 创建user类 User user = new User(); // 给user类的name属性设置值 user.setUsername("lisi"); // 把user类放入map集合 userMap.put("user", user); // 将Map集合存储到request域当中 request.setAttribute("map", userMap);%>${map.user.username}
9、从数组和List集合中取数据
①对于数组和List集合中取数据,都可以采用下标的形式进行取:
对于数组:${数组[0]}
${nameArray} ${nameArray[0]} ${nameArray[1]}${nameArray[2]}
对于list集合:${list[0]}
<% //创建一个list集合 List list = new ArrayList(); // 调用add方法,添加数据 list.add("abc"); list.add("def"); // 把list集合放入request域 request.setAttribute("myList", list);%>${myList}${myList[0]}${myList[1]}
10、设置忽略EL表达式
①page指令当中,有一个isELIgnored属性,可以忽略EL表达式;
②默认是不忽略了,如果设置忽略,写出的EL表达式会被当做普通字符串输出
③isELIgnored="true" 表示忽略JSP中整个页面的所有EL表达式。如果想忽略其中某个,可以使用反斜杠"\"!
isELIgnored="true" 表示忽略EL表达式isELIgnored="false" 表示不忽略EL表达式。(这是默认值)isELIgnored="true" 这个是全局的控制。可以使用反斜杠进行局部控制:\${username} 。
11、通过EL表达式获取应用的根
①我们已经知道JSP有九大内置对象:pageContext,request,session,application,response,out,config,page,exception;其中四个域对象,其中最小的域是pageContext(页面上下文),通过pageContext可以获取应用的根
②在内置对象pageContext中有一个getRequest()方法,可以用来获取到request对象;但是JSP中九大内置对象中已经包含了request对象;所以看起来这个方法没有什么用!
③实际上在EL表达式当中没有request这个隐式对象,前面讲的requestScope 这个只代表“请求范围”,不等同于request对象;但是在EL表达式当中有一个隐式的对象:pageContext, EL表达式中的pageContext和JSP中的九大内置对象pageContext是同一个对象;这就很有意思了;所以在EL表达式中虽然没有request隐式对象,但是可以通过隐式对象pageContex获取到request对象;就可以写出下面等价的代码:
// 在JSP中pageContext内置对象调用getRequest()方法获取到request对象// 对应到EL表达式中pageContext隐式对象的代码就是${pageContext.request}
④所以获取到应用的根,就可以通过EL表达式获取:${pageContext.request.contextPath}
// 直接通过request对象获取应用的根// 先通过pageContext对象获取到request对象,在获取应用的根// 注意:这里强转是因为getContextPath()是HttpServletRequest对象的方法,而先获取到的request对象// 上面对应的EL表达式${pageContext.request.contextPath}
12、常用的隐式对象
(1)pageContext
①这个隐式对象已经讲过了,它是和JSP九大内置对象的pageContex是同一个对象;最主要的用法就是用来获取应用的根:${pageContext.request.contextPath}
(2)param
①假如前端发送请求(通过form表单或者地址栏上直接提交数据):http://localhost:8080/jsp/15.jsp?username=lisi 我们要想获得前端提交的数据,就要调用内置对象request的getParameter方法;那如果使用EL表达式呢?需要使用隐含对象"param.用户名"的形式:
用户名:
用户名:${param.username}
(3)paramValues
①那如果提交的数据是一个复选框(checkbox)呢?同一组的checkbox的name是一样的;例如:http://localhost:8080/jsp/15.jsp?aihao=smoke&aihao=drink&aihao=tangtou--%>;此时在按照原来的方式进行访问,获取的是一维数组当中的第一个元素,这就需要paramValues 隐式对象了!
爱好:${param.aihao}
爱好:
②使用paramValues获取的是一个字符串的一维数组
${paramValues.aihao}
③得到这个一维数组后,就可以通过下标的方式进行获取数组中的元素!
爱好:${paramValues.aihao[0]}、${paramValues.aihao[1]}、${paramValues.aihao[2]}
(4)initParam
①ServletContext是Servlet上下文对象,对应的JSP九大内置对象之一是:application
②取出的是标签中配置的属性,属于上下文初始化参数(全局的)
pageSize 20 pageNum 5
③web.xml文件配置好以后进行输出
每页显示的记录条数:
页码:
-------------------------等价于---------------------------------每页显示的记录条数:${initParam.pageSize}
页码:${initParam.pageNum}
13、EL表达式的运算符
(1)算术运算符:+(重点)、-、*、/、%
+在这里只做求和运算,不会做字符串拼接;如果是数字类型的字符串会自动转换为数字进行运算;如果不是数字类型的字符串会报500错误,并抛出NumberFormatException异常。
${10 + 20}
30 ${10 + "20"}
30${10 + "abc"}
500错误
(2)关系运算符:== 、eq(相当于==,重点)、 !=、 >、 >=、 <、 <=
使用==实际上会自动调用equals方法;所以比较的是内容,不是内存地址。实际上eq、!=底层也会调用equals方法。
${"abc" == "abc"}
true${"abc"} == ${"abc"}
abc == abc${k1 == k2}
true${o1 == o2}
false${a == b}
true
(3)逻辑运算符:! && || not and or
! 和 not 效果一样的,都是取反。
Student stu1 = new Student("110", "警察");Student stu2 = new Student("110", "警察");${!(stu1 eq stu2)}
false${not(stu1 eq stu2)}
false
(4)取值运算符:[ ]和.
前面代码经常在用了,就是取值的作用。
(5)empty运算符 (重点)
empty运算符的结果是boolean类型 ;判断是否为空,如果为空,结果是true。如果不为空,结果是false。
${empty param.username}
${!empty param.username}
取反${not empty param.username}
取反${param.password == null}
true ${empty param.password == null}
false
(6)条件运算符:? :
和empty联合使用,可以实现一个很简单的逻辑业务。
${empty param.username ? "对不起,用户名不能为空!" : "欢迎访问!!!!" }