哔哩哔哩蛙课网【动力节点】JavaWeb-Eclipse版学习视频网址
解析 | 归属 | 备注 | |
---|---|---|---|
Java Server Pages | java 服务器页面 | JSP基础 | |
out. write () | JSP 写出 代码 | JSP基础 | 属于 IO流 |
<% %> |
Java 代码块 | JSP基础 | 翻译到_jspService() 中 |
<%! %> |
声明语句块 | JSP基础 | 可以声明变量、方法 |
<%= %> |
表达式块 | JSP基础 | out.print() |
pageContext | 页面上下文 | pageContext | |
set、getAttribute() | 设置、获得属性 | pageContext | 可获得八个内置对象 |
application | 应用 | pageContext | 即ServletContext |
page | 页面指令 | pageContext | 即Servlet对象本身 |
exception | 例外 | pageContext | 要配合着 page指令使用 |
import | 导入指定的类 | pageContext | |
errorPage | 错误页面 | pageContext | 发生异常时的跳转 |
session | 一会 | JSP page 指令 | 2无参方法,没有就创建一个 |
include | 包含指令 | JSP指令、动作 | |
forward | 转发动作 | JSP 动作 | |
pageContextpageConext | 页相关域页相关域 | 域属性空间域 | |
requestrequest | 请求域请求域 | 域属性空间域 | |
sessionsession | 会话域会话域 | 域属性空间域 | |
applicationapplication | 应用域应用域 | 域属性空间域 | |
Expression Language | EL表达式 | EL表达式 | |
${key.属性} | EL 的获得属性方式 | EL表达式 | |
${key[索引]} | EL 获得索引 | EL表达式 | |
${attributeName.mapKey} | EL 获得Map | EL表达式 | |
${pageContext.request} | 获取 request | EL表达式 | |
${param.参数名} | 获得请求中指定值 | EL表达式 | |
${paramValues.参数名[索引]} | 获得某数组值 | EL表达式 | |
${initParam.初始化参数名} | 获得指定初始化的值 | EL表达式 | |
${.tld文件名:内方法名(参数)} | 自定义 EL 函数 | EL表达式 | |
Standard Tag Library | 标准标签库 | JSTL | |
SimpleTag | 标签处理器 | 自定义标签 | 自定义标签的功能接口 |
SimpleTagSupport | 标签处理器实现类 | 自定义标签 | |
|
标签体 | 注册标签处理器 | |
empty | 空,没有标签 | ||
scriptless | 无脚本 | 无java脚本,但能EL计算 | |
tagdependent | 标记相关 | 会将 EL 传递成普通字符串 | |
invoke(Writer) | 调用,写 | JspFragment | 写入到输出流中 |
|
false 意思只能为常量 | 注册标签处理器 | Runtime Expression Value |
forEachList | 遍历 list 集合 | 自定义标签 | |
forEach | 遍历其他 | 自定义标签 | 除去Int等基本数据类型 |
Arrays.asList() | 数组转 list 集合 | forEach | |
Collection | 收集 | forEach | doTag()方法中的遍历对象 |
getClass().isArray() | 判断是否为数组 | forEach | |
JSP Standard Tag Library | JSTL 标准标签库 | JSTL | |
c:set | 进行变量定义 | JSTL | |
c:remove | 删除域属性空间内变量 | JSTL | |
c:out | 页面输出 | JSTL | default 预设,当没有值时输出 |
c:catch | 捕获异常 | JSTL | |
c:choose | 多分支判断 | JSTL | |
c:otherwise | 其他 | c:choose | |
varStatus = | 引用型变量 | c:forEach | 添加序号 |
fmt:formatDate | 不同模式的格式化日期 | 格式化标签库 | |
fmt:parseDate | 字符串转日期类型 | 格式化标签库 | |
fmt:formatNumber | 对数字进行格式化 | 格式化标签库 | |
fmt:parseNumber | 字符串转换为数组类型 | 格式化标签库 | |
View 层 | 接收用户请求层 | 三层框架 | |
Service 层 | 业务逻辑层 | 三层框架 | |
Dao 层 | 操作数据库层 | 三层框架 | |
trim() | 去掉前后文 | ||
executeQuery() | 执行结果查询 | SQL |
JSP,即 Java Server Pages,Java 服务器页面,即运行在服务器端的页面。它是由 Sun 公司倡导,许多国际性大公司参与,一起建立的一种动态网页技术。JSP 技术是在传统的静态网页 HTML文件中插入 Java 代码片断和 JSP 标签后形成的一种文件,其后缀名为 .jsp。使用 JSP 开发的 Web应用是跨平台的,既能在 Linux 上运行,也能在其他操作系统上运行。
在 Eclipse 下的 Web 工程的 WebContent 目录中新建一个 JSP 文件,例如新建一个 index.jsp文件。
在 jsp 文件中写入如下内容:
Hello JSP Woeld!
然后运行这个 Web 项目,在浏览器中即可看到 “ Hello JSP World! ” 字样。
打开 Eclipse 的工作空间 workspace 的如下子目录,可看到两个文件:
workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost
源码文件 index_jsp.java 就是由刚才的 Web 项目中的 Index.jsp 文件转变成的 Java 文件。而 index_jsp.class 文件为 index_jsp.java 文件编译后的字节码文件。
我们的.jsp 文件
打开这个 index_jsp.java 文件,发现其继承自 HttpJspBase 类。
使用Open Type 查询 HttpJspBase,连接 Tomcat 的源码
打开 Tomcat 的源码目录中的 java 子目录,在其中查看 HttpJspBase 的源码,发现其继承自 HttpServlet。
也就是说,JSP 文件的本质是 Servlet
只不过,JSP 与 Servlet 不同的是,JSP 是专门用于进行数据展示的 Servlet,其有特殊的写法
而普通的 Servlet 是用于完成业务逻辑处理的
由于 Servlet 是运行在单例多线程环境下的,所以 JSP 同样也是运行在单例多线程环境下的。
将 JSP 页面翻译为 Servlet 的过程,是由 Tomcat 完成。
在 Tomcat 中内置了一个 JSP 翻译引擎,当第一次访问该 JSP 页面时,翻译引擎会将 JSP 页面翻译为 Servlet 的.java 文件,再将其编译为.class 文件进行运行。
SUN 公司制定的 JavaEE 规范中包含两个很重要的子规范:Servlet 规范,及 JSP 规范。
其中 JSP 规范中就包含了如何将 JSP 页面翻译为 Servlet。例如, 页面中的 HTML、 JavaScript,JSPCSS、及普通文本部分,均会被翻译到 out. write ()中。
Tomcat 中的 JSP 翻译引擎,就遵循了这个 JSP 规范。
在 JSP 页面中使用注释,可以将要注释的内容使用<%-- --%>
括起来。
当然,在 JSP 页面中也可以使用 HTML 的注释。 但它们的使用效果是不同的。
HTML 注释会被 JSP 翻译引擎翻译到 Servlet 的 out.write()中;而 JSP 注释则会被 JSP 翻译引擎忽略,在 Servlet 中是看不到的。
在客户端浏览器查看源码时,HTML 注释是可以查看到的;但 JSP 注释在客户端是查看不到的。
例如,在 JSP 页面中写入如下注释:
This is my JSP page.
<%-- 这是JSP注释 --%>
查看 Tomcat 服务器的 work 目录中由 JSP 引擎翻译过的 Servlet,可以看到:
查看客户端浏览器的源码文件,可以看到:
JSP 的 Java 代码块也称为 JSP 小脚本,是以<% %>
括起来的部分,其中可以编写 Java代码。
编写在 Java 代码块中的代码,会被 JSP 翻译引擎将其置入到 Servlet 的_jspService()
方法中作为方法中的 Java 语句出现。所以,其中存放的必须是以分号结尾的 Java 语句。
需要注意的是,JSP 代码块可以放置在 JSP 页面的任意位置,可以放置任意数量。但它们都会被按照顺序放置到 Servlet 的_jspService()
方法中。也就是说,其执行顺序是与其在 JSP页面中的出现顺序是一致的。例如,
被翻译到 Servlet 的_jspService()方法中为:
由于 JSP 小脚本是被翻译到了 Servlet 的_jspService()方法中,所以 JSP 小脚本中是不能出现如下内容的:
但是能出现 Java 注释语句 // /* */
在 JSP 页面中使用<%! %>
括起来的部分,称为声明语句块。声明语句块中的内容,将被 JSP 引擎翻译到 Servlet 的类体中,没有包含到哪个方法体中。
这样的话,在 JSP 的声明语句块中就可声明实例变量、实例方法、静态方法、静态代码块等内容。并且,这些内容均可被 JSP 的 Java 代码块中代码访问。因为它们原本就是一个Servlet 类中的代码。
不过,还是不建议在 JSP 的声明语句块中声明实例变量。因为 JSP 是运行在单例多线程环境下的,实例变量将会引起线程安全问题。
需要注意的是,在 JSP 的声明语句块中,是不能编写普通的 Java 语句的。否则的话,这些语句将会直接出现在 Servlet 的类体中。
声明语句块也可以定义在 JSP 页面的任意位置,且可以定义任意多个。
在 JSP 的 Java 代码块与声明语句块中,均可使用 Java 的单行注释与多行注释。该注释将会出现在 Servlet 中的相应位置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTFUwepM-1628937484709)(JavaWeb-jsp.assets/image-20210808164346670.png)]
在 JSP 页面中使用<%= %>
括起来的部分,称为表达式块。其可在 JSP 页面中输出变量、常量,及它们组成的各种表达式的值。
注意,是表达式,而不是语句,是没有分号的。该表达式将被 JSP 引擎翻译到_jspService()
方法的 out.print()方法中输出。例如:
被 JSP 引擎翻译为 Servlet 后为:
在 JSP 的 Java 代码块、表达式块等中可以直接使用的引用,称为 JSP 的内置对象。
这九个对象在 JSP 的 Java 代码块、表达式块中可以直接使用。只所以可以直接使用,是因为 Java 代码块与表达式块被 JSP 引擎翻译后均出现在了 Servlet 的_jspS ervice()
方法中。
而这九个对象,就是_jspService()
方法中的局部变量。
在 JSP 的 Java 代码块、表达式块中的代码就是_jspService()
方法中的代码,所以在其中可以直接使用。
pageContext,页面上下文,其具有一个只在当前页面范围的域属性空间,即其具有setAttribute()方法与 getAttribute()方法。
但,由于在当前页面范围,数据不存放到域属性空间也可直接使用,将数据存放到域属性空间反而感觉“多此一举” 所以这些方法并不常用。
不过,在同一页面中,为了使用 EL 表达式(后面学习)来访问某变量的值,此时一般使用
pageContext
pageContext 具有一些 get 方法,可以获取到 Request、Response、Session、ServletContext、ServletConfig、page(即当前 Servlet)、exception、out 等另外八个内置对象。
但由于这些对象本身就是内置对象,在 JSP 页面中可以直接使用,所以这些方法也并不常用。不过,在后面将要学习的 EL 表达式中,将会经常使用 pageContext 的这些方法。
application,即 ServletContext。所以 ServletContext 所具有的方法,application 都具有。
常用的方法例如,
String getInitParameter ():
获 取 web.xml 文 件 的 中 指 定 名 称 的 上 下 文 参 数 值 。 例 如getInitParameter(“myDBDriver”);会返回字符串“com.mysql.jdbc.Driver”。
Enumeration getInitParameterNames():
获取 web.xml 文件的
中的所有的上下文参数名称。其返回值为枚举类型 Enumeration
。
void setAttribute(String name, Object object):
在 ServletContext 的公共数据空间中,也称为域属性空间,放入数据。这些数据对于 Web应用来说,是全局性的,与整个应用的生命周期相同。当然,放入其中的数据是有名称的,通过名称来访问该数据。
Object getAttribute(String name):
从 ServletContext 的域属性空间中获取指定名称的数据。
void removeAttribute(String name):
从 ServletContext 的域属性空间中删除指定名称的数据。
String getRealPath(String path):
获取当前 Web 应用中指定文件或目录在本地文件系统中的路径,是基于盘符的路径。
String getContextPath():
获取当前应用在 Web 容器中的名称。
out,类型为 javax.servlet.jsp.JspWriter。查看 JavaEE 文档,发现 JspWriter 类继承自 IO流的 Writer 类。即 out 就是一个输出流对象。
查看 JSP 翻译为的 Servlet,可以看到 page 对象即 Servlet 对象本身。这个对象在实际应用中并不常用。
在普通的 JSP 页面中是不能使用 exception 内置对象的。因为打开 JSP 翻译为的 Servlet,发现其中并没有exception 对象。若要在页面中直接使用 exception 对象,则需要配合着 page指令使用。page 指令后面讲解。
其它对象,还有 request、response、session,及 config。它们的用法与之前 Servlet 学习时的用法相同。只不过是直接使用在了 JSP 页面中了。
JSP 指令的作用是为当前页面做一些基本的属性设置,为当前的页面的运行提供基本的环境。
根据功能的不同,JSP 中包含三类指令:
page 指令,即页面指令;
include 指令,即包含指令;
及 taglib 指令,即标签库指令。
无论哪种指令,其使用的语法格式均为如下形式:
taglib 指令在后面学习 JSTL 时再进行讲解。
page 指令用于设置当前 JSP 页面的相关信息。一个 JSP 文件中可以包含多个 page 指令。
常用的 page 指令的属性意义及用法如下:
pageEncoding 属性
pageEncoding 属性用于设置当前 JSP 页面所使用的字符编码格式。即,用户在浏览器中通过右击查看编码所看到的编码格式。
其被 JSP 翻译引擎翻译到 Servlet 中的语句,是_jspService()方法中的 setContentType()。
contentType 属性
contentType 属性用于设置当 前 JSP 页面呈现于用户浏览器中的内容类型,通 常为”text/html”类型,即 html 格式的文本。若在 JSP 页面中设置如下:
对应 JSP 翻译引擎翻译过的 Servlet 中的语句,则为_jspService()方法中的如下语句:
但,若直接通过 contentType 属性指定内容类型与字符编码:
则生成的 Servlet 语句仍为:
所以,当内容类型为”text/html”时,使用 pageEncoding 属性与 contentType 属性效果是相同的。只有当内容类型不为”text/html”时,才专门使用 contentType 属性指定。在指定字符编码时,这两个属性一般不同时使用
import 属性
import 属性,用于完成在 JSP 页面中导入指定的类。其被 JSP 引擎翻译为 Servlet 中的import 语句。
例如:
在 Servlet 中被翻译为了:
若要导入多个类,则在 import 属性值中可使用逗号将这些类分隔。
在 Servlet 中将被翻译为多个 import 语句:
修改年月日格式
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.*,java.text.*"%>
Insert title here
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date now = new Date();
out.print("now = " + sdf.format(now));
%>
errorPage 属性
errorPage 属性用于指定,当前页面运行过程中发生异常时所要跳转到的页面。
需要注意的是,该属性会被翻译到 Servlet 的_jspService()
方法中,即这里出现的路径是一个后台路径,而非前台路径。所以这里指定的发生异常后所要跳转的页面,需要使用以斜杠开头的后台路径。
isErrorPage 属性
若一个页面中指定了发生异常后所要跳转的页面,将会出现一个问题:异常信息被隐藏了。在控制台看不到异常信息,在所跳转的页面中也看不到异常信息。这对于程序员来说,不是件好事,没有足够的信息提示。
此时,一般是希望当异常发生后,在所要跳转的页面中能够给出相应的异常信息。而异常信息是封装在异常对象 exception 中的。也就是说,我们需要在所要跳转的页面中能够获取到异常对象。此时,就需要将这个所要跳转的页面指定为“错误处理页面”。
当一个页面的 page 指令中设置 isErrorPage 的值为 true 时,表明当前页面为一个“错误处理页面”。默认 isErrorPage 的值为 false。
一旦一个页面 page 指令的 isErrorPage 属性被指定为了 true,查看 JSP 页面所翻译为的Servlet 则会发现,在_jspService()
方法中,多出了一个变量 exception。这就是内置对象exception,可以在 JSP 的 Java 代码块、表达式块中直接使用的内置对象。
session 属性
session 属性用于指定当前页面中是否可以直接使用内置对象 session。默认为 true,可以使用。查看 JSP 翻译为的 Servlet,可以看到 session 的创建,使用的是无参方法 getSession()。
该方法的功能是,若当前具有 session,则使用当前的 session;若当前没有 session,则会新建一个 session。即 session 对象肯定不为 null。
但,有些情况下,我们希望的仅仅是获取到之前已经存在的 session,若之前没有 session,则并不需要创建 session,即让 session 为 null。
显示使用默认的 session 属性为 true 已经无法满足需求了。此时,就需要将 session 属性设置为 false,即不使用内置对象 session,而是在JSP 页面的代码块中使用 request 的带参 getSession()方法。
HttpSession session = request.getSession(false);
若设置 session 属性的值为 false,查看生成的 Servlet 代码,会发现根本就没有出现内置
对象 session。
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page session="false"%>
Insert title here
<%
// 使用request的getSession()的原则:
// 若向Session域中存放数据,则使用getSession(true),即getSession()
// 若从Session域中读取数据,则使用getSession(false)
HttpSession session = request.getSession(false);
if(session != null) {
String user = (String) session.getAttribute("user");
out.print("user = " + user);
}
out.print("session = " + session);
%>
include 指令,即包含指令,用于将指定的文件包含到当前的 JSP 文件中。
该指令只有一个属性 file,用于指定要包含的文件。
用法
被 include 指定包含的文件,可以是 JSP 动态页面文件,也可以是 HTML 静态页面文件。这里定义一个名为 left.jsp 的动态文件。其中定义了一个变量 sum。
再定义一个 index.jsp,不仅将 left.jsp 文件包含了进来,还访问了变量 sum。
运行结果为:
静态联编
查看 Tomcat 的 work 目录中相关子目录,发现只生成了一个index_jsp.java
的 Servlet 源文件,并没有生成 left_jsp.java
文件。
那是因为 JSP 翻译引擎在翻译时,会将 include 指令所指定的文件内容直接翻译到当前 JSP 对应的 Servlet 中,形成一个 .java 文件。
这就说明一个问题:这个包含操作是在编译之前完成的,是在编译之前由 JSP 翻译引擎完成的,不是在程序运行期完成的。这种包含是一种静态包含,称为静态联编。
由于在编译期就将这些文件合并为了一个 Servlet 文件,所以,整个过程就一个_jspService()
方法。也就是说,这些文件之间是可以相互访问局部变量的。只要满足变量声明与使用的先后顺序即可。
为什么使用 include 指令
对于一个包含很多页面的系统或站点,很多页面的头部、底部,或者左侧部分都是相同的。
为了减少页面定义的重复性工作,为了便于对这些相同部分的修改,我们将这些相同的部分,分别定义为了多个页面。然后,让其它需要使用这些部分的页面,使用 include 指令将这些部分包含进来。
这样的话,不仅大大减少了工作量,还做到了对于页面修改的“一改全改”效果。
在 JSP 页面中大量使用 Java 代码块、表达式块等内容,会使 JSP 页面看起来“杂乱无章”。
为了使 JSP 页面看得简洁明了,为了简化 Java 代码,一般情况下,我们会尽量少的使用 Java代码块与表达式块。
取而代之的则是使用 EL 表达式、JSTL 标签(后面学习),及 JSP 动作。
JSP 动作是指,使用系统定义好的标签来完成本应由 Java 代码来完成的功能。
JSP 动作的语法格式为:
或
JSP 动作很多,但在实际开发时常用的就两个:转发动作与包含动作。
这两份个动作的完成,底层使用的是 RequestDispatcher 的 **forward()**与 **include()**方法实现的。
而这两份种请求转发方式的本质区别是,标准输出流的开启时间不同。
forward()方式的标准输出流是在目标资源中开启的标准输出流, include()方式的标准输出流则是在当前发而出包含运作的页面中开启的。
所以,forward()动作的发起页面中是无法向标准输出流中写入数据的;而 include()动作的发起页面及目标页面中均可向标准输出流中写入数据。
这两份个动作都具有一个 page 属性,用于指定要转向的页面。
页面中一旦具有了 forward 动作,那么当前页面中的所有要显示的内容都将无法显示。因为页面直接转发到了下一个页面。
定义 index.jsp 页面
定义 next.jsp 页面
运行结果:只显示 next.jsp 内容,index.jsp 未显示
打开 JSP 页面翻译为的 Servlet,可以看到要跳转的路径出现在了 Servlet 代码中,即可以使用后台路径。
注意,在 JSP 动作中,没有用于完成重定向的动作。
include 动作用于完成将指定页面包含到当前页面中的功能。
用法
定义 index.jsp 页面
定义 left.jsp 页面
运行结果:
动态联编
打开 Tomcat 的 work 目录的相关子目录,可以看到有两个.java 文件:index_jsp.java 与left_jsp.java。
也就是说,包含动作的包含,是在运行期完成的,而非在编译期。
这个包含动作,是在程序运行过程中,由 index_jsp 文件中的_jspService()
方法通过 JspRuntimeLibrary 类的 include()方法调用了 left_jsp 文件中的_jspService()
方法。
在运行期所执行的这种包含,称为动态联编。
静态联编与动态联编的应用场景
在静态联编与动态联编均可使用时,一般使用静态联编。因为在程序运行时只存在一个Servlet,对资源的消耗较少,且不存在调用问题,执行效率较高。
若在两个文件间需要共享同一变量,此时只能使用静态联编。
若在两个文件间存在同名变量,且不能混淆,此时只能使用动态联编。
EL,Expression Language,表达式语言,是一种在 JSP 页面中获取数据的简单方式。
EL表达式是从 JSP2.0 版本开始才引入的概念。
EL 表达式的基本语法形式很简单:在 JSP 页面的任何静态部分均可通过${expression}
的形式获取到指定表达式的值。
从四大域中依次查找数据
EL 只能从 pageConext、request、session、application 四大域属性空间中获取数据。
以下方式是无法获取到指定数据的。因为这个数据没有存放在四大域属性空间中。
此时,可以将这个值存放到四大域属性空间中的任意一个中。然后访问其存放时的 key即可。
我们发现,无论是将变量存放到了哪一个域属性空间,通过${key}
的方式,均可访问到该数据的值。
到底是从哪个域空间中查找指定的 key 的呢?
其底层实际是从最小范围依次EL查找,直到查找到最大范围 application。这期间,只要查找到了,则直接获取,后面的域空间将不再查找。若最终没有查找到,s则什么也不输出。
缺点:依次寻找,执行效率低
从指定域中获取数据
从 pageContext 依次查找到 application 域空间,会降低执行效率。
若某属性确定存放在某个域属性空间,则可指定直接从该空间中查找。
此时需要借助 EL 的四个域属性空间相关的内置对象。
序号 | 内置对象 | 说明 |
---|---|---|
1 | pageScope | 从 page 范围域属性空间中查找指定的 key |
2 | requestScope | 从 request 范围域属性空间中查找指定的 key |
3 | sessionScope | 从 session 范围域属性空间中查找指定的 key |
4 | applicationScope | 从 application 范围域属性空间中查找指定的 key |
访问 Bean 的属性
EL 可以通过 ${key.属性} 的方式获取到指定对象的指定属性值。其底层实际调用的是该对象的相应属性的 get 方法。
当然,也可以使用 ${key[‘属性’]或${key[“属性”]
的方式获取。该方式不常用。
当然,若要访问一个对象的域属性的值,则可多次使用点号运算符,依次取出相应的属性值。
首先定义 School 类:
然后再定义 Student 类:
在 JSP 页面中访问:
student 里的 school 里的 sname
获取数组中的元素
EL 可以通过 ${key[索引]}
的方式获取到指定索引的元素。
不过,需要注意的是,若数组中不存在该指定索引的元素,系统并不会抛出数组越界异常。
获取 List 中的元素
与获取数组中的元素相同,通过 ${key[索引]}
的方式可以获取 List 中指定索引的元素。
若 List 中不存在该指定索引的元素,系统并不会抛出越界异常。
不过,需要注意的是,EL 无法输出 Set 集合中的元素。因为 Set 集合中的元素具有无序性,即没有索引的概念。无法通过索引获取元素。
获取 Map 中的元素
EL 通过${attributeName.mapKey}
的方式可以获取指定 Map 的指定 key 的值。
可以将 Object 自动强转成 String类型
EL 表达式可以进行各种运算,其中常用的运算符有:
序号 | 种类 | 预算符 |
---|---|---|
1 | 计算运行符 | + - * / % (不支持 ++、–) |
2 | 关系运算符 | == != > >= < <= |
3 | 逻辑运算符 | ! && || not and or |
4 | 条件运算符 | ? : |
5 | 取值运算符 | [] 点号. |
<%@ page pageEncoding="UTF-8" import="com.bjpowernode.beans.*, java.util.*"%>
Insert title here
<%
String username = null;
String schoolName = "";
List students = new ArrayList<>();
pageContext.setAttribute("username", username);
pageContext.setAttribute("schoolName", schoolName);
pageContext.setAttribute("students", students);
%>
empty name = ${empty name }
empty username = ${empty username }
empty schoolName = ${empty schoolName }
empty students = ${empty students }
就像 JSP 的 Java 代码块及表达式块中可以使用九个内置对象一样,EL 表达式中,同样也存在有内置对象,并且存在 11 个内置对象。常用的内置对象,除了前面使用过的四个域属性空间相关的内置对象外,还有如下几个。
pageContext
该 pageContext 与 JSP 内置对象中的 pageContext 是同一个对象。通过该对象,可以获取到 request、response、session、servletContext、servletConfig 等对象。
注意,这些对象在 EL 中不是内置对象。这些对象只能通过 pageContext 获取。
在 EL 中直接${pageContext.request}
即可获取 request 对象。
当然,其底层实际调用的是pageContext.getRequest()方法。同理,也可以通过类似方式获取到其它对象。
在这些获取的对象中,有一个是实际工程中最常用的:
${pageContext.request.contextPath}
,用于获取当前项目的发布到服务器的名称,一般会用在 JSP 页面的路径前。
在 EL 的 11 个内置对象中,除了 pageContext 外,其它 10 个内置对象,其类型均为java.util.Map 类型。
param
在 EL 中通过 ${param.参数名}可获取到请求中指定参数名的值。 例如,提交的请求为:
在 JSP 页面中通过如下方式,可获取到 name 参数的值为 abc。
param.name = ${param.name}
paramValues
若提交的请求中同一参数具有多个值,则可通过${paramValues.参数名[索引]}
获取到指定索引号的该参数值。
例如,提交的请求为:
在 JSP 页面中获取方式如下:
bobby[0] = ${paramValues.hobby[0]}
bobby[1] = ${paramValues.hobby[1]}
在浏览器中显示内容如下:
initParam
在 EL 中通过使用 ${initParam.初始化参数名} 可以获取到指定的初始化参数的值。例如,在 web.xml 中定义了初始化参数 xxxName。
在 JSP 的 EL 中可访问该初始化参数:
程序代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
name = ${param.name }
age = ${param.age }
hobby[0] = ${paramValues.hobby[0] }
hobby[1] = ${paramValues.hobby[1] }
hobby[2] = ${paramValues.hobby[2] }
company = ${initParam.company }
address = ${initParam.address }
EL 中存在一个问题:不支持字符串的操作。
就连最简单的字符串连接,例如${“ab” + “cd”}
都不支持,运行会报错。
更不要提将字符串中的字符转换为全大写、判断一个字符串中是否包含另一个子串等操作,EL 本身更是无法完成。
但 EL 支持自定义函数,可以在 EL 中调用自定义的函数来完成这些功能。
下面以实现“将一个字符串转换为全大写”功能为例,来讲解自定义 EL 函数的过程。
定义函数
定义一个 POJO 类,在该类中定义一个静态方法。该方法可以实现将字符串转换为全大写字母的功能。
注册函数
在 Web 项目的/WEB-INF 目录下,新建一个扩展名为.tld 的 XML 文件,例如 myfn.tld。
tld,即 Tag Library Definition,标签库定义。将定义好的函数,在这个文件中进行注册。
1、添加约束
XML 文件是需要在文件中添加相应约束的,即添加配置文件头部信息。
这个头部信息可以从 Tomcat 的 webapps 中的/examples/WEB-INF/jsp2/jsp2-example-taglib.tld 文件中复制。
这个 .tld 的XML 文件,需要定义在当前 Web 项目的 WEB-INF 目录下
2、添加其它子标签(标签库信息)
在
根标签下添加其它子标签。
指定定义的当前函数库版本号。随意指定。
指定该函数库的名称,一个函数库一个名称,即一个 tld 文件一个
。名称随意,但一般与文件名相同,这个名称在后面 JSP 中要使用。
指定该函数库所对应的 URL,一个函数库一个 URL,即一个 tld 文件一个 URL。 随意,URL在后面 JSP 中要使用该 URL。
3、注册函数
在
根标签的
子标签下添加
子标签,注册函数。
指定将来在 JSP 的 EL 中使用该函数的名称。一般与类中静态方法同名。
指定该函数定义在哪个类中。
指定该函数的签名,即在指定类中的哪个方法,而且必须是全名。
tld 代码
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<