肖哥弹架构 跟大家“弹弹” Sharding-JDBC设计与实战应用,需要代码关注
欢迎 点赞,点赞,点赞。
关注公号Solomon肖哥弹架构获取更多精彩内容
本文通过一个完整的电商订单管理系统案例,全面讲解JSTL(JSP标准标签库)五大核心标签库的实战应用,包含:
- 核心标签库(c:) - 变量操作、条件分支、循环遍历
- 格式化标签库(fmt:) - 日期/数字格式化、国际化支持
- 函数标签库(fn:) - 字符串处理、集合操作
- XML标签库(x:) - XML解析与XPath数据提取
- SQL标签库(sql:) - 数据库查询(附最佳实践警告)
一、常用JSP标签用法案例
1. JSP 基本语法标签
(1) <% ... %>(脚本片段)
作用:嵌入 Java 代码片段
用法:
<%
String name = "John";
out.println("Hello, " + name);
%>
输出:
Hello, John
(2) <%= ... %>(表达式输出)
作用:直接输出变量或表达式结果
用法:
<%= "Current time: " + new java.util.Date() %>
输出:
Current time: Wed Jun 26 14:30:45 CST 2024
(3) <%! ... %>(声明标签)
作用:声明全局变量或方法
用法:
<%!
int count = 0;
public void increment() {
count++;
}
%>
<%
increment();
out.print("Count: " + count);
%>
输出:
Count: 1
2. JSP 指令标签
(1) <%@ page %>(页面指令)
作用:定义页面属性(编码、导入类等)
参数说明:
| 参数 | 说明 |
|---|---|
language="java" | 脚本语言(默认Java) |
contentType="text/html;charset=UTF-8" | 响应内容类型 |
import="java.util.*" | 导入Java包 |
session="true" | 是否启用session |
errorPage="error.jsp" | 指定错误处理页面 |
| 用法: |
<%@ page language="java" contentType="text/html; charset=UTF-8"
import="java.util.Date" session="true" %>
输出:无直接输出,影响页面行为。
(2) <%@ include %>(静态包含)
作用:在编译时合并另一个文件内容
用法:
<%@ include file="header.jsp" %>
输出:
将header.jsp的内容插入当前页面。
(3) <%@ taglib %>(标签库引入)
作用:引入JSTL或自定义标签库
参数说明:
| 参数 | 说明 |
|---|---|
uri="http://java.sun.com/jsp/jstl/core" | 标签库URI |
prefix="c" | 标签前缀 |
| 用法: |
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
输出:无直接输出,启用JSTL标签功能。
3. JSP 动作标签
(1) <jsp:include>(动态包含)
作用:运行时包含另一个页面
参数说明:
| 参数 | 说明 |
|---|---|
page="footer.jsp" | 目标页面路径 |
| 用法: |
<jsp:include page="footer.jsp" />
输出:
动态加载footer.jsp的内容。
(2) <jsp:forward>(请求转发)
作用:跳转到另一个页面
参数说明:
| 参数 | 说明 |
|---|---|
page="target.jsp" | 目标页面路径 |
| 用法: |
<jsp:forward page="target.jsp" />
输出:
终止当前页面,跳转到target.jsp。
(3) <jsp:useBean>(JavaBean操作)
作用:创建或访问JavaBean对象
参数说明:
| 参数 | 说明 |
|---|---|
id="user" | Bean变量名 |
class="com.example.User" | Bean类全限定名 |
scope="session" | 作用域(page/request/session/application) |
| 用法: |
<jsp:useBean id="user" class="com.example.User" scope="session" />
输出:
在session中创建或获取User对象。
4. JSTL 核心标签
(1) <c:out>(安全输出)
作用:避免XSS攻击,输出转义内容
参数说明:
| 参数 | 说明 |
|---|---|
value="${data}" | 要输出的值 |
default="N/A" | 默认值(可选) |
| 用法: |
<c:out value="${user.name}" default="Guest" />
输出:
若user.name存在则输出,否则输出Guest。
(2) <c:if>(条件判断)
作用:简单条件分支
参数说明:
| 参数 | 说明 |
|---|---|
test="${salary > 2000}" | 布尔表达式 |
| 用法: |
<c:if test="${salary > 2000}">
<p>High salary!</p>
</c:if>
输出:
若条件为真,输出<p>High salary!</p>。
(3) <c:forEach>(循环遍历)
作用:遍历集合或数组
参数说明:
| 参数 | 说明 |
|---|---|
items="${users}" | 要遍历的集合 |
var="user" | 当前项变量名 |
varStatus="status" | 循环状态对象(可选) |
| 用法: |
<c:forEach items="${users}" var="user" varStatus="status">
${status.index}: ${user.name}<br>
</c:forEach>
输出:
0: Alice<br>
1: Bob<br>
2: Charlie<br>
5. 自定义标签开发
(1) 定义标签处理器
public class HelloTag extends SimpleTagSupport {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void doTag() throws JspException, IOException {
getJspContext().getOut().write("Hello, " + name + "!");
}
}
(2) TLD配置
<tag>
<name>hello</name>
<tag-class>com.example.HelloTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>true</required>
</attribute>
</tag>
(3) JSP中使用
<%@ taglib uri="/WEB-INF/tags.tld" prefix="mytag" %>
<mytag:hello name="World" />
输出:
Hello, World!
二、JSTL 完整标签库参考手册
1. JSTL Core 核心标签库 (c:)
(1) 表达式控制标签
| 标签 | 作用 | 语法 | 参数说明 | 示例 |
|---|---|---|---|---|
<c:out> | 输出表达式值 | <c:out value="expr" [default="def"] [escapeXml="true/false"]/> | value: 要输出的表达式 default: 默认值 escapeXml: 是否转义XML | <c:out value="${user.name}" default="Guest"/> |
<c:set> | 设置变量值 | <c:set var="name" value="expr" [scope="page/request/session/application"]/> | var: 变量名 value: 值 scope: 作用域 | <c:set var="admin" value="${user.role == 'admin'}" scope="session"/> |
<c:remove> | 移除变量 | <c:remove var="name" [scope="page/request/session/application"]/> | var: 变量名 scope: 作用域 | <c:remove var="tempData" scope="request"/> |
(2) 流程控制标签
| 标签 | 作用 | 语法 | 参数说明 | 示例 |
|---|---|---|---|---|
<c:if> | 条件判断 | <c:if test="condition">content</c:if> | test: 布尔表达式 | <c:if test="${empty cart}">购物车为空</c:if> |
<c:choose> | 多条件选择 | <c:choose><c:when test="...">...</c:when><c:otherwise>...</c:otherwise></c:choose> | test: 条件表达式 | 见下方完整示例 |
<c:when> | choose的子条件 | <c:when test="condition">content</c:when> | test: 布尔表达式 | |
<c:otherwise> | choose的默认分支 | <c:otherwise>content</c:otherwise> | 无 |
完整示例:
<c:choose>
<c:when test="${score >= 90}">优秀</c:when>
<c:when test="${score >= 60}">及格</c:when>
<c:otherwise>不及格</c:otherwise>
</c:choose>
(3) 循环迭代标签
| 标签 | 作用 | 语法 | 参数说明 | 示例 |
|---|---|---|---|---|
<c:forEach> | 集合遍历 | <c:forEach items="collection" [var="varName"] [varStatus="status"] [begin="start"] [end="end"] [step="step"]>content</c:forEach> | items: 迭代集合 var: 当前项变量名 varStatus: 状态对象 begin/end/step: 控制子集 | <c:forEach items="${users}" var="u" varStatus="s">${s.index}: ${u.name}</c:forEach> |
<c:forTokens> | 字符串分割 | <c:forTokens items="string" delims="delimiters" [var="varName"] [varStatus="status"]>content</c:forTokens> | items: 要分割的字符串 delims: 分隔符 var: 当前项变量名 | <c:forTokens items="apple,orange,banana" delims="," var="fruit">${fruit}</c:forTokens> |
(4) URL相关标签
| 标签 | 作用 | 语法 | 参数说明 | 示例 |
|---|---|---|---|---|
<c:url> | URL编码 | <c:url value="url" [var="varName"] [scope="scope"] [context="contextPath"]/> | value: 基础URL var: 存储变量名 context: 上下文路径 | <c:url value="/product?id=${p.id}" var="productUrl"/> |
<c:param> | 添加URL参数 | <c:param name="paramName" value="paramValue"/> | name: 参数名 value: 参数值 | <c:url value="/search"><c:param name="keyword" value="${kw}"/></c:url> |
<c:redirect> | 重定向 | <c:redirect url="url" [context="contextPath"]/> | url: 目标URL context: 上下文路径 | <c:redirect url="/login.jsp"/> |
2. JSTL Functions 函数库 (fn:)
需额外声明:
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
| 函数 | 作用 | 语法 | 示例 |
|---|---|---|---|
fn:contains() | 判断包含 | ${fn:contains(string, substring)} | ${fn:contains(name, "Admin")} |
fn:escapeXml() | XML转义 | ${fn:escapeXml(unsafeString)} | ${fn:escapeXml(userInput)} |
fn:join() | 数组连接 | ${fn:join(array, delimiter)} | ${fn:join(tags, ",")} |
fn:length() | 获取长度 | ${fn:length(collection/string)} | ${fn:length(users)} |
fn:split() | 字符串分割 | ${fn:split(string, delimiter)} | ${fn:split(csvData, ",")} |
fn:startsWith() | 判断前缀 | ${fn:startsWith(string, prefix)} | ${fn:startsWith(url, "http")} |
fn:substring() | 获取子串 | ${fn:substring(string, begin, end)} | ${fn:substring(title, 0, 20)} |
fn:toLowerCase() | 转小写 | ${fn:toLowerCase(string)} | ${fn:toLowerCase(username)} |
fn:toUpperCase() | 转大写 | ${fn:toUpperCase(string)} | ${fn:toUpperCase(status)} |
fn:trim() | 去除空格 | ${fn:trim(string)} | ${fn:trim(input)} |
3. JSTL Formatting 格式化标签库 (fmt:)
需额外声明:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
(1) 数字格式化
| 标签 | 作用 | 语法 | 示例 |
|---|---|---|---|
<fmt:formatNumber> | 数字格式化 | <fmt:formatNumber value="num" [type="number/currency/percent"] [pattern="customPattern"]/> | <fmt:formatNumber value="${price}" type="currency"/> |
<fmt:parseNumber> | 字符串转数字 | <fmt:parseNumber value="string" [type="number/currency/percent"]/> | <fmt:parseNumber value="${strNum}"/> |
(2) 日期格式化
| 标签 | 作用 | 语法 | 示例 |
|---|---|---|---|
<fmt:formatDate> | 日期格式化 | <fmt:formatDate value="date" [type="date/time/both"] [pattern="yyyy-MM-dd"]/> | <fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm"/> |
<fmt:parseDate> | 字符串转日期 | <fmt:parseDate value="string" [pattern="yyyy-MM-dd"]/> | <fmt:parseDate value="${strDate}" pattern="MM/dd/yyyy"/> |
(3) 国际化支持
| 标签 | 作用 | 语法 | 示例 |
|---|---|---|---|
<fmt:setLocale> | 设置地区 | <fmt:setLocale value="zh_CN" [variant="..."] [scope="page/request/session/application"]/> | <fmt:setLocale value="en_US"/> |
<fmt:setBundle> | 设置资源包 | <fmt:setBundle basename="messages" [var="varName"] [scope="scope"]/> | <fmt:setBundle basename="com/myapp/messages"/> |
<fmt:message> | 获取国际化消息 | <fmt:message key="msgKey" [bundle="resourceBundle"]/> | <fmt:message key="welcome.message"/> |
<fmt:requestEncoding> | 设置请求编码 | <fmt:requestEncoding value="UTF-8"/> | <fmt:requestEncoding value="GBK"/> |
4. JSTL XML 处理标签库 (x:)
需额外声明:
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
| 标签 | 作用 | 语法 | 示例 |
|---|---|---|---|
<x:parse> | 解析XML | <x:parse xml="xmlContent" [var="varName"] [scope="scope"]/> | <x:parse xml="${rssFeed}" var="rssDoc"/> |
<x:out> | 输出XPath结果 | <x:out select="xpathExpr"/> | <x:out select="$rssDoc/channel/title"/> |
<x:set> | 保存XPath结果 | <x:set select="xpathExpr" var="varName"/> | <x:set select="$doc//item" var="newsItems"/> |
<x:if> | XPath条件判断 | <x:if select="xpathExpr">content</x:if> | <x:if select="$product/stock > 0">有货</x:if> |
<x:forEach> | XPath循环 | <x:forEach select="xpathExpr" [var="varName"]>content</x:forEach> | <x:forEach select="$rssDoc//item" var="item">${item.title}</x:forEach> |
<x:choose> | XPath多条件 | 类似核心库的choose | |
<x:transform> | XSLT转换 | <x:transform xml="xmlDoc" xslt="xslDoc"/> | <x:transform xml="${xmlData}" xslt="${xslTemplate}"/> |
<x:param> | XSLT参数 | <x:param name="paramName" value="paramValue"/> | 用于x:transform内部 |
5. JSTL SQL 标签库 (sql:)
注意:实际开发中不推荐在JSP中使用SQL标签,应使用DAO层
需额外声明:
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
| 标签 | 作用 | 语法 | 示例 |
|---|---|---|---|
<sql:setDataSource> | 设置数据源 | <sql:setDataSource url="jdbcUrl" driver="driverClass" user="username" password="pwd" [var="varName"]/> | <sql:setDataSource var="db" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/test" user="root" password="123456"/> |
<sql:query> | 执行查询 | <sql:query dataSource="ds" sql="sql" [var="result"]/> | <sql:query var="users" dataSource="${db}" sql="SELECT * FROM users"/> |
<sql:update> | 执行更新 | <sql:update dataSource="ds" sql="sql" [var="count"]/> | <sql:update dataSource="${db}" sql="INSERT INTO users(name) VALUES('Tom')"/> |
<sql:param> | 设置参数 | <sql:param value="paramValue"/> | <sql:query sql="SELECT * FROM products WHERE id=?"><sql:param value="${pid}"/></sql:query> |
<sql:dateParam> | 日期参数 | <sql:dateParam value="dateValue" type="date/time/timestamp"/> | <sql:dateParam value="${orderDate}" type="timestamp"/> |
<sql:transaction> | 事务管理 | <sql:transaction dataSource="ds">多个sql操作</sql:transaction> |
三、电商订单管理系统 - JSTL 完整标签综合案例
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
<!-- 1. 使用JSP脚本设置基础数据 -->
<%
// 模拟从数据库获取的订单数据
java.util.Map<String, Object> order = new java.util.HashMap<>();
order.put("orderId", "ORD202306001");
order.put("createTime", new java.util.Date());
order.put("totalAmount", 2999.99);
order.put("status", "SHIPPED");
// 订单商品列表
java.util.List<java.util.Map<String, Object>> items = new java.util.ArrayList<>();
java.util.Map<String, Object> item1 = new java.util.HashMap<>();
item1.put("productId", "P1001");
item1.put("productName", "智能手机 X1");
item1.put("price", 1999.99);
item1.put("quantity", 1);
items.add(item1);
java.util.Map<String, Object> item2 = new java.util.HashMap<>();
item2.put("productId", "P2002");
item2.put("productName", "无线耳机 Pro");
item2.put("price", 499.99);
item2.put("quantity", 2);
items.add(item2);
request.setAttribute("order", order);
request.setAttribute("items", items);
// 模拟国际化资源
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("messages", request.getLocale());
request.setAttribute("bundle", bundle);
%>
<!-- 2. 核心标签库使用 -->
<!DOCTYPE html>
<html>
<head>
<title><fmt:message key="order.detail.title"/></title>
</head>
<body>
<!-- 2.1 变量操作 -->
<c:set var="discount" value="0.1" scope="page"/> <!-- 设置10%折扣 -->
<!-- 2.2 输出订单基本信息 -->
<h1>
<fmt:message key="order.detail.header"/>:
<c:out value="${order.orderId}" default="N/A"/> <!-- 输出结果: ORD202306001 -->
</h1>
<p>
<fmt:message key="order.date"/>:
<fmt:formatDate value="${order.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/>
<!-- 输出结果: 2023-06-15 14:30:45 -->
</p>
<!-- 2.3 条件判断 -->
<c:choose>
<c:when test="${order.status == 'PAID'}">
<p class="status paid"><fmt:message key="order.status.paid"/></p>
<!-- 当status=PAID时输出: 已支付 -->
</c:when>
<c:when test="${order.status == 'SHIPPED'}">
<p class="status shipped"><fmt:message key="order.status.shipped"/></p>
<!-- 当status=SHIPPED时输出: 已发货 -->
</c:when>
<c:otherwise>
<p class="status other"><fmt:message key="order.status.other"/></p>
</c:otherwise>
</c:choose>
<!-- 2.4 循环展示商品 -->
<h2><fmt:message key="order.items.title"/></h2>
<table border="1">
<tr>
<th><fmt:message key="order.item.id"/></th>
<th><fmt:message key="order.item.name"/></th>
<th><fmt:message key="order.item.price"/></th>
<th><fmt:message key="order.item.quantity"/></th>
<th><fmt:message key="order.item.subtotal"/></th>
</tr>
<c:forEach items="${items}" var="item" varStatus="loop">
<!-- 输出结果: 循环输出所有商品行 -->
<tr>
<td>${item.productId}</td> <!-- 例如: P1001 -->
<td>
<c:out value="${item.productName}"/> <!-- 例如: 智能手机 X1 -->
</td>
<td>
<fmt:formatNumber value="${item.price}" type="currency"/>
<!-- 例如: ¥1,999.99 -->
</td>
<td>${item.quantity}</td> <!-- 例如: 1 -->
<td>
<fmt:formatNumber value="${item.price * item.quantity}" type="currency"/>
<!-- 例如: ¥1,999.99 -->
</td>
</tr>
</c:forEach>
</table>
<!-- 2.5 计算总金额 -->
<c:set var="subtotal" value="0"/>
<c:forEach items="${items}" var="item">
<c:set var="subtotal" value="${subtotal + (item.price * item.quantity)}"/>
</c:forEach>
<h3>
<fmt:message key="order.subtotal"/>:
<fmt:formatNumber value="${subtotal}" type="currency"/>
<!-- 输出结果: ¥2,999.97 -->
</h3>
<h3>
<fmt:message key="order.discount"/>:
<fmt:formatNumber value="${discount}" type="percent"/>
<!-- 输出结果: 10% -->
</h3>
<h2>
<fmt:message key="order.total"/>:
<fmt:formatNumber value="${subtotal * (1 - discount)}" type="currency"/>
<!-- 输出结果: ¥2,699.97 -->
</h2>
<!-- 3. 函数标签库使用 -->
<c:set var="deliveryInfo" value="北京市,朝阳区,建国路88号"/>
<p>
<fmt:message key="order.delivery.address"/>:
${fn:replace(deliveryInfo, ',', ' ')}
<!-- 输出结果: 北京市 朝阳区 建国路88号 -->
</p>
<!-- 4. XML标签库演示 (模拟从API获取的XML数据) -->
<c:set var="trackingXml">
<tracking>
<log>
<time>2023-06-15T08:00:00</time>
<location>北京转运中心</location>
<status>已揽收</status>
</log>
<log>
<time>2023-06-15T14:30:00</time>
<location>上海分拨中心</location>
<status>运输中</status>
</log>
</tracking>
</c:set>
<x:parse xml="${trackingXml}" var="trackingData"/>
<h2><fmt:message key="order.tracking.title"/></h2>
<ul>
<x:forEach select="$trackingData/tracking/log">
<li>
<x:out select="time"/> -
<x:out select="location"/> -
<x:out select="status"/>
<!-- 输出结果:
2023-06-15T08:00:00 - 北京转运中心 - 已揽收
2023-06-15T14:30:00 - 上海分拨中心 - 运输中
-->
</li>
</x:forEach>
</ul>
<!-- 5. SQL标签库演示 (仅作示例,实际项目不建议在JSP中使用) -->
<sql:setDataSource var="db"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/ecommerce"
user="root"
password="password"/>
<sql:query var="relatedProducts" dataSource="${db}">
SELECT * FROM products WHERE category = 'electronics' LIMIT 3
</sql:query>
<h2><fmt:message key="order.related.products"/></h2>
<ul>
<c:forEach var="product" items="${relatedProducts.rows}">
<li>${product.name} - <fmt:formatNumber value="${product.price}" type="currency"/></li>
<!-- 输出结果: 根据数据库查询结果显示3个电子产品 -->
</c:forEach>
</ul>
<!-- 6. URL和重定向操作 -->
<c:url var="orderListUrl" value="/orders">
<c:param name="status" value="completed"/>
<c:param name="page" value="1"/>
</c:url>
<p>
<a href="${orderListUrl}">
<fmt:message key="order.back.to.list"/>
<!-- 生成的URL: /orders?status=completed&page=1 -->
</a>
</p>
<!-- 7. 国际化消息 -->
<fmt:setLocale value="${pageContext.request.locale}"/>
<fmt:setBundle basename="messages" var="lang"/>
<footer>
<p><fmt:message key="footer.copyright"/></p>
<!-- 输出结果: 根据语言环境显示如"© 2023 电商平台" -->
</footer>
</body>
</html>