JSP 标准标签库(JSTL)
core / fmt / functions 三个标签库的常用标签与写法。
Key PointsJSTL 用标签代替脚本:c:if 做判断,c:forEach 做循环,c:out 安全输出,fmt 格式化,fn 做字符串处理。
引入
JSP
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<%@ taglib prefix="fn" uri="jakarta.tags.functions" %>JSTL 1.x uses http://java.sun.com/jsp/jstl/core; JSTL 2.0+ (Jakarta EE 9 onward) uses jakarta.tags.core. A wrong URI raises no error — the tags are just echoed as plain HTML.
core 标签
| Tag | Purpose |
|---|---|
<c:out> | 输出并转义 HTML |
<c:set> / <c:remove> | 在指定作用域存/删变量 |
<c:if> | 单分支判断 |
<c:choose> | 配 when / otherwise |
<c:forEach> | 遍历集合或计数 |
<c:forTokens> | 按分隔符拆字符串 |
<c:url> / <c:param> | 拼 URL 并自动编码 |
<c:redirect> | 标签形式的重定向 |
JSP
<c:if test="${not empty user}">
<p>欢迎,<c:out value="${user.name}"/></p>
</c:if>
<c:choose>
<c:when test="${score >= 90}"><p>优秀</p></c:when>
<c:when test="${score >= 60}"><p>及格</p></c:when>
<c:otherwise><p>不及格</p></c:otherwise>
</c:choose>
<c:forEach var="u" items="${users}" varStatus="s">
<p>${s.index + 1}. <c:out value="${u.name}"/></p>
</c:forEach>varStatus gives index (0-based), count (1-based), first and last. "No comma on the last row" is exactly s.last.
fmt 标签
JSP
<fmt:formatNumber value="${price}" pattern="#,##0.00"/>
<fmt:formatNumber value="${rate}" type="percent"/>
<fmt:formatDate value="${created}" pattern="yyyy-MM-dd HH:mm"/>
<fmt:formatDate value="${created}" type="both" dateStyle="long"/>
<fmt:setLocale value="zh_CN"/>
<fmt:setBundle basename="messages"/>
<fmt:message key="greeting"/>functions 标签
JSP
${fn:length(users)}
${fn:toUpperCase(user.name)}
${fn:trim(param.q)}
${fn:contains(str, 'java')}
${fn:startsWith(str, 'http')}
${fn:replace(str, '-', '/')}
${fn:substring(str, 0, 10)}
${fn:escapeXml(param.comment)}
${fn:join(paramValues.hobby, '、')}fn:escapeXml is the key XSS defence. Any place user input reaches HTML must go through it or <c:out>.
常见坑
- EL 里不能写方法调用 ——
${user.getName()}无效,写${user.name} - **
${empty x}判断更全** —— 同时覆盖null、空串、空集合 - **
<c:out>默认转义** —— 需要输出 HTML 时加escapeXml="false"
Use
escapeXml="false" only for content you fully trust — your own rich text or HTML sanitised against a whitelist. Using it on user comments opens an XSS door.引入
JSP
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<%@ taglib prefix="fn" uri="jakarta.tags.functions" %>JSTL 1.x 的 uri 是 http://java.sun.com/jsp/jstl/core,JSTL 2.0+(Jakarta EE 9 之后)是 jakarta.tags.core。URI 写错不会报错,只是标签被当成普通 HTML 原样输出。
core 标签
| 标签 | 用途 |
|---|---|
| 输出 | 输出并转义 HTML |
| 赋值 | 在指定作用域存/删变量 |
| 条件 | 单分支判断 |
| 多分支 | 配 when / otherwise |
| 循环 | 遍历集合或计数 |
| 分词循环 | 按分隔符拆字符串 |
| URL | 拼 URL 并自动编码 |
| 重定向 | 标签形式的重定向 |
JSP
<c:if test="${not empty user}">
<p>欢迎,<c:out value="${user.name}"/></p>
</c:if>
<c:choose>
<c:when test="${score >= 90}"><p>优秀</p></c:when>
<c:when test="${score >= 60}"><p>及格</p></c:when>
<c:otherwise><p>不及格</p></c:otherwise>
</c:choose>
<c:forEach var="u" items="${users}" varStatus="s">
<p>${s.index + 1}. <c:out value="${u.name}"/></p>
</c:forEach>varStatus 提供 index(从 0 开始)、count(从 1 开始)、first、last。做「最后一行不加逗号」这类需求就靠 s.last。
fmt 标签
JSP
<fmt:formatNumber value="${price}" pattern="#,##0.00"/>
<fmt:formatNumber value="${rate}" type="percent"/>
<fmt:formatDate value="${created}" pattern="yyyy-MM-dd HH:mm"/>
<fmt:formatDate value="${created}" type="both" dateStyle="long"/>
<fmt:setLocale value="zh_CN"/>
<fmt:setBundle basename="messages"/>
<fmt:message key="greeting"/>functions 标签
JSP
${fn:length(users)}
${fn:toUpperCase(user.name)}
${fn:trim(param.q)}
${fn:contains(str, 'java')}
${fn:startsWith(str, 'http')}
${fn:replace(str, '-', '/')}
${fn:substring(str, 0, 10)}
${fn:escapeXml(param.comment)}
${fn:join(paramValues.hobby, '、')}fn:escapeXml 是防 XSS 的关键函数。凡是把用户输入输出到 HTML 的地方,都要过一遍它或 <c:out>。
常见坑
- EL 里不能写方法调用 ——
${user.getName()}无效,写${user.name} - **
${empty x}判断更全** —— 同时覆盖null、空串、空集合 - **
<c:out>默认转义** —— 需要输出 HTML 时加escapeXml="false"
escapeXml="false" 只在内容完全可信(你自己生成的富文本、经过白名单清洗的 HTML)时用。用它渲染用户评论,等于开了一个 XSS 大门。