JSP包含指令、JSP包含动作和使用JSP标签文件之间有什么区别?

160
似乎使用JSP进行模板化有两种方法。其中一种方法是通过以下语句包含文件:
<%@ include file="foo.html" %>
<jsp:include page="foo.html" />

或者使用JSP标记文件。
// Save this as mytag.tag
<%@ tag description="Description" pageEncoding="UTF-8"%>
<html>
<head>
</head>
<body>
    <jsp:doBody/>
</body>
</html>

在另一个JSP页面中,可以使用以下方式调用:

<%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:mytag>
    <h1>Hello World</h1>
</t:mytag>

那么我应该使用哪种方法?现在是否有一种被认为已经过时,还是它们都有效并涵盖不同的用例?

编辑

使用这个标签文件和使用include是一样的吗?

// Save this as product.tag
<%@ tag description="Product templage" pageEncoding="UTF-8"%>
<%@ tag import="com.myapp.Product" %>
<%@ attribute name="product" required="true" type="com.myapp.Product"%>

Product name: ${product.name} <br/>
Quantity: ${product.quantity} <br/>

在另一个JSP上调用它:

<%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:product>
    <c:forEach items="${cart.products}" var="product">
        <t:product product="${product}"/>
    </c:forEach>
</t:product>

这对我来说似乎与使用include并传递参数相同。那么,标签文件和include是一样的吗?
5个回答

303

JSP语法元素概述

首先,为了更清楚地说明问题,这里简要概述了JSP语法元素

  • 指令:这些指令传达有关JSP页面的整体信息。
  • 脚本元素:这些是Java编码元素,如声明、表达式、脚本块和注释。
  • 对象和作用域:JSP对象可以显式或隐式地创建,并且可以在给定的作用域内访问,例如从JSP页面或会话的任何位置。
  • 动作:这些动作在JSP响应中创建对象或影响输出流(或两者兼有)。

JSP中如何包含内容

JSP文件中有几种机制可以重用内容。

以下4种将内容包含在JSP中的机制可以归类为直接重用
(前3种机制引用自"Head First Servlets and JSP"

1) The include directive:

<%@ include file="header.html" %>

Static: adds the content from the value of the file attribute to the current page at translation time. The directive was originally intended for static layout templates, like HTML headers.

2) The <jsp:include> standard action:

<jsp:include page="header.jsp" />

Dynamic: adds the content from the value of the page attribute to the current page at request time. Was intended more for dynamic content coming from JSPs.

3) The <c:import> JSTL tag:

<c:import url=”http://www.example.com/foo/bar.html” />

Dynamic: adds the content from the value of the URL attribute to the current page, at request time. It works a lot like <jsp:include>, but it’s more powerful and flexible: unlike the other two includes, the <c:import> URL can be from outside the web Container!

4) Preludes and codas:

Static: preludes and codas can be applied only to the beginnings and ends of pages.
You can implicitly include preludes (also called headers) and codas (also called footers) for a group of JSP pages by adding <include-prelude> and <include-coda> elements respectively within a <jsp-property-group> element in the Web application web.xml deployment descriptor.

Read more here:
Configuring Implicit Includes at the Beginning and End of JSPs
Defining implicit includes


标签文件是一种间接的内容重用方法,一种封装可重用内容的方式。 标签文件是一个包含可重用JSP代码片段的源文件,可作为自定义标签使用。

包含文件和标签文件的目的是不同的。

标签文件(JSP 2.0引入的概念)是创建自定义标签的选项之一。这是一种更快、更简便的构建自定义标签的方法。 自定义标签,也称为标签扩展,是允许将其他Java组件提供的自定义逻辑和输出插入到JSP页面中的JSP元素。通过自定义标签提供的逻辑由一个称为标签处理器的Java对象实现。

一些可以由自定义标签执行的任务的示例包括对隐式对象进行操作、处理表单、访问数据库和其他企业服务(如电子邮件和目录),以及实现流程控制。

关于您的编辑

也许在您的示例中(在您的“编辑”段落中),直接包含和标签文件之间没有区别。但是自定义标签具有丰富的功能。它们可以:

  • 通过从调用页面传递的属性进行自定义。

  • 将变量传递回调用页面。

  • 访问所有可用于JSP页面的对象。

  • 彼此通信。您可以创建和初始化一个JavaBeans组件,在一个标签中创建一个引用该bean的公共EL变量,然后在另一个标签中使用该bean。

  • 可以嵌套在彼此之内,并通过私有变量进行通信。

也可以从《Pro JSP 2》中阅读这篇文章:了解 JSP 自定义标签

有用的阅读


结论

为每个任务使用合适的工具。

使用标签文件是一种快速简便的方法,可以创建自定义标签,帮助您封装可重用的内容

至于在JSP中包含内容(引用自这里):

  • 如果文件很少更改,请使用包含指令。这是最快的机制。如果您的容器无法自动检测更改,您可以通过删除主页面类文件来强制生效更改。
  • 仅在内容经常更改且在请求主页面之前无法确定要包含的页面时,请使用包含操作。

1
但是,jsp:include 不就和使用标签文件一样吗?我看不出有什么区别...你可以像传递变量到标签文件一样传递变量到被 jsp:include 包含的文件中。这两种方法都允许您重复使用内容,它们似乎完全相同。除了名称之外,它们之间是否有任何区别? - sonicboom
2
@informatik01 给出了非常好的答案,我很欣赏它的深度、漂亮的格式和非常实用的4个机制列表。 - Russell Silva
2
jsp:include 相对于 <*@ include url..> 的优势是什么? - Chaitanya Gudala
@KrsnaChaitanya 注意:你在include指令中有一个拼写错误(星号*)。<jsp:include>是标准的include动作,<%@ include file="" %>是include指令。请阅读最后一节(灰色框中)以了解其优势(即何时选择其中之一的建议)。还可以查看这篇文章(http://sharat.wordpress.com/2006/08/28/10-what-is-the-difference-between-pagedirective-include-action-tag-include/)获取详细描述。希望对你有所帮助。 - informatik01
@informatik01这是否意味着使用include standard action,每次我们“要求”包含的页面时都会进行翻译?因为如果只翻译一次,它就不会是动态的,对吧?我的意思是它看不到任何更改的内容。 - Stefan
2
@Stefan 不是每一次都要改变,只有在被改变时才需要,即与包含(“父”)JSP 相同的方式。请参见 此答案,了解使用 <jsp:include> 时生成代码的示例。此外,这是关于 "JSP 执行" 过程的非常有帮助的描述。 - informatik01

23

可能重复的问题

<@include> - 指令标签指示JSP编译器在创建生成的servlet代码之前将包含文件内容合并到JSP中。它等同于将文本从您的包含页面剪切并粘贴到您的JSP中。

  • 在运行时只执行一个servlet。
  • 在父页面中声明的脚本变量可以在包含的页面中访问(记住,它们是同一页)。
  • 包含的页面不需要能够作为独立的JSP编译。它可以是代码片段或纯文本。包含的页面永远不会被编译为独立的。包含的页面也可以有任何扩展名,尽管.jspf已成为惯常使用的扩展名。
  • 旧容器的一个缺点是,对包含的页面所做的更改可能不会生效,直到更新了父页面。最近版本的Tomcat会检查包含页面的更新并强制重新编译父页面。
  • 进一步的缺点是,由于代码直接嵌入到生成的servlet的service方法中,方法可能会变得非常大。如果超过64KB,则JSP编译可能会失败。

<jsp:include> - 另一方面,JSP操作标记指示容器暂停执行此页面,去运行包含的页面,并将该页面的输出合并到此页面的输出中。

  • 每个包含的页面在运行时作为单独的servlet执行。
  • 可以在运行时有条件地包含页面。这对于构建包含页面的模板框架通常很有用。父页面可以根据某些运行时条件确定是否包含哪个页面。
  • 脚本变量的值需要明确传递给包含的页面。
  • 包含的页面必须能够单独运行。
  • 由于生成的servlet类中的最大方法大小未被超越,您不太可能遇到编译错误。

根据你的需求,你可以使用<@include><jsp:include>


1
你的意思是像你在问题中展示的那样:<t:mytag><h1>Hello World</h1></t:mytag>?那不是一个包含,它是标签的正常使用(就像<jsp:useBean><c:if>)。 - Uooo
那么使用标签文件和包含文件有什么区别呢?因为似乎标签文件可以用于在页面中包含内容? - sonicboom

9
< p > <jsp:include /> 相对于 <%@ include > 的主要优势是:< /p> < p ><jsp:include /> 允许传递参数。< /p>
<jsp:include page="inclusion.jsp">
    <jsp:param name="menu" value="objectValue"/>
</jsp:include>

<%@include file="somefile.jsp" %>中不可能实现。

关于标签文件,我知道如何使用包含文件。我想知道标签文件与包含文件的关系,因为它们似乎提供相同的功能。使用标签文件和使用包含文件有什么区别? - sonicboom
<%@include file="somefile.jsp?menu=value" %>也受限制吗? - Roshana Pitigala

6
所有三种模板选项 - <%@include><jsp:include><%@tag>都是有效的,并且它们覆盖不同的使用情况。
使用<@include>时,JSP解析器会将包含文件的内容嵌入到JSP中进行编译(类似于C中的#include)。您可以使用此选项来包含简单的静态内容:例如,如果您想在Web应用程序的每个页面中包含标题、页脚或导航元素。包含的内容成为已编译JSP的一部分,在运行时没有额外的成本。 <jsp:include>(以及类似而更强大的JSTL的<c:import>)最适合动态内容。当您需要从另一个URL(本地或远程)包含内容时,或者被包含资源本身是动态的,或者被包含的内容使用与包含页面冲突的变量或bean定义时,请使用这些选项。 <c:import>还允许您将包含的文本存储在变量中,您可以进一步操作或重用。这两种方法都会产生额外的运行时成本:这很小,但您需要知道动态包含不是“免费的”。
当您想要创建可重用的用户界面组件时,请使用标记文件。例如,如果您有一个Widget列表,并且想要迭代Widgets并显示每个Widget的属性(在表格中或在表单中),则会创建一个标记。标记可以使用<%@tag attribute>接受参数,这些参数可以是强制性的或可选的 - 有点像方法参数。
标记文件是一种更简单、基于JSP的编写标记库的机制,而在JSP2.0之前,您必须使用Java代码编写标记库。如果标记中需要进行大量呈现,则使用JSP标记文件更加清晰:如果您使用Java编写标记,则需要混合Java和HTML代码。

所以,如果一个JSP文件使用<jsp:include>标签10次来调用某个其他文件,那么该其他文件将被翻译10次(并发送其响应)。而使用<@include>标签10次,则只会在翻译时翻译一次该其他文件。我理解得对吗? - Stefan
@Stefan 对于 <jsp:include>,另一个文件将被翻译成 Java 代码并编译一次,然后编译的类(方法)将被调用10次。对于 @include,其他文件的10个副本将被“粘贴”到调用文件中,然后整个内容将被翻译和编译一次。如果包含的文件包含变量声明,则会出现错误,因为使用 @include 会重新声明9次该变量。 - Stephen P

1
根据: Java Revisited
  1. 通过include指令包含的资源在jsp翻译时被加载,而通过include操作包含的资源在请求时被加载。

  2. 对于include指令包含的资源进行的更改,在jsp文件重新编译之前是不可见的。而对于include操作,任何包含资源的更改将在下一次请求中可见。

  3. Include指令是静态导入,而include操作是动态导入。

  4. Include指令使用file属性来指定要包含的资源,而include操作使用page属性来实现相同的目的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接