0


JSP的简化:一文吃透EL表达式

在这里插入图片描述

本文被 系统学习JavaWeb 收录点击订阅专栏


文章目录


1 走进EL表达式

何为EL表达式?
EL(Expression Language) 是为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
EL表达式主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出。

下面来浅浅感受一下EL表达式的简洁:

<%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>Title</title></head><body><%
    request.setAttribute("key","值");%>
表达式脚本输出key的值:<%=request.getAttribute("key")%><br/>
EL表达式输出key的值: ${key}</body></html>

需要注意的是,使用表达式脚本的时候,若原key无值,则会显示null;而当使用EL表达式的时候,若原key无值,则不显示。

回顾一下上节关于jsp域对象的知识
域对象是可以像Map一样存取数据的对象,四个域对象的功能一样,区别是对数据的存取范围。

下表列举了四个域对象和作用范围
对象作用范围pageContext(PageContextImpl类)当前jsp页面范围request(HttpServletRequest类)一次请求内session(HttpSession类)一个会话范围内(打开浏览器访问服务器,直到关闭浏览器)application(ServletContext类)整个web工程范围内有效(只要web工程不停止,数据都在)
在EL表达式中也一样,当四个域中都有相同的key数据时,EL表达式会根据这四个域的从小到大顺序去搜索,找到就输出, 优先级从小到大顺序:

  1. pageContext
  2. request
  3. session
  4. application

2 关于EL表达式与Bean对象

2.1 什么是Java Bean?

JavaBean(是java类)是一种JAVA语言写成的可重用组件(Component)。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。众所周知,属性名称符合这种模式,其他Java 类可以通过自省机制(反射机制)发现和操作这些JavaBean 的属性。

一个JavaBean由3部分组成:

  1. 属性(properties)   JavaBean提供了高层次的属性概念,属性在JavaBean中不只是传统的面向对象的概念里的属性,它同时还得到了属性读取和属性写入的API的支持。属性值可以通过调用适当的bean方法进行。比如,可能bean有一个名字属性,这个属性的值可能需要调用String getName()方法读取,而写入属性值可能要需要调用void setName(String str)的方法。   每个JavaBean属性通常都应该遵循简单的方法命名规则,这样应用程序构造器工具和最终用户才能找到JavaBean提供的属性,然后查询或修改属性值,对bean进行操作。JavaBean还可以对属性值的改变作出及时的反应。比如一个显示当前时间的JavaBean,如果改变时钟的时区属性,则时钟会立即重画,显示当前指定时区的时间。
  2. 方法(method)   JavaBean中的方法就是通常的Java方法,它可以从其他组件或在脚本环境中调用。默认情况下,所有bean的公有方法都可以被外部调用,但bean一般只会引出其公有方法的一个子集。   由于JavaBean本身是Java对象,调用这个对象的方法是与其交互作用的唯一途径。JavaBean严格遵守面向对象的类设计逻辑,不让外部世界访问其任何字段(没有public字段)。这样,方法调用是接触Bean的唯一途径。   但是和普通类不同的是,对有些Bean来说,采用调用实例方法的低级机制并不是操作和使用Bean的主要途径。公开Bean方法在Bean操作中降为辅助地位,因为两个高级Bean特性–属性和事件是与Bean交互作用的更好方式。   因此Bean可以提供要让客户使用的public方法,但应当认识到,Bean设计人员希望看到绝大部分Bean的功能反映在属性和事件中,而不是在人工调用和各个方法中。
  3. 事件(event)   Bean与其他软件组件交流信息的主要方式是发送和接受事件。我们可以将bean的事件支持功能看作是集成电路中的输入输出引脚:工程师将引脚连接在一起组成系统,让组件进行通讯。有些引脚用于输入,有些引脚用于输出,相当于事件模型中的发送事件和接收事件。   事件为JavaBean组件提供了一种发送通知给其他组件的方法。在AWT事件模型中,一个事件源可以注册事件监听器对象。当事件源检测到发生了某种事件时,它将调用事件监听器对象中的一个适当的事件处理方法来处理这个事件。   由此可见,JavaBean确实也是普通的Java对象,只不过它遵循了一些特别的约定而已。

2.2 使用EL表达式输出复杂Bean对象

首先,我们先创建一个学生类,包括相应的set、get方法:

Student.java

importjava.util.Arrays;importjava.util.List;importjava.util.Map;/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */publicclassStudent{privateString name;privateint age;privateString[] phones;privateList<String> cites;privateMap<String,Object> map;publicStudent(){}publicStudent(String name,int age,String[] phones,List<String> cites,Map<String,Object> map){this.name = name;this.age = age;this.phones = phones;this.cites = cites;this.map = map;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicString[]getPhones(){return phones;}publicvoidsetPhones(String[] phones){this.phones = phones;}publicList<String>getCites(){return cites;}publicvoidsetCites(List<String> cites){this.cites = cites;}publicMap<String,Object>getMap(){return map;}publicvoidsetMap(Map<String,Object> map){this.map = map;}@OverridepublicStringtoString(){return"Student{"+"name='"+ name +'\''+", age="+ age +", phones="+Arrays.toString(phones)+", cites="+ cites +", map="+ map +'}';}}

jsp代码及EL表达式如下:

<%@ page import="com.hxh.expressionlanguage.Student"%><%@ page import="java.util.ArrayList"%><%@ page import="java.util.List"%><%@ page import="java.util.HashMap"%><%@ page import="java.util.Map"%><%--Created by IntelliJIDEA.
  User:26510Date:2022/10/24Time:10:31To change this template use File|Settings|FileTemplates.--%><%@ page contentType="text/html;charset=UTF-8" language="java"%><html><head><title>Title</title></head><body><%Student student =newStudent();
    student.setName("黄小黄");
    student.setPhones(newString[]{"15325367485","18811026589"});List<String> cites =newArrayList<>();
    cites.add("北京");
    cites.add("上海");
    cites.add("天津");
    cites.add("西安");
    student.setCites(cites);Map<String,Object> map =newHashMap<>();
    map.put("key1","value1");
    map.put("key2","value2");
    map.put("key3","value3");
    student.setMap(map);//存放到域对象中
    pageContext.setAttribute("s", student);%><%-- EL表达式获取值,并输出 --%>
输出student: ${s}<br>
输出student的name: ${s.name}<br>
输出student的phones数组的值: ${s.phones[0]}<br>
输出student的cites集合中的元素: ${s.cites}<br>
输出student的map集合: ${s.map}<br>
输出Map集合中某个key值: ${s.map.key1}<br></body></html>

结果如下:
在这里插入图片描述

注意事项:
EL表达式输出对象值,不是直接查找对应的属性,而是通过对应属性的get方法获取值, 也就是说,如果只声明了属性,而没有在对应类中提供相应的get方法,则无法通过EL表达式获取该属性值!


3 EL表达式的运算

3.1 关系运算

语法格式如下:

${运算表达式}

在这里插入图片描述

3.2 逻辑运算

在这里插入图片描述

3.3 算术运算

在这里插入图片描述

3.4 empty运算

empty运算可以判断一个数据是否为空,若为空,输出true,不为空,输出false。 以下几种情况为空(在原本的key之前加empty关键字):

  1. 值为null、空串
  2. 值为Object类型的数组且长度为0 (注:其他类型的长度为0的数组值为非空)
  3. List、Map集合元素个数为0

3.5 三元运算

表达式 1?表达式 2:表达式 3
表达式1为真返回表达式2的值,表达式1为假返回表达式3的值

示例代码及结果如下:

<body><%//1、值为null值时
        request.setAttribute("emptyNull",null);//2、值为空串时
        request.setAttribute("emptyStr","");//3、值是Object类型数组,长度为零的时候
        request.setAttribute("emptyArr",newObject[]{});//4、list集合,元素个数为零List<String> list =newArrayList<>();
        request.setAttribute("emptyList", list);//5、map集合,元素个数为零Map<String,Object> map =newHashMap<String,Object>();
        request.setAttribute("emptyMap", map);//6、其他类型数组长度为0
        request.setAttribute("emptyIntArr",newint[]{});%>
    ${ empty emptyNull }<br/>
    ${ empty emptyStr }<br/>
    ${ empty emptyArr }<br/>
    ${ empty emptyList }<br/>
    ${ empty emptyMap }<br/>
    ${ empty emptyIntArr}<br/><%-- 三元运算   --%>
    ${12!=12?"相等":"不相等"}</body>

在这里插入图片描述

3.6 点运算和中括号运算

  1. 点运算可以输出某个对象的某个属性的值(getXxx或isXxx方法返回的值)
  2. 中括号运算可以输出有序集合中某个元素的值

中括号运算可以输出Map集合中key里含有特殊字符的key的值

特殊字符:等于、大于小于、点等。

示例代码如下:

<body><%Map<String,Object> map =newHashMap<String,Object>();
        map.put("a.a.a","aaaValue");
        map.put("b+b+b","bbbValue");
        map.put("c-c-c","cccValue");
        request.setAttribute("map", map);%><%--特殊的key需要去掉最开始的"."并使用中括号和单引号(双引号)包起来--%>
    ${ map["a.a.a"]}<br><%--如果不加中括号则相当于三个.运算--%>//错误的是 ${map.a.a.a}
    ${ map["b+b+b"]}<br><%--如果不加中括号则相当于三个+运算--%>
    ${ map["c-c-c"]}<br><%--如果不加中括号则相当于三个-运算--%></body>

4 EL表达式的11个隐含对象

4.1 概述

EL表达式中的11个隐含对象是EL表达式自己定义的,可以直接使用。
在这里插入图片描述

4.2 获取四个特定域中的属性

<body><%
        pageContext.setAttribute("key1","pageContext1");
        pageContext.setAttribute("key2","pageContext2");
        request.setAttribute("key2","request");
        session.setAttribute("key2","session");
        application.setAttribute("key2","application");%><%--  获取特定域中的属性  --%>
    ${ pageScope.key1 }<br>
    ${ applicationScope.key2 }<%--  若直接获取key1或key2依然按照之前范围从小到大检索,无法获取指定域  --%></body>

4.3 pageContext对象的使用

pageContext常用于如下需求,在jsp的代码脚本中使用如下:

  • 获取请求的协议: request.getScheme()
  • 获取请求的服务器ip或域名: request.getServerName()
  • 获取请求的服务器端口号: request.getServerPort()
  • 获取当前工程路径: request.getContextPath()
  • 获取请求的方式: request.getMethod()
  • 获取客户端的ip地址: request.getRemoteHost()
  • 获取会话的唯一标识: session.getId()

在EL表达式中 更加简便,实现上述需求的代码如下:

<body><%-- 先通过pageContext对象获取request、session对象,再获取以下内容 --%>1.协议: ${ pageContext.request.scheme }<br>2.服务器ip:${ pageContext.request.serverName }<br>3.服务器端口:${ pageContext.request.serverPort }<br>4.获取工程路径:${ pageContext.request.contextPath }<br>5.获取请求方法:${ pageContext.request.method }<br>6.获取客户端ip地址:${ pageContext.request.remoteHost }<br>7.获取会话的id编号:${ pageContext.session.id}<br></body>

在这里插入图片描述
看到这里,是不是会感到困惑?
不是说EL表达式会更加简洁吗,为何在获取的时候语句长度反而比代码脚本要复杂呢?

在实际开发中,有一个小技巧,代码示例如下:

<body><%
    pageContext.setAttribute("req", request);
    pageContext.setAttribute("session", session);%>1.协议: ${ req.scheme }<br>2.服务器ip:${ req.serverName }<br>3.服务器端口:${ req.serverPort }<br>4.获取工程路径:${ req.contextPath }<br>5.获取请求方法:${ req.method }<br>6.获取客户端ip地址:${ req.remoteHost }<br>7.获取会话的id编号:${ session.id}<br></body>

提前将对应的对象设置成域对象,便于EL表达式访问,可以使代码更简洁!

4.4 param、paramValues对象的使用

<body>
    获取请求参数username的值:${ param.username }<br>
    获取请求参数password的值:${ param.password }<br>
    获取请求参数中第一个hobby的值:${ paramValues.hobby[0]}<br>
    获取请求参数中第二个hobby的值:${ paramValues.hobby[1]}<br><%--  有多个同名的key时使用paramValues的索引值决定获取哪一个,使用param只可获取第一个  --%>
    使用param获取hobby的值:${ param.hobby }<br></body>

4.5 header、headerValues对象的使用

<body>
    输出请求头[user-Agent]的值:${ header["User-Agent"]}<br>
    输出请求头中第一个[user-Agent]的值:${ headerValues["User-Agent"][0]}<br></body>

4.6 cookie对象的使用

<body>
    获取Cookie的名称:${ cookie.JSESSIONID.name }<br>
    获取Cookie的值:${ cookie.JSESSIONID.value }<br></body>

4.7 initParam对象的使用

<body>
    输出&lt;Context-param&gt;username的值:${ initParam.username }<br>
    输出&lt;Context-param&gt;url的值:${ initParam.url }<br></body>

写在最后

 本文部分内容参考:尚硅谷JavaWeb课程。好了,本文内容到这里就告一段落了,欢迎大家订阅专栏,加入JavaWeb学习!点击订阅
部分图片出处:EL表达式 @CSDN early_day

 如果你有任何问题,欢迎私信,感谢您的支持!
在这里插入图片描述
在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_60353039/article/details/127487256
版权归原作者 兴趣使然黄小黄 所有, 如有侵权,请联系我们删除。

“JSP的简化:一文吃透EL表达式”的评论:

还没有评论