您可以选择三个选项,每个选项都有其优点和缺点。
1。 <jsp:doBody var="bodyText" />
这可能是最常见和最明显的解决方案。
您执行一次主体,将其输出存储在一个变量中,然后检查该变量是否为空。
<jsp:doBody var="bodyText"/>
<c:choose>
<c:when test="${not empty fn:trim(bodyText)}">
${bodyText}
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>
为什么使用${not empty fn:trim(bodyText)} 而不是更简单的条件${empty bodyText}?感谢@ach,他指出了这一点,后者修剪了空白,因此无论trimDirectiveWhitespaces 设置如何,其行为都是一致的。
优点
缺点
身体总是被执行。您可能不想仅仅为了测试它的存在而执行标签主体(以及任何副作用)。
标签正文的全部内容都存储在内存中。对于较长的标签正文,这可能是一个问题。
-
(使用${not empty fn:trim(bodyText)}时忽略此点。仅适用于${empty bodyText}。)
条件${empty bodyText}是否为真取决于调用JSP是否启用trimDirectiveWhitespaces。
当标签的主体只包含空格时
<%@ page trimDirectiveWhitespaces="true" %>
<my:tag value="a">
</my:tag>
并且页面定义了trimDirectiveWhitespaces="true",您的标签文件将检测到没有正文。如果trimDirectiveWhitespaces="false",你的标签文件会检测到有body。
请注意,这只适用于标签文件,不适用于简单/经典的标签处理程序。在上面的例子中,如果<my:tag> 被定义在一个标签处理程序中,无论空白设置如何,处理程序都会表现得好像一个主体存在:
- 对于简单的标签处理程序,
getJspBody() 将是非空的。
- 对于经典标记处理程序,将调用
doAfterBody()。
2。小脚本
您可以通过使用 Java 代码测试空体来消除第一个解决方案的缺点。这个解决方案和下一个解决方案正是这样做的,只是这个解决方案更简单并且使用了一个 scriptlet。
<c:choose>
<c:when test="<%= super.getJspBody() != null %>">
<jsp:doBody />
</c:when>
<c:otherwise>
<!-- My default HTML content here -->
</c:otherwise>
</c:choose>
这样做的原因是标记文件被转换为扩展SimpleTagSupport 的处理程序(参见javax.servlet.jsp.tagext),并且脚本在处理程序的doTag() 方法中执行。因此super.getJspBody() == null 的工作方式与您在任何简单的标签处理程序中所期望的一样。
优点
空主体的测试在不执行主体的情况下完成。
正文未存储在变量中。
缺点
- 小脚本的使用。 (但请注意,无论 JSP 文件的
scripting-invalid 配置如何,标记文件都可以使用 scriptlet。)
3。助手标签
如果您需要 scriptlet 解决方案的功能而不实际使用 scriptlet,请继续阅读。
这里的想法是将主体空测试封装在从标记文件调用的标记处理程序中。标签处理程序可以通过getParent() 访问标签文件,并将布尔测试结果导出为变量:
class HasBody extends SimpleTag {
@Override
public void doTag() throws JspException {
TagAdapter adapter = (TagAdapter)this.getParent();
SimpleTagSupport parent = (SimpleTagSupport)adapter.getAdaptee();
// `getJspBody()` is a protected method, so actually you must use reflection.
JspFragment body = parent.getJspBody();
this.getJspContext().setAttribute("hasBody", body == null);
}
}
现在您的标签文件可能如下所示:
<my:hasBody />
<c:choose>
<c:when test="${hasBody}">
<jsp:doBody />
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>
优点
- 不使用小脚本。
- 功能上等同于 scriptlet 解决方案。
缺点
- 复杂。需要一个单独的标签处理程序来执行 body null 测试。
- 需要使用反射。
附录:与非正文 JSPF 片段一起使用
@Ryan 想知道如何将这种方法应用于一般的JSPFragment 属性。幸运的是,因为所有属性都可以作为 EL 中的变量直接访问(而 body 不是),所以对空片段属性的测试很简单:
<%@ attribute name="frag" fragment="true" %>
<c:choose>
<c:when test="${frag != null}">
<jsp:invoke fragment="frag" />
</c:when>
<c:otherwise>
<!-- Default content here -->
</c:otherwise>
</c:choose>