JSP标记库是否像某种受限制的JAVA代码生成一样工作?

时间:2015-01-28 04:00:45

标签: jsp tags jstl jsp-tags

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

我是JSP的新手。我了解到JSP页面最终变成了Servlets。

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

似乎每个标记都封装了一个常用的Java代码块,其中一些插槽由标记属性填充/控制。并将块插入_jspService()方法。

这是标记库如何为最终的servlet Java代码做出贡献的一般机制吗?

ADD 1

我为包含<c:forEach>标记的JSP挖掘生成的 servlet 代码。

JSP代码是这样的:

图片1:

enter image description here

生成的servlet代码如下:

图片2:

enter image description here

图3:

enter image description here

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

  1. JSP (picture 1) ==> Servlet Java code (picture 2, 3)
  2. Servlet Java code ==> HTML(容器执行_jspService()方法)。
  3. 我的问题是:

    • 图片2和3的代码来自哪里?

    • 谁在JSP生成的servlet类中布局图片2和3的代码?

    ADD 2

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

    • 给出了一系列要迭代的项目。
    • 它为外部世界提供了一些API来控制迭代过程。

    并公开迭代数据:

    • 它使用scope作为桥梁将当前迭代项目传达给外部世界。

    虽然外部_jspx_meth_c_005fforEach_005f0方法只使用ForEachTag类型来执行迭代。直到ForEachTag告诉他停止。

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

    ADD 3

    如果我对Web容器和Tab库之间的不同责任进行分析,容器如何知道如何生成类似于图片2和3的代码以支持新的标签库

    回答ADD 3

    无论是简单/经典标签,容器只需要生成boilplate代码来调用其生命周期方法。下面是一个简单标记的示例:

    enter image description here

    Container只关心生命周期方法。如果有身体,容器将进一步解析身体的经典标签。对于简单标记,doTag()方法涵盖了所有内容。

    ADD 4

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

    ForEachTag

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

2 个答案:

答案 0 :(得分:2)

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

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

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

URI(由conatiner)映射到.tld标记库描述符文件,该文件包含将<tag>条目映射到其实现的Java类并描述标记支持的所有属性。如果要实现生成屏幕键盘的自定义标记,则输入可能类似于

<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目录下的任何位置。标记处理程序类需要实现特定的接口,但容器还提供了我们可以扩展的SimpleTagSupport类。

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>

答案 1 :(得分:0)

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

ForEachTag:

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

回答ADD 3

无论是简单/经典标签,容器只需要生成boilplate代码来调用其生命周期方法。下面是一个简单标记的示例:

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

enter image description here

Container只关心生命周期方法。如果有身体,容器将进一步解析身体的经典标签。对于简单标记,doTag()方法涵盖了所有内容。