第7章 EL和JSTL


学习目标

在JSP开发中,为了获取Servlet域对象中存储的数据,经常需要书写很多Java代码,这样的话会使JSP页面混乱。为了降低JSP页面的复杂度,增强代码的重用性,Sun公司制定了一套标准标签库JSTL,同时为了获取Servlet域对象中存储的数据,JSP 2.0规范还提供了EL(表达式语言),大大降低了开发的难度。

1. EL

1.1 EL基本语法

(1) EL的概念

EL全称为Expression Language,即表达式语言。它是JSP 2.0引入的一个新内容。EL可以简化JSP开发中的对象(setAttribute|getAttribute)引用,从而规范页面代码,增加程序的可读性及可维护性。

(2) EL的语法

${表达式}

\${  表示输出字符 ${
# 转义输出

(4) EL基本语法的特点

参照ch04创建ch07_zzh项目,创建ch07首页index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <meta charset="UTF-8">
    <title>ch07 EL和JSTL(郑佐汉)</title>
  </head>
  <body>
  <h1>ch07 EL和JSTL(郑佐汉)</h1>
  <hr>
  <h3>EL</h3>
  <a href="01myServlet">1. JSP表达式与EL表达式对比</a><br>
  <a href="02pageContext_zzh.jsp">2. pageContext隐含对象</a><br>
  <a href="03scopes_zzh.jsp">3. 域相关对象---使用EL表达式查询属性名的属性值</a><br>
  <a href="04param_zzh.jsp?姓名=鲁智深&爱好=吃肉&爱好=喝酒">4. param和paramValues隐含对象----传递、获取请求参数</a><br>
  <a href="04param_zzh.jsp">  param和paramValues隐含对象----传递、获取请求参数</a><br>
  <a href="05cookie_zzh.jsp">5. 提取和添加Cookie (如提取的cookie为空时,请再次执行)</a><br>
  <a href="06initParam_zzh.jsp">6. initParam对象(提取web.xml文件中&lt;context-param>参数值)</a><br>
  <a href="07elServlet">7. EL表达式小结</a><br>
  <h3>JSTL</h3>
  <a href="08c_test_zzh.jsp">8. JSTL测试</a><br>
  <a href="09c_out1_zzh.jsp">9. JSTL c:out value属性</a><br>
  <a href="09c_out1_zzh.jsp?用户名=郑佐汉">  JSTL c:out value属性 带请求参数:用户名=郑佐汉</a><br>
  <a href="09c_out2_zzh.jsp">  JSTL c:out escapeXml属性 </a><br>
  <a href="09c_out2_zzh.jsp?用户名=郑佐汉">  JSTL c:out escapeXml属性 带请求参数:用户名=郑佐汉</a><br>
  <a href="09c_out3_zzh.jsp">  JSTL c:out escapeXml属性 </a><br>
  <a href="10c_remove1_zzh.jsp">10. JSTL c:remove 移除属性 </a><br>
  <a href="11c_if_zzh.jsp">11. JSTL c:if 判断条件 </a><br>
  <a href="12c_choose_zzh.jsp">12. JSTL c:choose 选择判断</a><br>
  <a href="12c_choose_zzh.jsp?用户名=郑佐汉">  JSTL c:choose 选择判断,带请求参数:用户名=郑佐汉</a><br>
  <a href="12c_choose_zzh.jsp?用户名=吴婉婷">  JSTL c:choose 选择判断,带请求参数:用户名=吴婉婷</a><br>
  <a href="13c_foreach1_zzh.jsp">13. JSTL c:foreach 遍历数组、Map</a><br>
  <a href="14c_foreach2_zzh.jsp">14. JSTL c:foreach遍历 指定范围初值、终值和步长值</a><br>
  <a href="15c_url_zzh.jsp">15. JSTL c:url</a><br>
  <a href="16c_redirect_zzh.jsp">16. JSTL c:redirect 重定向url</a><br>
  <h3>任务:根据不同请求参数值显示不同的页面内容</h3>
  <a href="17if_zzh.jsp?action=mon">参数 星期一</a><br>
  <a href="17if_zzh.jsp?action=tues">参数 星期二</a><br>
  <a href="17if_zzh.jsp?action=wed">参数 星期三</a><br>
  <a href="17if_zzh.jsp?action=thu">参数 星期四</a><br>
  <a href="17if_zzh.jsp?action=fri">参数 星期五</a><br>
  <a href="17if_zzh.jsp?action=sat">参数 星期六</a><br>
  <a href="17if_zzh.jsp?action=sun">参数 星期日</a><br>
  <hr>
  <p><a href="http://101.42.158.247/21javaweb.html">返回课程首页</a>
  郑佐汉 <script>document.write(document.lastModified); </script> 制作</p>
  </body>
</html>

运行结果如下:

图1 ch07 EL和JSTL--首页

cn.zzh.servlet.MyServlet.java

package cn.zzh.servlet;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/01myServlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        req.setAttribute("username", "zzhzhaojiang");
        req.setAttribute("password", "123456");
        req.setAttribute("用户名", "郑佐汉");
        req.setAttribute("密码", "654321");
        RequestDispatcher dispatcher = req
                .getRequestDispatcher("/01myjsp_zzh.jsp");
        dispatcher.forward(req, resp);
    }
}

01myjsp.jsp

<%@ page language="java" contentType="text/html; charset=utf-8" %>
<html>
<head>
   <title>JSP表达式与EL表达式对比</title>
</head>
<body>
    <h1>JSP表达式与EL表达式对比</h1>
    <hr>
    使用JSP表达式:<br/>
    username:<%=request.getAttribute("username")%><br>
    password:<%=request.getAttribute("password")%><br>
    用户名:<%=request.getAttribute("用户名")%><br>
    密 码:<%=request.getAttribute("密码")%><br>
    <hr>
    使用EL表达式:<br>
    用户名:${username}<br>
    密 码:${password}<br>
    用户名:${用户名}<br>
    密 码:${密码}<br>
</body>
</html>

运行结果如下:

图2 JSP表达式和EL表达式对比

1.2 EL中的标识符、关键字、变量、常量

(1) EL中标识符的规范

在EL中,经常需要使用一些符号标记一些名称,如变量名、自定义函数名等,这些符号被称为标识符。EL中的标识符可以由任意的大小写字母、汉字、数字和下划线组成,为了避免出现非法的标识符,在定义标识符时还需要遵循以下规范:

(2) EL中的关键字

and         eq           gt           true           instanceof    
or         ne           le           false           empty    
not         lt           ge           null           div           mod

(3) EL中变量

EL中的变量就是一个基本的存储单元(就是 .setAttribute("属性名",值)中的属性名,EL中的变量不用事先定义就可以直接使用。通过表达式${变量名}就可以访问变量[变量名]的值。

${变量名}

(4) EL中常量

/*
布尔常量: true和false
整型常量: Long.MIN_VALUE到Long.MAX_VALUE之间
  Long.MIN_VALUE: 
  Long.MAX_VALUE: 
浮点数常量: Double.MIN_VALUE到Double.MAX_VALUE之间
  Double.MIN_VALUE到
  Double.MAX_VALUE
,即4.9E-324~1.8E308之间的浮点数。
字符串常量: 引号或双引号引起来的一连串字符
  转义:由于字符串常量需要用单引号或双引号引起来,所以字符串本身包含的单引号或双引号需要用反斜杠(\)进行转义,即用“\'”表示字面意义上的单引号,用“\"”表示字面意义上的双引号。如果字符串本身包含反斜杠(\),也要进行转义,即用“\\”表示字面意义上的一个反斜杠。
Null:表示变量引用的对象为空

需要注意的是:

1.3 EL访问数据

# 点运算符(.)
${customer.name}
# customer对象中的name属性。

# 方括号运算符([])
# 当获取的属性名中包含一些特殊符号,如“-”或“?”等非字母或数字的符号,就只能使用中括号运算符访问该属性。
${user["My-Name"]}

EL中的运算符在实际中的应用

1.4 EL中的运算符

(1) 算术运算符

算术运算符 说明 算术表达式 结果
+ ${10+2} 12
- ${10-2} 8
- 负号 ${-2} -2
* ${10*2} 20
/(或div) ${10/4}或${10 div 2} 2.5
%(或mod) 取模(取余) ${10%4}或${10 mod 2} 2

(2) 比较运算符

比较运算符 说明 算术表达式 结果
==(或eq) 等于 ${10==2}或${10 eq 2} false
!=(或ne) 不等于 ${10!=2}或${10 ne 2} true
<(或lt) 小于 ${10<2}或${10 lt 2} false
>(或gt) 大于 ${10>2}或${10 gt 2} true
<=(或le) 小于等于 ${10<=2}或${10 le 2} false
>=(或ge) 大于等于 ${10>=2}或${10 ge 2} true

为了避免与JSP页面的标签产生冲突,对于后4种比较运算符,EL中通常使用上表中括号内的表示方式,例如,使用“lt”代替“<”运算符,如${1 lt 2}

(3) 逻辑运算符

逻辑运算符 说明 算术表达式 结果
&&(and) 逻辑与 ${true && false}或${true and false} false
\ \ (or) 逻辑或 ```${false true}或${false or true}``` true

(4) empty运算符

${empty expression}

用来判断一个对象或变量是否为null或空。

(5) 条件运算符

${A?B:C}

(6) “()”运算符

EL中的小括号用于改变其他运算符的优先级。

优先级 运算符
1 [ ] .
2 ( )
3 -(unary) not ! empty
4 * / div % mod
5 + -(binary)
6 < > <= >= lt gt le ge
7 == != eq ne
8 && and
9 \ \ or
10 ?:

2. EL隐式对象

为了能够获得Web应用程序中的相关数据,EL提供了11个隐式对象,这些对象类似于JSP的内置对象,可以直接通过对象名进行各种操作。在EL的隐式对象中,除PageContext是JavaBean对象,对应于javax.servlet.jsp.PageContext类型外,其他的隐式对象都对应于java.util.Map类型。这些隐式对象可以分为页面上下文对象访问作用域范围的隐式对象访问环境信息的隐式对象3种。

隐式对象名称
pageContext 对应于JSP页面中的pageContext对象 页面上下文对象
pageScope 代表page域中用于保存属性的Map对象 访问作用域范围的隐式对象
requestScope 代表request域中用于保存属性的Map对象 访问作用域范围的隐式对象
sessionScope 代表session域中用于保存属性的Map对象 访问作用域范围的隐式对象
applicationScope 代表application域中用于保存属性的Map对象 访问作用域范围的隐式对象
param 表示一个保存了所有请求参数的Map对象 访问环境信息的隐式对象
paramValues 表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个String类型数组 访问环境信息的隐式对象
header 表示一个保存了所有http请求头字段的Map对象 访问环境信息的隐式对象
headerValues 表示一个保存了所有http请求头字段的Map对象,返回String类型数组 访问环境信息的隐式对象
cookie 用于获取使用者的cookie值,cookie的类型是Map 访问环境信息的隐式对象
initParam 表示一个保存了所有Web应用初始化参数的Map对象 访问环境信息的隐式对象

在上表列举的隐式对象中,pageContext可以获取其他10个隐式对象:

2.1 pageContext对象

02pageContext_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>页面上下文对象</title>
</head>
<body>
    <h1>页面上下文对象pageContext</h1>
    <hr>
    请求URI为:${pageContext.request.requestURI} <br>
    请求文件为:${pageContext.request.servletPath} <br>
    SessionID为:${pageContext.session.id} <br>
    响应的内容类型:${pageContext.response.contentType} <br>
    响应字符编码为:${pageContext.response.characterEncoding} <br>
    服务器信息为:${pageContext.servletContext.serverInfo} <br>
    上下文信息为:${pageContext.request.contextPath} <br>
    Servlet注册名为:${pageContext.servletConfig.servletName} <br>
</body>
</html>

运行结果:

图3 页面上下文对象

2.2 Web域相关对象

在EL中提供了4 个用于访问作用域范围的隐式对象,即pageScope、requestScope、sessionScope和applicationScope。应用这4个隐式对象指定所要查找的标识符的作用域后,系统将不再按照默认的顺序(page、request、session、application)查找相应的标识符。它们与JSP中的page、request、session及application内置对象类似,只不过这4个隐式对象只能用于获取指定范围内的属性值,而不能获取其他相关信息

03scopes_zzh.jsp 域相关

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>使用EL表达式查询属性名的属性值</title>
</head>
<body>
    <h1>使用EL表达式查询属性名的属性值</h1>
    <hr>
    <%-- Java脚本设置属性值 --%>
    <% pageContext.setAttribute("用户名", "zzhzhaojiang"); %>
    <% request.setAttribute("书名", "《Java Web程序设计》"); %>
    <% session.setAttribute("用户名", "郑佐汉"); %>
    <% application.setAttribute("书名", "《Java基础》"); %>
    <h4>使用\${xxxxScope.属性名}格式的EL查询指定范围的属性值</h4>
    表达式\${pageScope.用户名}的值为:${pageScope.用户名} <br>
    表达式\${requestScope.书名}的值为:${requestScope.书名} <br>
    表达式\${sessionScope.用户名}的值为:${sessionScope.用户名} <br>
    表达式\${applicationScope.书名}的值为:${applicationScope.书名}<br>
    <h4>使用\${属性名}格式的EL查询属性值</h4>
    <p>在page、request、session、application这4个作用域内按顺序依次查找[属性名]的属性值。</p>
    表达式\${用户名}的值为:${用户名}<br>
    表达式\${书名}的值为:${书名}<br>
</body>
</html>

运行结果:

图4 使用EL表达式查询属性名的属性值

2.3 访问环境信息的隐式对象

使用param和paramValues两个隐式对象获取客户端传递的请求参数。

04param_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>传递请求参数</title>
</head>
<body style="text-align: center;">
    <h1>传递、获取请求参数</h1>
    <form action="${pageContext.request.contextPath}/04param_zzh.jsp">
        姓名:<input type="text" name="姓名"><br>
        爱好1:<input type="text" name="爱好"><br>
        爱好2:<input type="text" name="爱好"><br> <br />
        <input type="submit" value="提交" />&nbsp;&nbsp;
        <input type="submit" value="重置" />
        <hr>
        姓名:${param.姓名}<br>
        爱好1:${paramValues.爱好[0]}<br>
        爱好2:${paramValues.爱好[1]}<br>
    </form>
</body>
</html>

运行结果:

图5 使用param和paramValues获取请求参数
<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>获取和添加Cookie</title>
</head>
<body>
    <h1>获取和添加Cookie</h1>
    <hr>
    Cookie对象的信息:<br>
    ${cookie.userName } <br>
    Cookie对象的名称和值:<br>
    ${cookie.userName.name }=${cookie.userName.value }
    <!-- 添加cookie -->
    <% response.addCookie(new Cookie("userName", "郑佐汉")); %>
</body>
</html>

运行结果:

图6 获取和添加Cookie

2.5 initParam对象

web/WEB-INF/web.xml

    <context-param>
        <param-name>作者</param-name>
        <param-value>郑佐汉</param-value>
    </context-param>

06initParam_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>提取web.xml文件中&lt;context-param>参数值</title>
</head>
<body>
    提取web.xml文件中&lt;context-param>参数为[作者]的值:${initParam.作者}
</body>
</html>

运行结果:

图7 提取web.xml文件中<context-param>参数值

2.7 EL表达式小结

cn.zzh.bean.Group

package cn.zzh.bean;

public class Group {
    private String 集团名称;

    public String get集团名称() {
        return 集团名称;
    }

    public void set集团名称(String 集团名称) {
        this.集团名称 = 集团名称;
    }
}

cn.zzh.bean.User

package cn.zzh.bean;

public class User {
    private String 姓名;
    private int 年龄;
    private Group 集团;

    public String get姓名() {
        return 姓名;
    }
    public void set姓名(String 姓名) {
        this.姓名 = 姓名;
    }

    public int get年龄() {
        return 年龄;
    }
    public void set年龄(int 年龄) {
        this.年龄 = 年龄;
    }

    public Group get集团() {
        return 集团;
    }
    public void set集团(Group 集团) {
        this.集团 = 集团;
    }
}

cn.zzh.servlet.ElServlet

package cn.zzh.servlet;

import cn.zzh.bean.Group;
import cn.zzh.bean.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@WebServlet("/07elServlet")
public class ElServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("hello", "Hello World. 您好,郑佐汉。");
        req.getServletContext().setAttribute("hello", "ServletContext Hello World. 应用中 您好,郑佐汉。");

        //结构
        Group group = new Group();
        group.set集团名称("梦之队");

        User user = new User();
        user.set姓名("郑佐汉");
        user.set年龄(23);
        user.set集团(group);

        req.setAttribute("user", user);

        //map
        Map map = new HashMap();
        map.put("11", "北京市");
        map.put("12", "天津市");
        map.put("13", "河北省");
        map.put("14", "山西省");
        map.put("15", "内蒙古");
        req.setAttribute("map", map);

        //字符器数组
        String[] strArray = new String[]{"北京","天津","上海","重庆"};
        req.setAttribute("strArray", strArray);

        //对象数组
        User[] users = new User[10];
        for (int i = 0; i < users.length ;i++) {
            users[i] = new User();
            users[i].set姓名("郑佐汉_" + i);
        }
        req.setAttribute("users", users);

        //List
        List userList = new ArrayList();
        for (int i = 0;i < 10;i++) {
            User usl = new User();
            usl.set姓名("李老师_" + i);
            userList.add(usl);
        }
        req.setAttribute("userList", userList);

        //empty 判断是为空值
        req.setAttribute("v2", "");
        req.setAttribute("v3", new ArrayList());
        req.setAttribute("v4", "12345");
        req.setAttribute("v5", null);

        req.getRequestDispatcher("/07el_zzh.jsp").forward(req, resp);
    }
}

07el_zzh.jsp

<%@ page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" %>
<html>
<head>
    <title>el表达式</title>
</head>
<body>
    <h1>测试EL表达式</h1>
    <hr>
    <table>
        <tr>
            <td>
                <h3>普通字符器</h3>
                hello(jsp表达式):<%=request.getAttribute("hello") %><br>
                hello( el表达式):${hello}<br>
            </td>
            <td>
                <h3>内置对象范围</h3>
                <p>内置对象范围: pageScope < requestScope < sessionScope < applicationScope</p>
                hello(el表达式,范围pageScope):${pageScope.hello }<br>
                hello(el表达式,范围requestScope):${requestScope.hello }<br>
                hello(el表达式,范围sessionScope):${sessionScope.hello }<br>
                hello(el表达式,范围applicationScope):${applicationScope.hello }<br>
                如果不指定范围,它的搜索顺序为pageScope~applicationScope):${hello }<br>
            </td>
        </tr>
        <tr>
            <td>
                <h3>结构,采用.或[]进行导航,或称为存取器</h3>
                姓名:${user["姓名"]}<br>
                年龄:${user["年龄"] }<br>
                所属组:${user["集团"]["集团名称"] }<br><br>
                姓名:${user.姓名 }<br>
                年龄:${user.年龄 }<br>
                所属组:${user.集团.集团名称 }<br>
            </td>
            <td>
                <h3>map</h3>
                map.11:${map["11"] }<br>
                map.12:${map["12"] }<br>
                map.13:${map["13"] }<br>
                map.14:${map["14"] }<br>
                map.15:${map["15"] }<br>
            </td>
        </tr>
        <tr>
            <td>
                <h3>字符串数组,采用[]下标</h3>
                strArray[0]:${strArray[0] }<br>
                strArray[1]:${strArray[1] }<br>
                strArray[2]:${strArray[2] }<br>
                strArray[3]:${strArray[3] }<br>
            </td>
            <td>
                <h3>对象数组,采用[]下标</h3>
                users[3].姓名:${users[3].姓名}<br>
                users[5].姓名:${users[5].姓名}<br>

                <h3>List,采用[]下标</h3>
                userList[4].姓名:${userList[4].姓名 }<br>
                userList[6].姓名:${userList[6].姓名 }<br>
            </td>
        </tr>
        <tr>
            <td>
                <h3>el表达式对运算符的支持</h3>
                1 + 1 = ${1 + 1 }<br>
                10 / 5 = ${ 10 / 5 }<br>
                10 div 5 = ${10 div 5 }<br>
                10 % 3 = ${10 % 3 } <br>
                10 mod 3 = ${10 mod 3 }<br>
            </td>
            <td>
                <h3>测试empty 判断是为空值</h3>
                v1:${empty v1 }<br>
                v2:${empty v2 }<br>
                v3:${empty v3 }<br>
                v4:${empty v4 }<br>
                v5:${empty v5 }<br>

                <%request.setAttribute("用户名","郑佐汉"); %>
                <%request.setAttribute("用户名1",""); %>
                <%request.setAttribute("用户名2",null); %>

                判断 request.setAttribute("用户名","郑佐汉") 是否为空:${empty 用户名}<br>
                判断 request.setAttribute("用户名1","") 是否为空:${empty 用户名1}<br>
                判断 request.setAttribute("用户名2",null) 是否为空:${empty 用户名2}<br>
            </td>
        </tr>
    </table>
</body>
</html>

运行结果:

图8 EL表达式语言小结

3. JSTL

3.1 什么是JSTL

从JSP 1.1规范开始,JSP就支持使用自定义标签,使用自定义标签大大降低了JSP页面的复杂度,同时增强了代码的重用性。为此,许多Web应用厂商都制定了自身应用的标签库,然而同一功能的标签由不同的Web应用厂商制定可能是不同的,这就导致市面上出现了很多功能相同的标签,令网页制作者无从选择,为了解决这个问题,Sun公司制定了一套标准标签库(Java Server Pages Standard Tag Library JSP标准标签库),简称JSTL。

JSTL =Java Server Pages Standard Tag Library JSP标准标签库

JSTL 5个标签库:

JSTL核心标签库

<%@ taglib prefix="c" url="http://java.sun.com/jsp/jstl/core" %>

核心标签库主要用于完成JSP页面的常用功能,包括JSTL的表达式标签、URL标签、流程控制标签。

JSTL格式标签库

<%@ taglib prefix "fmt" url="http://java.sun.com/jsp/jstl/fmt"%>

国际化/格式化标签库,它包含实现Web应用程序的国际化标签和格式化标签。例如,设置JSP页面的本地信息、设置JSP页面的时区、使日期按照本地格式显示等。

JSTL SQL标签库

<%@ taglib prefix="sql" url="http://java.sun.com/jsp/jstl/sql" %>

SQL标签库,它包含了用于访问数据库和操作数据库的标签。例如,获取数据库连接、从数据库表中检索数据等。由于在软件分层开发模型中,JSP页面仅作为显示层,一般不会在JSP页面中直接操作数据库,所以,JSTL中提供的这套标签库不经常使用

JSTL XML标签库

<%@ taglib prefx="xml" url="http://java.sun.com/jsp/jstl/xml" %>

XML文档的标签库,它包含对XML文档中的数据进行操作的标签。例如,解析XML文件、输出XML文档中的内容,以及迭代处理XML文档中的元素。XML广泛应用于Web开发,使用XML标签库处理XML文档更加简单方便。

JSTL函数标签库

<%@ taglib prefix= "fn" url="http://java.sun.com/jsp/jstl/functions"%>

函数标签库,它提供了一套自定义EL函数,包含了JSP网页制作者经常要用到的字符串操作。例如,提取字符串中的子字符串、获取字符串的长度等。

3.2 JSTL的下载和使用指令

https://downloads.apache.org/tomcat/taglibs/taglibs-standard-1.2.5/

单击 文件 --> 项目设置 --> 模块 弹出如下的界面

图9 将2个jar加入项目中

08c_test_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>测试JSTL</title>
</head>
<body>
    <h1>测试JSTL</h1>
    <hr>
    <c:out value="Hello World! 测试JSTL。">这里的文字显示不出来!!!</c:out>
</body>
</html>

运行结果如下:

图10 测试JSTL

4. JSTL中的Core标签库

4.1 表达式标签

<c:out>标签两种语法格式

语法1:没有标签体的情况

<c:out value="value" [default="默认值"] [escapeXml="{true|false}"]/>

语法2:有标签体的情况

<c:out value="value" [escapeXml="{true|false}"]>默认值</c:out>

需要注意的是,只有当value属性值为null时,标签才会输出默认值,如果没有指定默认值,则默认输出空字符串。

09c_out1_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>c:out value</title>
</head>
<body>
    <h2>c:out value</h2>
    <hr>
    <%--第1个out标签 --%>
    param.用户名 属性的值为:
    <c:out value="${param.用户名}" default="不知道"/><br>
    <%--第2个out标签 --%>
    param.用户名 属性的值为:
    <c:out value="${param.用户名}">不知道</c:out>
</body>
</html>

运行结果如下:

图11 c:out value

09c_out2_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>&lt;c:out>的escapeXml属性</title>
</head>
<body>
    <h1>&lt;c:out>的escapeXml属性</h1>
    <hr>
    <c:out value="${param.用户名 }" escapeXml="true">
        <meta http-equiv="refresh" content="0; url=http://www.itcast.cn" />
    </c:out> <br>
    <c:out value="${param.用户名 }" escapeXml="true">
        <h2>为人民服务</h2><hr>
    </c:out> <br>
    <c:out value="${param.用户名 }" escapeXml="false">
        <h2>为人民服务</h2><hr>
    </c:out> <br>
</body>
</html>

运行结果如下:

图12 <c:out>的escapeXml属性

09c_out3_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>2秒后转移到另一网址</title>
</head>
<body>
    <h1>2秒后转移到另一网址</h1>
    <hr>
    <c:out value="${param.用户名 }" escapeXml="false">
        <meta http-equiv="refresh" content="2; url=http://www.itcast.cn" />
    </c:out>
</body>
</html>

运行结果如下:

图13 <c:out>的escapeXml属性=false
<c:remove var="name" [scope=”范围”]/>

需要注意的是,如果在该标签中没有指定变量的有效范围,那么将分别在page、request、 session 和application的范围内查找要移除的变量并移除。因此,在移除变量时,最好指定变量的有效范围。

10c_remove1_zzh.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>设置属性值</title>
</head>
<body>
<%
  request.setAttribute("用户名", "请求域的郑佐汉");
  session.setAttribute("用户名", "会话域的郑佐汉" );
  request.getRequestDispatcher("10c_remove2_zzh.jsp").forward(request, response);
%>
</body>
</html>

10c_remove2_zzh.jsp

<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>&lt;c:removr>移除属性</title>
</head>
<body>
  <h1>&lt;c:removr>移除属性</h1>
  <hr>
  <%--通过el表达式获取指定域中的值 --%>
  request域中的[用户名]属性值: ${requestScope.用户名} <br>
  session域中的[用户名]属性值: ${sessionScope.用户名} <br>
  <%--移除--%>
  <c:remove var= "用户名" scope="session"/>
  <%--通过jstl获取值--%>
  <hr>
  <p>移除会话域的[用户名]属性后</p>
  request域中的[用户名]属性值: <c:out value="${requestScope.用户名}"/><br>
  session域中的[用户名]属性值: <c:out value="${sessionScope.用户名}"/><br>
</body>
</html>

运行结果如下:

图14 <c:removr>移除属性

4.2 流程控制标签

(1) <c:set> 设置变量值和对象属性

<c:set>标签用于设置变量值和对象属性。

<c:set>标签就是jsp:setProperty行为标签的孪生兄弟。

<c:set [var="变量名"]
       [target="要修改的属性所属的对象"] [property="对象属性名"]
       [value=""] [scope="作用域"]
   />
属性 描述 必要 默认值
var 存储信息的变量
target 要修改的属性所属的对象
property 要修改的属性
value 要存储的值 主体的内容
scope var属性的作用域 page
<body>
    <c:set var="薪水" scope="session" value="${100*2}"/>
    <c:out value="${薪水}"/>
</body>

输出结果:200

(2) <c:if test> 测试条件写入对象的key值或显示标签体

语法1:没有标签体的情况

<c:if test="测试条件" var="变量名" 
[scope="{page|request|session|application}"]/>

功能:测试结果(true|false)写入var 变量----存入域对象的key值

语法2:有标签体的情况,在标签体中指定要输出的内容

<c:if test="测试条件" [var="变量名"] 
[scope="{page|request|session|application}"]>
标签体
</c:if>

功能:[测试结果(true|false)写入var 变量----存入域对象的key值];如果测试条件成立,显示标签提

需要注意的是,判断条件要写入el表达式里

11c_if_zzh.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>c:if test 判断条件</title>
</head>
<body>
    <h1>c:set设置变量、c:if test 判断条件</h1>
    <hr>
    <c:set value="1" var="visitCount" property="visitCount" />
    测试前结果标志:${结果标志}<br>
    <c:if test="${visitCount==1 }" var="结果标志">
        This is you first visit. Welcome to the site! <br>
        这是你第一次来。欢迎访问网站!
    </c:if> <br>
    <c:if test="${结果标志}">
        visitCount==1 是正确的!
    </c:if><br>
    测试后结果标志:${结果标志}
</body>
</html>

运行结果如下:

图15 c:set设置变量、c:if test 判断条件

(3) c:choose 多项测试

Core标签库提供了<c:choose>标签,该标签用于指定多个条件选择的组合边界,它必须与<c:when>、<c:otherwise>标签一起使用。

<c:choose>
    <c:when test="测试条件">
        标签体
    </c:when>
    [...]
    [<c:otherwise>
        标签体
    </c:otherwise>]
</c:choose>

12c_choose_zzh.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>c:choose - c:when - c:otherwise的使用</title>
</head>
<body>
    <h1>c:choose - c:when - c:otherwise的使用</h1>
    <hr>
    <c:choose>
        <c:when test="${empty param.用户名}">
            用户名 为空。
        </c:when>
        <c:when test="${param.用户名=='郑佐汉' }">
            ${ param.用户名} 是 我自己。
        </c:when>
        <c:otherwise>
            ${ param.用户名} 是 我的同学。
        </c:otherwise>
    </c:choose>
</body>
</html>

运行结果如下:

图16 c:choose - c:when - c:otherwise的使用

4.3 循环标签

Core标签库提供了一个<c:forEach>标签,该标签专门用于迭代集合对象中的元素,如Set、List、Map、数组等,并且能重复执行标签体中的内容。

<c:forEach [var="varName"] [items="collection"] [varStatus="varStatusName"]
           [begin="begin"] [end="end"] [step="step"]>
    标签体
</c:forEach>
属性 描述 是否必要 默认值
items 要被循环的信息(指定将要迭代的集合对象)
begin 开始的元素(0=第一个,1=第二个,...) 0
end 最后的元素(0=第一个,1=第二个,...) 最后元素
step 每一次迭代的步长 1
var 代表当前条目的变量名称
varStatus 代表循环状态的变量名称

varStatus属性常用参数总结如下,假设状态变量名为status:

13c_foreach1_zzh.jsp

<%@ page contentType="text/html; charset=utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>forEach遍历</title>
</head>
<body>
    <h1>forEach遍历 c:forEach var="..." items="..."</h1>
    <hr>
    <%
        String[] fruits = { "apple", "orange", "grape", "banana" };
    %>
    String数组中的元素:<br>
    <c:forEach var="name" items="<%=fruits%>">
        水果名称:${name}<br>
    </c:forEach>
    <hr>
    <h3>世界人口排名2022前三</h3>
    <%
        Map<String,String > aMap = new HashMap<String,String>();
        aMap.put("中国", "1,447,301,400");
        aMap.put("印度", "1,403,018,576");
        aMap.put("美国", "334,282,669");
    %>
    HashMap集合中的元素:<br>
    <c:forEach var="entry" items="<%=aMap%>">
       国家:${entry.key}&nbsp;人口:${entry.value}<br>
    </c:forEach>
</body>
</html>

运行结果如下:

图17 forEach遍历--迭代包含多个对象的集合

14c_foreach2_zzh.jsp

<%@ page contentType="text/html; charset=utf-8" import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>List集合迭代</title>
</head>
<body>
    <h1>List集合遍历(c:forEach 指定范围初值、终值和步长值)</h1>
    <hr>
    <%
        List<String> mountainList =new ArrayList<String>();
        mountainList.add("泰山");
        mountainList.add("华山");
        mountainList.add("衡山");
        mountainList.add("恒山");
        mountainList.add("黄山");
    %>
    <c:forEach var="mountain" items="<%=mountainList%>" begin="1"
               end="3" step="2">
        ${mountain}&nbsp;
    </c:forEach>
</body>
</html>

运行结果如下:

图18 c:forEach 指定范围初值、终值和步长值

4.4 URL相关标签

在开发一个Web应用程序时,通常会在JSP页面中完成URL的重写以及重定向等特殊功能,为了完成这些功能,Core标签库也提供了相应标签,这些标签包括<c:param>、<c:redirect>和<c:url>。其中

(1) <c:param>标签

<!-- 语法1:使用value属性指定参数的值 -->
<c:param name="name" value="value">
<!-- 语法2:在标签体中指定参数的值 -->
<c:param name="name">parameter value</c:param>

(2) <c:url>标签

<!-- 语法1:没有标签实体的情况 -->
<c:url value="value" [context="context"] [var="varName"]
[scope="{page|request|session|application}"]>
<!-- 语法2:有标签实体的情况,在标签体中指定构造URL参数 -->
<c:url value="value" [context="context"] [var="varName"]
[scope="{page|request|session|application}"]>
    <c:param>标签
</c:url>

(3) <c:redirect>标签

<!--a、没有body的情况-->
<c:redirect url=”value” [context=”context”]/>
<!--b、有body,在body 中查询指定的参数-->
<c:redirect url=”value” [context=”context”]>
    <c:param> subtags
</c:redirect>

用来通过自动重写URL来将浏览器重定向至一个新的URL

15c_url_zzh.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title></title>
</head>
<body>
    <h1>使用绝对路径构造URL</h1>
    <hr>
    <c:url var="myURL"
           value="/09c_out1_zzh.jsp">
        <c:param name="用户名" value="郑佐汉1" />
    </c:url>
    <a href="${myURL}">c_out1.jsp</a><br />
    <h1>使用相对路径构造URL</h1>
    <hr>
    <c:url var="myURL"
           value="09c_out1_zzh.jsp?用户名=郑佐汉2" />
    <a href="${myURL}">c_out1.jsp</a>
</body>
</html>

运行结果如下:

图19 c:url 超链接

16c_redirect_zzh.jsp

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
  <title>JSTL:c:redirect的使用</title>
</head>
<body>
  <c:url var="myURL"
         value="09c_out1_zzh.jsp">
    <c:param name="用户名" value="郑佐汉3" />
  </c:url>
  <c:redirect url="${myURL}"/>
</body>
</html>

运行结果类同图19。

任务:根据参数请求显示不同的页面内容

通过JSTL标签库中的<c:if>标签可以根据不同的条件去处理不同的业务。本任务要求应用标签实现根据参数请求显示不同页面的功能。

17if_zzh.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>根据参数请求显示不同的页面内容</title>
</head>
<body>
    <h1>根据参数请求显示不同的页面内容</h1>
    <hr>
    <fieldset>
        <c:if test="${param.action=='mon'}">
            周一了:工作的第一天,加油!
        </c:if>
        <c:if test="${param.action=='tues'}">
            周二了:工作的第二天,加油!
        </c:if>
        <c:if test="${param.action=='wed'}">
            周三了:工作的第三天,加油!
        </c:if>
        <c:if test="${param.action=='thu'}">
            周四了:工作的第四天,加油!
        </c:if>
        <c:if test="${param.action=='fri'}">
            周五了:工作的第五天,加油!
        </c:if>
        <c:if test="${param.action=='sat'}">
            周六了:休息的第一天!
        </c:if>
        <c:if test="${param.action=='sun'}">
            周日了:休息的第二天!
        </c:if>
    </fieldset>
</body>
</html>

运行结果如下:

图20 根据参数请求显示不同的页面内容
图21 ch07源代码文件结构

返回