目录
一:深入学习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表达式:Expression Language(表达式语言) 。
②EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观。
③JSP中夹杂着各种java代码,例如<% java代码 %>、<%=%>等,导致JSP文件很混乱,不好看,不好维护!所以才有了后期的EL表达式。
④EL表达式可以算是JSP语法的一部分,EL表达式归属于JSP。
从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器。这就是EL表达式的功效;三大功效:
①第一功效:从某个域中取数据。 四个域:pageContext、request、session、application
②第二功效:将取出的数据转成字符串。如果是一个java对象,也会自动调用java对象的toString方法将其转换成字符串。
③第三功效:将字符串输出到浏览器。和<%= %>效果一样,将其输出到浏览器。
${表达式}
①注意:EL表达式只负责取,不负责存。
②我们来看下面一个例子,调用 request的setAttribute("username","zhangsan");方法存入数据;以前取的话是使用<%=request.getAttribute("username")%>这种方式取;但是现在使用EL表达式只需要简介的一句话:${username}。
<%@page contentType="text/html;charset=UTF-8" %>
<%
// 向request作用域当中存储数据
request.setAttribute("username","zhangsan");
%>
<%--将request域当中的数据取出来,并且还要输出到浏览器,使用java代码的方式--%>
<%=request.getAttribute("username")%>
<%--使用EL表达式--%>
${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='北京'}
<%@ page import="com.bjpowernode.javaweb.jsp.Dept" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<%
// 创建一个java对象
Dept dept = new Dept();
dept.setDeptno("10");
dept.setDname("研发部");
dept.setLoc("北京");
// 将这个对象放到request域当中
request.setAttribute("userObj",dept);
%>
${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错误。
①${abc}表示从某个域中取出数据,并且被取的这个数据的name是"abc",之前一定有这样的代码: 域.setAttribute("abc", 对象);
②${"abc"} 表示直接将"abc"当做普通字符串输出到浏览器,不会从某个域中取数据了。
①EL表达式优先从小范围中读取数据。
②pageContext < request < session < application
<%
// 四个域都存储了数据,并且name相同。
session.setAttribute("data", "session");
request.setAttribute("data", "request");
pageContext.setAttribute("data", "pageContext");
application.setAttribute("data", "application");
%>
<%--在没有指定范围的前提下,EL表达式优先从小范围中取数据--%>
<%--pageContext < request < session < application --%>
${data}
③在EL表达式中可以指定范围来读取数据;EL表达式有4个隐含的隐式的范围对象:
pageScope 对应的是 pageContext范围。
requestScope 对应的是 request范围。
sessionScope 对应的是 session范围。
applicationScope 对应的是 application范围。
<%--以下是指定范围取数据--%>
${pageScope.data}
${requestScope.data}
${sessionScope.data}
${applicationScope.data}
①EL表达式主要任务是做页面展示,要求最终页面展示上是友好的。
②所以EL表达式对null进行了处理。如果是null,则在浏览器上显示空白。
③EL表达式表面上是这种写法,实际上运行的时候,还是要翻译生成java代码的。
④${usernam} 这个EL表达式等同于三目运算符这一段java代码:<%=request.getAttribute("usernam") == null ? "" : request.getAttribute("usernam")%>
<%@page contentType="text/html;charset=UTF-8" %>
<%
request.setAttribute("username", "zhangsan");
%>
<%--取出数据并且输出到浏览器,都能正常输出到浏览器--%>
<%=request.getAttribute("username")%>
采用EL表达式:${username}
<%--故意写错,前者取出来的是null,后者显示的是空白--%>
<%=request.getAttribute("usernam")%>
采用EL表达式:${usernam}
①前面我们已经学习了"."的形式取出数据;
例如:${dept.dname}就等于${dept["dname"]},注意以"[]"形式取,一定要加上双引号[""]
②对于存在特殊字符的变量名,只能使用[""]的方式取
<%
// 向request域当中存储数据。
request.setAttribute("abc.def", "hello");
%>
<%--将数据取出并输出到浏览器--%>
${requestScope.abc.def} 这样是无法取值的
${requestScope["abc.def"]} 可以正常取值
语法格式:${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);
%>
<%--使用EL表达式,将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);
%>
<%--使用EL表达式,将map中的数据取出,并输出到浏览器--%>
${map.user.username}
①对于数组和List集合中取数据,都可以采用下标的形式进行取:
对于数组:${数组[0]}
<%
// 数组对象
String[] usernames = {"zhangsan", "lisi", "wangwu"};
// 向request域中存储数组
request.setAttribute("nameArray", usernames);
%>
<%--使用EL表达式取出数组中的元素--%>
${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);
%>
<%--取出List集合--%>
<%--list集合也是通过下标的方式取数据的。--%>
${myList}
${myList[0]}
${myList[1]}
①page指令当中,有一个isELIgnored属性,可以忽略EL表达式;
②默认是不忽略了,如果设置忽略,写出的EL表达式会被当做普通字符串输出
③isELIgnored="true" 表示忽略JSP中整个页面的所有EL表达式。如果想忽略其中某个,可以使用反斜杠"\"!
<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>
isELIgnored="true" 表示忽略EL表达式
isELIgnored="false" 表示不忽略EL表达式。(这是默认值)
isELIgnored="true" 这个是全局的控制。
可以使用反斜杠进行局部控制:\${username} 。
①我们已经知道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对象
<%=pageContext.getRequest() %>
// 对应到EL表达式中pageContext隐式对象的代码就是
${pageContext.request}
④所以获取到应用的根,就可以通过EL表达式获取:${pageContext.request.contextPath}
// 直接通过request对象获取应用的根
<%=request.getContextPath()%>
// 先通过pageContext对象获取到request对象,在获取应用的根
// 注意:这里强转是因为getContextPath()是HttpServletRequest对象的方法,而先获取到的request对象
<%=((HttpServletRequest)pageContext.getRequest()).getContextPath() %>
// 上面对应的EL表达式
${pageContext.request.contextPath}
(1)pageContext
①这个隐式对象已经讲过了,它是和JSP九大内置对象的pageContex是同一个对象;最主要的用法就是用来获取应用的根:${pageContext.request.contextPath}
(2)param
①假如前端发送请求(通过form表单或者地址栏上直接提交数据):http://localhost:8080/jsp/15.jsp?username=lisi 我们要想获得前端提交的数据,就要调用内置对象request的getParameter方法;那如果使用EL表达式呢?需要使用隐含对象"param.用户名"的形式:
用户名:<%=request.getParameter("username")%>
用户名:${param.username}
(3)paramValues
①那如果提交的数据是一个复选框(checkbox)呢?同一组的checkbox的name是一样的;例如:http://localhost:8080/jsp/15.jsp?aihao=smoke&aihao=drink&aihao=tangtou--%>;此时在按照原来的方式进行访问,获取的是一维数组当中的第一个元素,这就需要paramValues 隐式对象了!
<%--param 获取的是请求参数一维数组当中的第一个元素--%>
爱好:${param.aihao}
爱好:<%=request.getParameter("aihao")%>
②使用paramValues获取的是一个字符串的一维数组
${paramValues.aihao}
<%=request.getParameterValues("aihao")%>
③得到这个一维数组后,就可以通过下标的方式进行获取数组中的元素!
爱好:${paramValues.aihao[0]}、${paramValues.aihao[1]}、${paramValues.aihao[2]}
(4)initParam
①ServletContext是Servlet上下文对象,对应的JSP九大内置对象之一是:application
②取出的是
标签中配置的属性,属于上下文初始化参数(全局的)
pageSize
20
pageNum
5
③web.xml文件配置好以后进行输出
每页显示的记录条数:<%=application.getInitParameter("pageSize")%>
页码:<%=application.getInitParameter("pageNum")%>
-------------------------等价于---------------------------------
每页显示的记录条数:${initParam.pageSize}
页码:${initParam.pageNum}
(1)算术运算符:+(重点)、-、*、/、%
+在这里只做求和运算,不会做字符串拼接;如果是数字类型的字符串会自动转换为数字进行运算;如果不是数字类型的字符串会报500错误,并抛出NumberFormatException异常。
${10 + 20}
30
<%-- 在EL表达式当中“+”运算符只能做求和运算;不会进行字符串拼接操作 --%>
<%--"20"会被自动转换成数字20--%>
${10 + "20"}
30
<%-- java.lang.NumberFormatException: For input string: "abc" --%>
<%-- + 两边不是数字的时候,一定会转成数字。转不成数字就报错:NumberFormatException--%>
${10 + "abc"}
500错误
(2)关系运算符:== 、eq(相当于==,重点)、 !=、 >、 >=、 <、 <=
使用==实际上会自动调用equals方法;所以比较的是内容,不是内存地址。实际上eq、!=底层也会调用equals方法。
${"abc" == "abc"}
true
${"abc"} == ${"abc"}
abc == abc
<%
Object obj = new Object();
request.setAttribute("k1", obj);
request.setAttribute("k2", obj);
%>
${k1 == k2}
true
<%
Object o1 = new Object();
Object o2 = new Object();
request.setAttribute("o1", o1);
request.setAttribute("o2", o2);
%>
${o1 == o2}
false
<%
String s1 = new String("hehe");
String s2 = new String("hehe");
request.setAttribute("a", s1);
request.setAttribute("b", s2);
%>
${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}
取反
<%--前提:访问的时候,地址栏上没有给password传参--%>
${param.password == null}
true
<%--前半部分是boolean类型,后面是null--%>
${empty param.password == null}
false
(6)条件运算符:? :
和empty联合使用,可以实现一个很简单的逻辑业务。
${empty param.username ? "对不起,用户名不能为空!" : "欢迎访问!!!!" }