1. JSP 技术的引入

在 JSP 出现之前,有两种方式获取 web 服务器端的资源,如果是静态 web 资源,可以直接让服务器去文件系统查找,如果是动态资源,则需要将请求转交给 servlet 去处理。但是会存在如下问题。

以下是一段 servlet 代码:

  1. public class HelloServlet extends HttpServlet{
  2. @Override
  3. protect void doGet(HttpServletRequest req, HttpServletResponse resp){
  4. PrintWriter out = resp.getWrite();
  5. resp.setHeader("Content-type", "text/html");
  6. out.write("<html>");
  7. out.write("<head>Hello</head>");
  8. out.write("<body>");
  9. out.write("<b>" + req.getParameter("username") + </b>);
  10. out.write("</body></html>");
  11. out.close();
  12. }
  13. }

可以看出,在 servlet 代码中,使用了拼接 html 的方式生成了一个 html 页面从而返回给客户端。也就是说其中既有 java 代码,又有大量的 html 标签语句。通常来说一个网站的 html 结构是很复杂的,这样显然是非常繁琐且不好维护的一件事。

JSP 的目的就是为了简化 servlet 的书写,它要做的事就是将 java 代码与 html 代码进行解耦。

2. JSP的运行原理

首先,JSP 就是 servlet,它的全称为 Java Server Page,即 Java 服务端页面。从名字可以看出它是一个页面,即它长得和 html 是很像的,但是它里面却又嵌入了 java 的代码,可以实现动态 web。

当客户端访问一个 jsp 页面时,发生的事情如下:

  1. 服务端首先会查找是否存在与该 jsp 对应的 servlet,如果有则直接调用它的 service 方法
  2. 如果不存在,则会对该 jsp 文件进行编译。所谓 jsp 文件的编译指的是首先将 jsp 翻译成 servlet 源文件(.java),再将 servlet 源文件编译称为 servlet 类(.class),之后再初始化并运行 servlet。

原理就是这么简单了。当然这只是表面上这么说,接下来深入源码来看看究竟是如何将一个 jsp 文件转化成一个 servlet 的。

首先当 tomcat 启动后,如果访问 jsp 资源,则会将 jsp 生成的源文件和类文件放在 /work 目录下。在 mac 中,由于 tomcat 是部署在 idea 目录下的,所以它的目录在 /Users/username/Library/Caches/JetBrains/IntelliJIdea/tomcat下。
截屏2021-07-20 下午2.46.21.png
这里可以看到,当访问 index.jsp 时,生成了两个文件:index_jsp.java 和 index_jsp.class,这就是 index.jsp 编译以后的产物。先来看看 index.jsp 文件长什么样:

  1. <html>
  2. <body>
  3. <h2>Hello, <%= request.getParameter("username")%></h2>
  4. </body>
  5. </html>

非常简单,其中使用了 jsp 的语法,目的就是打印出 username 的内容。

接下来访问如下 url:localhost:10086/cs?username=tom,此时页面就会显示 Hello,tom。

再来看下 index_jsp.java长什么样:

  1. package org.apache.jsp;
  2. import javax.servlet.*;
  3. import javax.servlet.http.*;
  4. import javax.servlet.jsp.*;
  5. public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
  6. implements org.apache.jasper.runtime.JspSourceDependent,
  7. org.apache.jasper.runtime.JspSourceImports {
  8. private static final javax.servlet.jsp.JspFactory _jspxFactory =
  9. javax.servlet.jsp.JspFactory.getDefaultFactory();
  10. private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
  11. private static final java.util.Set<java.lang.String> _jspx_imports_packages;
  12. private static final java.util.Set<java.lang.String> _jspx_imports_classes;
  13. static {
  14. _jspx_imports_packages = new java.util.HashSet<>();
  15. _jspx_imports_packages.add("javax.servlet");
  16. _jspx_imports_packages.add("javax.servlet.http");
  17. _jspx_imports_packages.add("javax.servlet.jsp");
  18. _jspx_imports_classes = null;
  19. }
  20. private volatile javax.el.ExpressionFactory _el_expressionfactory;
  21. private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
  22. public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
  23. return _jspx_dependants;
  24. }
  25. public java.util.Set<java.lang.String> getPackageImports() {
  26. return _jspx_imports_packages;
  27. }
  28. public java.util.Set<java.lang.String> getClassImports() {
  29. return _jspx_imports_classes;
  30. }
  31. public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
  32. if (_el_expressionfactory == null) {
  33. synchronized (this) {
  34. if (_el_expressionfactory == null) {
  35. _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
  36. }
  37. }
  38. }
  39. return _el_expressionfactory;
  40. }
  41. public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
  42. if (_jsp_instancemanager == null) {
  43. synchronized (this) {
  44. if (_jsp_instancemanager == null) {
  45. _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
  46. }
  47. }
  48. }
  49. return _jsp_instancemanager;
  50. }
  51. public void _jspInit() {
  52. }
  53. public void _jspDestroy() {
  54. }
  55. public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
  56. throws java.io.IOException, javax.servlet.ServletException {
  57. if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
  58. final java.lang.String _jspx_method = request.getMethod();
  59. if ("OPTIONS".equals(_jspx_method)) {
  60. response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
  61. return;
  62. }
  63. if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
  64. response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
  65. response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
  66. return;
  67. }
  68. }
  69. final javax.servlet.jsp.PageContext pageContext;
  70. javax.servlet.http.HttpSession session = null;
  71. final javax.servlet.ServletContext application;
  72. final javax.servlet.ServletConfig config;
  73. javax.servlet.jsp.JspWriter out = null;
  74. final java.lang.Object page = this;
  75. javax.servlet.jsp.JspWriter _jspx_out = null;
  76. javax.servlet.jsp.PageContext _jspx_page_context = null;
  77. try {
  78. response.setContentType("text/html");
  79. pageContext = _jspxFactory.getPageContext(this, request, response,
  80. null, true, 8192, true);
  81. _jspx_page_context = pageContext;
  82. application = pageContext.getServletContext();
  83. config = pageContext.getServletConfig();
  84. session = pageContext.getSession();
  85. out = pageContext.getOut();
  86. _jspx_out = out;
  87. out.write("<html>\n");
  88. out.write("<body>\n");
  89. out.write("<h2>Hello, ");
  90. out.write(request.getParameter("username"));
  91. out.write("</h2>\n");
  92. out.write("</body>\n");
  93. out.write("</html>\n");
  94. } catch (java.lang.Throwable t) {
  95. if (!(t instanceof javax.servlet.jsp.SkipPageException)){
  96. out = _jspx_out;
  97. if (out != null && out.getBufferSize() != 0)
  98. try {
  99. if (response.isCommitted()) {
  100. out.flush();
  101. } else {
  102. out.clearBuffer();
  103. }
  104. } catch (java.io.IOException e) {}
  105. if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
  106. else throw new ServletException(t);
  107. }
  108. } finally {
  109. _jspxFactory.releasePageContext(_jspx_page_context);
  110. }
  111. }
  112. }

文件内容很长,挑重点看,首先看第 7 行关于类的声明,可以看出 index_jsp 继承了 HttpJspBase 类。HttpJspBase 类的继承关系如下图所示:
截屏2021-07-20 下午2.57.57.png
是的,它实际上间接实现了 Servlet 接口,所以说 jsp 本质就是一个 servlet。

87-94 行,在该类中初始化了很多对象,包括了:

  • pageContext
  • session
  • application
  • config
  • out
  • page
  • _jspx_out
  • _jspx_page_context

除了 page 在初始化时就被赋值为 this 外,其他所有对象的赋值,都可以在 98-106 行找到。

108-114 行是 jsp 文件中的内容,这也是每个 jsp 翻译成 servlet 源文件后存在差异化的部分。可以看出,在翻译之后,自动的就把 html 代码和 java 代码区分开了。

这样一来,如果想要获取动态 web,就从以前请求 servlet 变成了请求 jsp(其实也就是请求 servlet)。以后写 jsp 时,也不用去拼接 html 和 java 代码,而是使用 jsp 语法去写即可,翻译 jsp 时会自动的将 html 和 java 代码区分开。

3. JSP语法

JSP 语法特点是尽可能的用标记来取代 java 代码,使整个 jsp 文件看起来不像 java 代码,而像一个标记文档

JSP 文件中除了能包含 HTML 文本外,还可以包含如下内容:

  • JSP 指令
  • JSP 声明
  • Java 程序片段
  • Java 表达式
  • JSP 隐含对象

JSP 文件的模板文本默认类型为 HTML,当然我们可以将其设置为纯文本(text/plain)的形式。

3.1 JSP 指令

JSP 指令用来设置整个 jsp 页面的相关属性,比如编码方式和脚本语言等。它的语法格式为:
<%@ 指令名 属性="值" %>。常用的三种指令为:page、include和taglib。

3.1.1 page 指令

该指令可以指定所使用的的编程语言,与 jsp 对应的 servlet 所实现的接口、所拓展的类以及导入的包等。其语法格式如下:<%@ page 属性1="值1" 属性2="值2" %>。具体的属性请参考本文

3.1.2 include 指令

该指令可以在翻译阶段去包含其他文件(.jsp/.html),它能够在翻译阶段把外部文件和当前的 jsp 文件进行合并(merge),并一同进行编译。该指令可以写在 jsp 文件内的任何地方。它的语法格式为:<%@ include file="relative path" %>

文件的路径如果在声明时只有一个文件名的话,那么就会默认在当前 jsp 文件的路径下找。

该指令的应用场景在于:假设一个 web 应用很多网页的设计风格都相同,那么必然包含相同的 html 代码,此时就可以将这部分代码抽象出去,而在不同页面中将它们包含进来就好了,可以减少代码量。

3.2 JSP 声明

JSP 声明语句可以声明一个或多个与 JSP 相关的 servlet 类的变量与方法。语法如下:
<%! declaration;[declaration]... %>

  1. <%! int v1 = 0; %>
  2. <%! int v1, v2, v3; %>
  3. <%! String v4 = "hello";
  4. static int v6;
  5. %>
  6. <%!
  7. public String amethod(int i){
  8. if(i < 3) return "i < 3";
  9. else return "i >=3";
  10. }
  11. %>

3.3 Java 程序片段(Java Scriptlet)

Java 程序片段简单理解就是一段 java 代码,语法如下:<% java-statement %>。当然官方的定义更加严谨,定义如下:

A JSP scriptlet is used to contain any code fragment that is valid for the scripting language used in a page. When the scripting language is set to java, a scriptlet is transformed into a Java programming language statement fragment and is inserted into the service method of the JSP page’s servlet. A programming language variable created within a scriptlet is accessible from anywhere within the JSP page.

大概意思就是说,所谓 Scriptlet 就是包含了任何有效的脚本代码的任意代码片段。这段代码会被插入到与该 jsp页面对应的 servlet 的 service() 方法中。由于这里讨论的是 javaweb,自然是使用 Java 作为脚本语法。在该 JSP 页面的任何位置都可以访问到在脚本程序片段中声明的变量。

Any text, HTML tags, or JSP elements you write must be outside the scriptlet.

任何的文本、html 标签或是 JSP 的元素都必须写在scriptlet的外面。

3.4 Java 表达式

Java 表达式的语法格式如下:<%= expression %>,它会将表达式的值转化成字符串并且插入到它所在 jsp 文件的位置。紧接着它会跟着数据流一同被发送给客户端。

需要注意的是,在 Java 表达式中不允许使用分号,即使在 scriptlet 中使用相同的表达式带有分号。

3.5 隐含对象

Servlet 可以访问由 Servlet 容器提供的 ServletContext、ServletRequest、ServletResponse等对象。同样的,在 JSP 中可以访问对应的对象,只是这些对象是“隐藏”起来的。

在分析运行原理时,已经看到在将 jsp 翻译成 servlet 源文件后,源文件中已经声明并初始化了若干个对象,这些对象就可以拿来直接使用,JSP 的隐含对象共有 9 种:

隐含对象的引用变量 隐含对象的类型
request javax.servlet.HttpServletRequest
response javax.servlet.HttpServletResponse
pageContext javax.servlet.jsp.PageContext
application javax.servlet.ServletContext
out javax.servlet.jsp.JspWriter
config javax.servlet.ServletConfig
page java.lang.Object
session javax.servlet.http.HttpSession
exception java.lang.Exception

其中,request、pageContext、application、session这四个对象都可以用来设置属性,但是通过它们设置的属性作用域却不尽相同。按作用域从小到大排列顺序为:pageContext、request、session、application。

  • pageContext:只在当前页面内有效
  • request:只在单次请求内有效
  • session:在整个会话范围内有效
  • application:在整个 web 应用内有效

4. JSP 的生命周期

与 servlet 不同,jsp 文件需要经过一系列的过程才能成为一个 servlet。这个过程分为以下阶段:

  1. 解析阶段:servlet 容器对 jsp 文件进行解析,如果有语法错误,则直接向客户端返回错误信息
  2. 翻译阶段:servlet 容器将 jsp 文件翻译成 servlet 源文件
  3. 编译阶段:servlet 容器编译 servlet 源文件,产生 servlet 类文件
  4. 初始化阶段:加载与 jsp 对应的 servlet 类,创建其实例,并调用它的_jspInit()方法
  5. 运行时阶段:调用与 jsp 对应的 servlet 实例的_jspService() 方法
  6. 销毁阶段:调用与 jsp 对应的 servlet 实例的_jspDestroy()方法

其中后三个阶段是 jsp 和 servlet 共有的,因为到了初始化阶段,jsp 才变成了一个 servlet。前三个阶段是 jsp 被 servlet 容器变成 servlet 的阶段,它们仅发生于如下三种场合:

  • JSP 文件被用户首次访问
  • JSP 文件被更新
  • 与 JSP 文件对应的 servlet 类的类文件被手工删除

从上面还可以看出,jsp 是一种热部署,即 servlet 容器会自动定期扫描 jsp 文件的更新,并重新编译生成对应的 servlet 类文件(我猜的),并不需要重新启动 servlet 容器才能实现代码的更新。但是之前使用 servlet 时,如果需要更新 servlet,需要重启 servlet 容器才行,因为那样才能重新编译修改后的 servlet。


— JSP 技术的发展 —

自从 JSP 技术诞生后,它的发展目标就是是 JSP 的代码变的更加简洁和精炼,为了达到这个目标,就要尽可能的把 JSP 文件中的 Java 代码分离出去,最终使 JSP 文件中只有 HTML 和 JSP 标签,而在后续 JSP 技术的发展也确实都朝着这一目标前进。这些技术包括了:

  • 把 JSP 文件中的 Java 程序代码放到 JavaBean 中,JSP 文件通过专门的标签访问 JavaBean
  • 用 EL 表达式替换 Java 表达式,即 <%= expression %>
  • 在 JSP 文件中使用 JSTL(JSP 标准标签库)
  • Web 应用采用 MVC 设计模式的框架(比如Spring MVC框架),使得 JSP 位于视图层,用来展示数据,不用负责流程控制与业务逻辑。

接下来的内容就是围绕着这些升级技术展开的。


5. EL 表达式

EL 表达式是 JSP 2.0 引入的新特性,它简化了 JSP 代码的书写,可以在替代传统的形如 <%= expression %> 的 Java 表达式和部分基于 <% %> 的 Java 程序片段

5.1 基本语法

EL 表达式的基本形式为:${var}。如果在 JSP 文件中使用 EL 表达式,那么表达式的值会输出到网页上。此外,EL 表达式还可以作为 JSP 标签属性的值。

5.1.1 访问对象的属性和数组的元素

EL 表达式可以使用 . 运算符来访问对象的属性,此外可以使用中括号来访问数组的元素。

  1. ${param.username} // 访问param对象的username属性值
  2. ${customers[0]} // 访问customers数组的第一个元素

5.1.2 EL 运算符

EL 表达式支持算术运算符、逻辑运算符和关系运算符,此外还支持 empty 运算符和条件运算符。

  • 算术运算符:+、-、*、/、%
  • 逻辑运算符:&&、||、!
  • 关系运算符:==、!=、>=、>、<、<=
  • empty 运算符:检查是否为空,语法为 ${empty var},如果 var 为空,则返回 true
  • 条件运算符(三目运算符):a?b:c

截屏2021-07-21 下午4.23.50.png如果想在网页上展示 EL 表达式,需要对 $ 进行转义,方法为在该符号前面加上反斜杠即可。

5.1.3 隐含对象

EL 语言定义了 11 种内置隐含对象,可以直接访问这些对象的属性。在这 11 种对象中,有 10 种类型都是 Map 类型。截屏2021-07-21 上午11.46.57.png这 11 中隐含对象可以分为以下四类:

  1. 表示 HTTP 请求的特定数据
    1. header
    2. headerValues
    3. param
    4. paramValues
    5. cookie
  2. 表示特定范围
    1. applicationScope
    2. requestScope
    3. sessionScope
    4. pageScope
  3. 表示 pageContext 对象
    1. pageContext
  4. 表示 web 应用的初始化参数集合
    1. initParam

5.1.4 命名变量

EL 表达式中的变量称为命名变量,它不是 JSP 文件中的局部变量或实例变量,而是存放在特定范围内的属性。命名变量的名字和特定范围内的属性名对应。

例如,${username} 等价为以下代码:

  1. <%
  2. String username = (String) pageContext.findAttribute("username");
  3. if (username != null) {
  4. %>
  5. <%=username%>
  6. <%
  7. }
  8. %>

5.2 定义和使用 EL 函数

EL 表达式可以访问 EL 函数,EL 函数实际上和 Java 类中的方法对应。这个 Java 类必须由 public 修饰,且作为函数方法必须声明为 public static。在 Java 类定义好之后,需要在 .tld 文件中,把 Java 类方法映射成函数。

以一个案例来说明如何定义和使用 EL 函数:

  1. 编写 Tools 类。该类提供了两个静态方法

    1. public class Tools {
    2. // 计算两个int的和
    3. public static int add(String a, String b) {
    4. int x = 0;
    5. int y = 0;
    6. x = Integer.parseInt(a);
    7. y = Integer.parseInt(b);
    8. return x + y;
    9. }
    10. // 将字符串改成大写
    11. public static String convert(String str) {
    12. return str.toUpperCase();
    13. }
    14. }
  2. 在 tld 文件中,将 Tools 类的 add() 方法映射为 add 函数,convert() 方法映射为 convert 函数。具体做法为创建名为 mytaglib.tld 文件,并将其放在 WEB-INF 目录下 ```java <?xml version=”1.0” encoding=”UTF-8” ?>

    1.0 mytaglib

    /mytaglib add x and y add com.kc.Tools int add(java.lang.String, java.lang.String) convert encoding convert com.kc.Tools java.lang.String convert(java.lang.String)

  1. 3. web.xml 文件中增加 <taglib> 元素。该元素用于声明 web 应用会访问 uri /mytaglib 的标签库,以及指定了该标签库的 TLD 文件路径
  2. ```java
  3. <jsp-config>
  4. <taglib>
  5. <taglib-uri>/mytaglib</taglib-uri>
  6. <taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
  7. </taglib>
  8. </jsp-config>

— 标签库的引入 —

之前已经说到了 JSP 技术的发展趋势就是尽可能的在 JSP 文件中把 Java 代码分离出去,取而代之的是使用标签的方式来访问 Java 代码。

在定义与使用 EL 函数小结中,梳理下我们做了什么:

  1. 定义了一个 Java 类,在里面编写了两个静态方法
  2. 将 Java 类中定义的方法与 EL 函数方法做一个映射
  3. 在 web.xml 中配置 taglib 元素

核心思想就在于一段 Java 代码做的事,在 JSP 文件中能用一个函数或者标签去搞定,如果要实现这种能力,自然就需要把 Java 代码中的方法与函数或者标签做一个映射。那么 JSP 又是如何识别这些函数和标签的呢?有关这些函数和标签的描述信息都放在了 .tld 文件中;通过配置 web.xml,web 应用能够知道 .tld 文件的路径并访问到该文件。

TLD(taglib descriptors):标签库描述符是一个 XML 文档,其中包含有关整个库以及库中包含的每个标签的信息。 Web 容器使用 TLD 来验证标签。taglib 技术的推出,使得各大厂商推出了自己的标签库,比如 Sun 公司提供的 JSTL(JSP Standard Taglib)就是接下来要具体学习的内容。


6. JSTL

6.1 如何使用 JSTL 标签

JSTL 是 sun 公司提供的一套标签库,由于是第三方提供的,所以如果想使用 JSTL 标签,那么需要按照以下步骤去操作:

  1. 把 standard.jar 文件复制到 /lib 目录或者 WEB-INF/lib 目录下
  2. 在 JSP 文件中,通过 taglib 指令声明标签库
    1. // 声明 jstl core 标签库
    2. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    3. // 使用标签库内的标签
    4. <c:out value="${param.username}" default="unknown" />
    第 1 步如果使用 maven 依赖,需要配置两个依赖: ```html javax.servlet.jsp.jstl jstl-api 1.2

taglibs standard 1.1.2

  1. <a name="WUNzQ"></a>
  2. ### 6.2 JSTL 标签库的分类
  3. 根据标签的功能可能分为如下 5 类:
  4. - **
  5. - **格式化标签**
  6. - **SQL 标签**
  7. - **XML 标签**
  8. - **JSTL 函数**
  9. ![截屏2021-07-22 上午1.00.24.png](https://cdn.nlark.com/yuque/0/2021/png/12951212/1626886832628-17190cb4-7c4c-4e2c-b942-b9a9d3df68b6.png#clientId=u16abe7d1-5e54-4&from=ui&id=u7f56fac5&margin=%5Bobject%20Object%5D&name=%E6%88%AA%E5%B1%8F2021-07-22%20%E4%B8%8A%E5%8D%881.00.24.png&originHeight=202&originWidth=661&originalType=binary&ratio=1&size=108414&status=done&style=none&taskId=u6009d1d2-a07f-42fa-90e9-cc61fc57f8f)
  10. <a name="HEos2"></a>
  11. ### 6.3 核心标签
  12. > 不介绍其他标签,用的时候查就可以了。
  13. <a name="TOxVK"></a>
  14. #### 6.3.1 <c:out>标签
  15. 该标签能把一个表达式的值打印到网页上,这个表达式既可以是传统的形如 <%= %> 的 Java 表达式,也可以是 EL 表达式。它的语法格式为:`<c:out value="表达式" />`。如果表达式的值为 null,则输出空串。
  16. 此外还可以采用如下两种方式设置默认值:
  17. ```html
  18. <%-- 方式一: 使用default属性设置默认值 -->
  19. <c:out value="expression" default="default value" />
  20. <%-- 方式二: 用标签主体设置默认值 -->
  21. <c:out value="expression" >
  22. default value
  23. </c:out>

6.3.2 标签

该标签具有以下作用:

  • 为 String 类型的命名变量设定值
  • 如果命名变量为 JavaBean,则为这个 JavaBean 对象的特定属性设置值
  • 如果命名变量为 Map 类型,则为这个 Map 的指定 Key 设置值 ```html
  1. 为String类型的命名变量设置值

  2. 为 JavaBean 对象的特定属性设置值

  3. 为 Map 的指定 Key 设置值 ```

6.3.3 标签

该标签用于删除特定范围内的命名变量,语法格式为:
<c:remove var="变量名" scope="{page|request|session|application}" />

6.3.4 标签

该标签用于捕获标签主体范围内出现的异常,并将异常对象作为命名变量保存在页面范围内。它的语法格式为:
<c:catch var="代表异常对象的命名变量的名字" />

6.3.5 标签

该标签用于实现 Java 中的 if 功能,语法格式为:

  1. <c:if test="逻辑表达式" var="用于存储逻辑表达式结果的变量" scope="{page|request|session|application}" />

6.3.6 标签

这三个标签连用,可以实现 Java 中 if-else 语句。它的语法格式为:

  1. <c:choose>
  2. <c:when test="<boolean>">
  3. ...
  4. </c:when>
  5. <c:when test="<boolean>">
  6. ...
  7. </c:when>
  8. ...
  9. ...
  10. <c:otherwise>
  11. ...
  12. </c:otherwise>
  13. </c:choose>

使用该系列需要注意几点:

  1. 不能单独使用,必须位于 标签内
  2. 可以有多个, 可以没有
  3. 如果有 ,必须放在 后面

6.3.7 标签

这两个标签封装了 Java 中的 for,while,do-while 循环。

标签是更加通用的标签,因为它迭代一个集合中的对象。标签通过指定分隔符将字符串分隔为一个数组然后迭代它们。它们的语法格式如下:

  1. ---forEach 语法格式---
  2. <c:forEach
  3. items="<object>" // 被循环的信息
  4. begin="<int>" // 开始的元素(0=第一个元素,1=第二个元素),默认为0
  5. end="<int>" // 最后一个元素(0=第一个元素,1=第二个元素),默认为last element
  6. step="<int>" // 步长
  7. var="<string>" // 代表当前条目的变量名称
  8. varStatus="<string>"> // 代表循环状态的变量名称
  9. ...
  10. ---forTokens 语法格式---
  11. <c:forTokens
  12. items="<string>"
  13. delims="<string>" // 分隔符
  14. begin="<int>"
  15. end="<int>"
  16. step="<int>"
  17. var="<string>"
  18. varStatus="<string>">

6.3.8 标签

这三个标签都与 URL 相关:

  • - 包含其他 web 资源
  • - 按照特定的规则重新构造 url
  • - 重定向