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 脚本,降低代码复杂度。
- 提高可维护性:将逻辑和展示分离,使代码更易维护。
- 跨平台支持:支持多种数据源和数据库。