JSP 标签库的工作方式是否类似于某种模板化的 JAVA 代码生成?

Does JSP tag libraries work like some kind of tempated JAVA code generation?

(这个问题更多是关于容器如何包含标签。而不是关于标签应该如何实现。感谢 Ravi Thapliyal 指出。)

我是 JSP 的新手。我了解到 JSP 页面终于变成了 Servlet。

所以我比较了使用一些JSTL标签的JSP页面和容器生成的servletJava代码。

似乎每个标签都封装了一个常用的Java代码块,标签属性带有一些插槽filled/controlled。并且该块被插入到 _jspService() 方法中。

这是标记库对最终 servlet Java 代码的贡献的一般机制吗?

加 1

我挖掘生成的 servlet 代码用于包含 <c:forEach> 标签的 JSP。

JSP代码是这样的:

图片1:

生成的servlet代码是这样的:

图片二:

图3:

它应该是一个 2 步 过程来生成对客户端的最终响应:

  1. JSP (picture 1) ==> Servlet Java code (picture 2, 3)
  2. Servlet Java code ==> HTML(容器执行_jspService()方法)。

我的问题是:

添加 2

通过检查图 3 中的代码,对于 org.apache.taglibs.standard.tag.rt.core.ForEachTag class, 我猜 ForEachTag 类型有点像 iterator:

并公开迭代数据:

而外面的_jspx_meth_c_005fforEach_005f0方法只是使用ForEachTag类型进行迭代。直到 ForEachTag 让他停止。

所以我猜图 2 和图 3 中的代码只是 Web 容器的 JSP 解析逻辑的一部分,用于支持 JSTL 标签。

加 3

如果我分析Web Container和Tab库的不同职责,容器怎么知道如何生成类似于图2和图3的代码来支持一个新的标签库

回答加3

无论是 simple/classic 标签,容器只需要生成样板代码来调用它们的生命周期方法。下面是一个简单标签的示例:

容器只关心生命周期方法。如果有正文,容器将进一步解析正文以获得 classic 标签。对于简单的标签,doTag() 方法涵盖所有​​内容。

加 4

学习了classic tag lifecycle后,我明白了org.apache.taglibs.standard.tag.rt.core.ForEachTag是一个classic标签处理器。图 3 中的代码是 Container 在评估标签体时调用 classic 生命周期方法。

ForEachTag:

是的,您的观察是正确的。标签库的行为类似于迷你模板引擎 运行 Java 代码(作为最终 servlet 的一部分),带有标签属性(可选)自定义 Java 实现。

如果您查看 JSP 文件头,它使用了任何 JSTL 标记,您会注意到它通过引用其 URI 导入标记库描述符并为其分配一个前缀,稍后在调用时使用库中的标签之一。

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

URI 被(由容器)映射到一个 .tld 标签库描述符文件,该文件包含 <tag> 个条目,将每个标签映射到它的实现 Java class 和描述标签支持的所有属性。如果您要实现生成屏幕键盘的自定义标签,您的条目可能看起来像

<tag>
  <description>Generates an on-screen keyboard</description>
  <name>onScreenKB</name>
  <tag-class>com.myapp.jsp.tags.OnScreenKBTag</tag-class>
  <body-content>empty</body-content>
</tag>

此 .tld 文件被放置在 /WEB-INF 目录下的任何位置。标签处理程序 class 需要实现一个特定的 接口 但容器还提供了一个 SimpleTagSupport class 我们可以从中扩展。

public class OnScreenKBTag extends SimpleTagSupport {

  public void doTag() throws JspException, IOException {
    StringBuilder html = new StrinBuilder();
    JspWriter out = getJspContext().getOut();

    // tag logic
    html.append(...);
    ...
    // print response
    out.print(html);
  }
}

然后在您的 JSP 文件中导入

<%@ taglib uri="/WEB-INF/tags/myapp.tld" prefix="app" %>

并将您的自定义标签用作

<div id="keyboard">
  <app:onScreenKB />
</div>

学习了经典的tag lifecycle,明白了org.apache.taglibs.standard.tag.rt.core.ForEachTag是一个经典的tag handler。图3中的代码是Container在评估标签体时调用经典的生命周期方法。

ForEachTag:

  • 包含要循环的收集数据
  • 保持循环状态
  • 并使用其生命周期方法来控制循环。

回答加3

无论是 simple/classic 标签,容器只需要生成样板代码来调用它们的生命周期方法。下面是一个简单标记的示例:

红色的是生命周期方法调用。

容器只关心生命周期方法。如果有 body,container 会进一步解析 body 中的 classic 标签。对于简单的标签,doTag()方法涵盖了一切。