EL与 JSTL 实践
一. EL(Expression Language)
EL(表达式语言)是 JSP 2.0 中引入的一种简单的脚本语言,用于在 JSP 页面中简化数据的访问和显示。它通过一种类似于 JavaScript 的语法,允许开发者在 JSP 页面中直接访问 JavaBean 的属性、集合、甚至是 Java 类的静态字段和方法。
1、 EL 的基本语法
EL 表达式的语法格式为 ${}
,例如:
${requestScope.userName}
2、 EL 的变量
EL 变量是自动创建的,您无需显式声明。以下是一些常见的变量:
-
隐式变量:
pageScope
:当前页面的作用域。requestScope
:请求作用域。sessionScope
:会话作用域。applicationScope
:应用作用域。
-
用户定义变量:
使用 JSTL 的<c:set>
标签可以自定义变量,例如:<c:set var="title" value="EL 示例" scope="page"/> ${title}
3、EL 的操作符
EL 支持多种操作符,包括:
- 算术操作符:
+
,-
,*
,/
,%
,div
,mul
。 - 比较操作符:
==
,eq
,!=
,neq
,>
,gt
,<
,lt
。 - 逻辑操作符:
&&
,and
,||
,or
,not
,!
。 - 空检查操作符:
empty
(检查对象是否为空)。
示例:
${10 + 5} <!-- 算术操作 -->
${user.age > 18} <!-- 比较操作 -->
${!empty user.name} <!-- 空检查 -->
4、EL 的使用场景
-
访问 JavaBean 的属性:
<jsp:useBean id="user" class="com.example.User" scope="request"/> 用户名称:${user.name}
-
遍历集合:
<c:forEach items="${users}" var="user"> ${user.name} </c:forEach>
-
条件判断:
<c:if test="${user.age > 18}"> 成人用户 </c:if>
-
格式化输出:
<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd"/>
二. JSTL(JavaServer Pages Standard Tag Library)
JSTL 是 Java 社区为了简化 JSP 页面开发而推出的一组标准标签库。它提供了多种功能标签,涵盖了常见的 Web 开发需求。
1、 JSTL 的核心标签库
JSTL 分为四个主要模块:
- 核心标签库:用于流程控制、集合操作、数据处理等。
- 格式化标签库:用于日期、时间、数字等格式化。
- 数据库标签库:用于简化 JDBC 操作。
- XML 标签库:用于 XML 数据的处理。
核心标签库(core)
以下是核心标签库中常用的标签:
-
<c:out>:
用于输出数据,支持 HTML 转义。<c:out value="${user.name}" default="未知"/>
-
<c:forEach>:
用于遍历集合或数组。<c:forEach items="${users}" var="user" varStatus="status"> ${status.index}: ${user.name} </c:forEach>
-
<c:forTokens>:
用于遍历字符串标记。<c:forTokens items="a,b,c" delims=","> ${token} </c:forTokens>
-
<c:if>:
用于条件判断。<c:if test="${user.age > 18}"> 成人用户 </c:if>
-
<c:choose>:
用于多分支条件判断。<c:choose> <c:when test="${user.age > 18}">成人用户</c:when> <c:otherwise>未成年用户</c:otherwise> </c:choose>
-
<c:set>:
用于设置变量。<c:set var="title" value="JSTL 示例" scope="page"/> ${title}
-
<c:remove>:
用于删除变量。<c:remove var="title" scope="page"/>
-
<c:import>:
用于导入其他资源(如 HTML 文件、JSP 页面)。<c:import url="http://example.com/header.html"/>
-
<c:param>:
用于在导入资源时传递参数。<c:import url="detail.jsp"> <c:param name="id" value="123"/> </c:import>
-
<c:redirect>:
用于页面跳转。<c:redirect url="/login.jsp"/>
格式化标签库(fmt)
-
fmt:setLocale:
设置Locale。<fmt:setLocale value="zh_CN"/>
-
fmt:bundle:
加载资源文件。<fmt:bundle basename="messages"> <fmt:message key="welcome.message"/> </fmt:bundle>
-
fmt:formatDate:
格式化日期。<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd"/>
-
fmt:formatNumber:
格式化数字。<fmt:formatNumber value="12345.678" pattern="#,###.##"/>
数据库标签库(sql)
-
sql:setDataSource:
设置数据源。<sql:setDataSource var="dataSource" driver="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/testdb" user="root" password="password"/>
-
sql:query:
执行查询。<sql:query dataSource="${dataSource}" sql="SELECT * FROM users"> ${users} </sql:query>
-
sql:update:
执行更新(插入、删除、修改)。<sql:update dataSource="${dataSource}" sql="INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com')"/>
2、 JSTL 的使用场景
-
简化流程控制:
<c:forEach items="${users}" var="user"> <p>用户 ${user.name}</p> </c:forEach>
-
格式化数据:
<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd"/>
-
数据库操作:
<sql:query var="users" sql="SELECT * FROM users"> <c:forEach items="${users.rows}" var="user"> ${user.name} </c:forEach> </sql:query>
-
国际化:
<fmt:setLocale value="${param.locale}"/> <fmt:bundle basename="messages"> <h1><fmt:message key="welcome.message"/></h1> </fmt:bundle>
三. 实践:数据显示与分页
以下是一个完整的实践示例,展示如何使用 EL 和 JSTL 实现数据显示与分页功能。
1、 准备工作
-
创建数据库表:
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) );
-
添加测试数据:
INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com'), ('Jane Smith', 'jane@example.com'), ('Bob Johnson', 'bob@example.com');
-
添加依赖:
在pom.xml
中添加 JSTL 和 MySQL Connector/J 的依赖:<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency>
2、 JSP 页面实现
以下是一个完整的 JSP 页面示例,展示数据显示和分页功能。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %> <html>
<head> <title>用户管理 - 数据显示与分页</title>
</head>
<body> <h1>用户管理系统</h1> <% // 定义每页显示的记录数 int pageSize = 5; // 获取当前页码(默认为第 1 页) int currentPage = 1; if (request.getParameter("currentPage") != null) { currentPage = Integer.parseInt(request.getParameter("currentPage")); } // 总记录数 int totalRecords = 0; // 计算总记录数 try { Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "password"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM users"); if (rs.next()) { totalRecords = rs.getInt(1); } rs.close(); stmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace(); } %> <c:set var="pageSize" value="<%=pageSize%>"/> <c:set var="currentPage" value="<%=currentPage%>"/> <c:set var="totalRecords" value="<%=totalRecords%>"/> <c:if test="${totalRecords > 0}"> <sql:setDataSource var="dataSource" driver="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/testdb" user="root" password="password"/> <sql:query dataSource="${dataSource}" sql="SELECT * FROM users LIMIT ${currentPage-1}, ${pageSize}" var="users"/> <div> <h2>用户列表(第 ${currentPage} 页 / 共 ${totalRecords} 条记录)</h2> <table border="1"> <tr> <th>序号</th> <th>用户姓名</th> <th>用户邮箱</th> </tr> <c:forEach items="${users.rows}" var="user" varStatus="status"> <tr> <td>${status.index + 1}</td> <td>${user.name}</td> <td>${user.email}</td> </tr> </c:forEach> </table> </div> <!-- 分页导航 --> <div style="margin-top: 20px;"> <c:if test="${currentPage > 1}"> <a href="?currentPage=${currentPage-1}">上一页</a> </c:if> <c:forEach begin="1" end="${totalRecords / pageSize + 1}" var="page"> <c:choose> <c:when test="${page == currentPage}"> <span style="color: red;">${page}</span> </c:when> <c:otherwise> <a href="?currentPage=${page}">${page}</a> </c:otherwise> </c:choose> </c:forEach> <c:if test="${currentPage < totalRecords / pageSize + 1}"> <a href="?currentPage=${currentPage+1}">下一页</a> </c:if> </div> </c:if> </body>
</html>
3、 功能说明
- 数据显示:
- 使用
<sql:query>
标签执行 SQL 查询,获取用户数据。 - 使用
<c:forEach>
标签遍历结果集,显示用户信息。
- 使用
- 分页功能:
- 计算总记录数和每页显示的记录数。
- 使用
<c:forEach>
标签生成分页导航链接。 - 通过
currentPage
参数控制当前显示的页码。
- EL 的使用:
- 使用 EL 表达式
${}
来访问变量和显示数据。 - 支持复杂的逻辑操作和格式化输出。
- 使用 EL 表达式
四. 总结
通过本讲义,您已经掌握了 EL 和 JSTL 的核心功能及其在实际开发中的应用。EL 和 JSTL 的优势在于:
- 简化代码:通过标签代替 Java 脚本,降低代码复杂度。
- 提高可维护性:将逻辑和展示分离,使代码更易维护。
- 跨平台支持:支持多种数据源和数据库。