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

时间:2014-08-05 08:11:44

标签: jsp jsp-tags

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

所以在我的JSP视图中我有

<web-component:mytag>
<!-- HTML specific to that page -->
</web-component:mytag>

在我的代码文件中,我获得了带有<jsp:doBody/>的HTML。

我的问题是,如何测试<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>

所以我正在寻找doBody.empty

的正确表达方式

提前致谢。

2 个答案:

答案 0 :(得分: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>
  

为什么使用${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",您的代码文件将检测到有正文。

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

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

2。的scriptlet

您可以通过使用Java代码测试null body来消除第一个解决方案的缺点。这个解决方案和下一个解决方案就是这样做的,除了这个解决方案更简单并且使用了一个小脚本。

<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()方法中执行scriptlet。因此,super.getJspBody() == null的工作方式与您在任何简单标记处理程序中的预期相同。

赞成

  • 在不执行正文的情况下完成对空体的测试。

  • 正文未存储在变量中。

缺点

  • 使用scriptlet。 (但请注意,无论JSP文件的scripting-invalid配置如何,都允许标记文件使用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);
  }
}

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

<my:hasBody />
<c:choose>
  <c:when test="${hasBody}">
    <jsp:doBody />
  </c:when>
  <c:otherwise>
    <!-- Default content here -->
  </c:otherwise>
</c:choose>

赞成

  • 不使用scriptlet。
  • 功能上与scriptlet解决方案等效。

缺点

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

附录:与非正文JSPFragments一起使用

@Ryan想知道如何将此方法应用于一般JSPFragment属性。幸运的是,因为所有属性都可以作为EL中的变量直接访问(而实体不是),测试空片段属性是微不足道的:

<%@ 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>

答案 1 :(得分:0)

你可以这样做。

<jsp:doBody var="bodyText"/>
<c:if test="${not empty bodyText}">
    //will shown if its not empty
</c:if>