【问题标题】:How to test if <jsp:doBody/> is empty / null in a tag file?如何测试标签文件中的 <jsp:doBody/> 是否为空/null?
【发布时间】:2014-08-05 08:11:43
【问题描述】:

我最近发现了jsp标签并使用它们来避免重复我的观点的共同部分。

所以在我的 JSP 视图中我有

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

在我的标签文件中,我得到了带有&lt;jsp:doBody/&gt; 的 HTML。

我的问题是,我如何测试 &lt;jsp:doBody/&gt; 是否为空,以便我可以放置默认的 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的正确表达

提前致谢。

【问题讨论】:

    标签: jsp jsp-tags


    【解决方案1】:

    您可以选择三个选项,每个选项都有其优点和缺点。

    1。 &lt;jsp:doBody var="bodyText" /&gt;

    这可能是最常见和最明显的解决方案。

    您执行一次主体,将其输出存储在一个变量中,然后检查该变量是否为空。

    <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。

      请注意,这只适用于标签文件,不适用于简单/经典的标签处理程序。在上面的例子中,如果&lt;my:tag&gt; 被定义在一个标签处理程序中,无论空白设置如何,处理程序都会表现得好像一个主体存在:

      • 对于简单的标签处理程序,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>
    

    【讨论】:

    • 非常好的和彻底的答案。请注意,您可以使用内置的 JSTL 函数 trim,如下所示:&lt;c:when test="${not empty fn:trim(bodyText)}"&gt;。现在,父 JSP 上的空白设置是什么并不重要。
    • 优秀点@ach!我刚刚将您的建议纳入答案。 ?
    • 看起来您可以将其概括为任何 JSPFragment,而不仅仅是正文。使用 。 Scriptlet 版本并不明显,但我认为有一种方法可以以编程方式访问通用片段。
    • @Ryan 有趣的建议...实际上测试属性JSPFragment 比测试主体JSPFragment 更容易。查看更新的答案!
    • @mxxk 酷。该测试表达式中实际发生了什么? JSPFragment 对象如何转换为布尔值?谢谢。
    【解决方案2】:

    你可以这样做。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-05
      • 1970-01-01
      • 2011-02-27
      • 2011-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多