如何在标记文件中测试<jsp:doBody />是否为空/空?

Fla*_*Fla 6 jsp jsp-tags

我最近发现了jsp标签并使用它们来避免重复我的视图的常见部分.

所以在我的JSP视图中我有

<web-component:mytag>
<!-- HTML specific to that page -->
</web-component:mytag>
Run Code Online (Sandbox Code Playgroud)

在我的标签文件中,我得到了HTML <jsp:doBody/>.

我的问题是,如何测试是否<jsp:doBody/>为空,以便我可以放置默认的HTML内容?

就像是

<c:choose>
    <c:when test="${!doBody.empty}">
        <jsp:doBody/>
    </c:when>
    <c:otherwise>
    <!-- My default HTML content here -->
    </c:otherwise>
</c:choose>
Run Code Online (Sandbox Code Playgroud)

所以我正在寻找正确的表达方式 doBody.empty

提前致谢.

mxx*_*xxk 8

您有三种选择,每种选择都有其优缺点.

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>
Run Code Online (Sandbox Code Playgroud)

为什么要使用${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>
    
    Run Code Online (Sandbox Code Playgroud)

    并且页面定义了trimDirectiveWhitespaces="true",您的标记文件将检测到没有正文.如果trimDirectiveWhitespaces="false",您的标记文件将检测到有正文.

    请注意,这仅适用于标记文件,而不适用于简单/经典标记处理程序.在上面的示例中,如果<my:tag>在标记处理程序中定义,则无论空白设置如何,处理程序的行为都会像正文一样存在:

    • 对于简单标记处理程序,getJspBody()将为非null.
    • 对于经典标记处理程序,doAfterBody()将被调用.

2. Scriptlet

您可以通过使用Java代码测试null body来消除第一个解决方案的缺点.这个解决方案和下一个解决方案完全相同,除了这个更简单并使用scriptlet.

<c:choose>
  <c:when test="<%= super.getJspBody() != null %>">
    <jsp:doBody />
  </c:when>
  <c:otherwise>
    <!-- My default HTML content here -->
  </c:otherwise>
</c:choose>
Run Code Online (Sandbox Code Playgroud)

这样做的原因是标记文件被转换为扩展的处理程序SimpleTagSupport(请参阅javax.servlet.jsp.tagext),并且scriptlet在处理程序的doTag()方法中执行.因此super.getJspBody() == null在任何简单的标记处理程序中的工作方式与您期望的相同.

优点

  • 无需执行主体即可完成对空体的测试.

  • 正文不存储在变量中.

缺点

  • 使用scriptlet.(但请注意,无论scripting-invalidJSP文件的配置如何,都允许标记文件使用scriptlet .)

3.助手标签

如果您需要scriptlet解决方案的功能而不实际使用scriptlet,请继续阅读.

这里的想法是将body null测试封装在从标记文件调用的标记处理程序中.标签处理程序可以通过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);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在你的标签文件看起来像这样:

<my:hasBody />
<c:choose>
  <c:when test="${hasBody}">
    <jsp:doBody />
  </c:when>
  <c:otherwise>
    <!-- Default content here -->
  </c:otherwise>
</c:choose>
Run Code Online (Sandbox Code Playgroud)

优点

  • 不使用scriptlet.
  • 功能上等同于scriptlet解决方案.

缺点

  • 复杂.需要单独的标记处理程序才能执行body null测试.
  • 需要使用反射.