- 在JSP 指令中,可以通过include指令来包含其他文件的方法,include指令的语法为:
<%@ include file="被包含组件的绝对或相对URL" %>
- 除了使用include指令,还可以使用include标签来包含其他文件,include标签的语法为:
<jsp:include page="被包含的组件的绝对或相对URL" />
include指令用于静态包含;而include标签用于动态包含;
无论是静态包含还是动态包含,源组件和被包含的目标组件都共享请求范围内的共享数据。
静态包含
假设源JSP文件为include_source.jsp,被包含的目标JSP文件为include_destination.jsp。
当客户端请求访问源JSP时,JSP容器按照一下流程响应客户请求:
- 解析源JSP文件include_source.jsp;在解析<%@ include file="include_destination.jsp" %>时,把目标JSP文件include_destination.jsp的所有的源代码融合到include_source.jsp中。
- 把融合后的JSP源代码翻译为Servlet源文件,再把它翻译成为Servlet类。
- 初始化源JSP文件include_source.jsp对应的Servlet,再运行它的服务方法。
由此可见,静态包含发生在解析JSP源组件阶段,被包含的目标文件中的内容被原封不动地添加到JSP源组件中,Servlet容器然后再对JSP源组件进行翻译和编译。
静态包含的目标组件可以为HTML文件或者JSP文件,但不允许为Servlet。
如果目标组件为JSP文件,那么该JSP文件可以访问在源组件中定义的局部变量,因为实际上JSP源组件和JSP目标组件对应的是同一个Servlet。
为了区分JSP源组件及被静态包含的JSP或HTML目标组件,可以将静态包含的JSP文件用“*.jspf”作为文件扩展名,被静态包含的HTML文件用“*.htmf”作为文件扩展名;或者被静态包含的JSP或HTML文件都用“.inc”作为文件扩展名。
示例:
include_source.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Static Include Source JSP</title>
</head>
<body>
<% int var = 1;
request.setAttribute("username", "New User"); %>
The output is from include_source.jsp before include include_destination.jsp <br/>
<%@ include file="include_destination.jsp" %>
The output is from include_source.jsp after include include_destination.jsp <br/>
</body>
</html>
include_destination.jsp
<p>
Output is from include_destination.jsp<br/>
var = <%= var %><br/>
username = <%= request.getAttribute("username") %><br/>
</p>
在浏览器中访问如下URL:
http://localhost:8080/base-webapp/jsp/include_source.jsp
浏览器显示为:
动态包含
将源组件include_source.jsp中的include指令改为:
<%--
<%@ include file="include_destination.jsp" %>
--%>
<jsp:include page="include_destination.jsp" />
在浏览器中访问上面的URL,将会得到一个编译错误,变量var无法解析。
这是因为对于动态包含,目标组件和源组件分别对应不同的Servlet,两个不同的Servlet之间无法访问对方的服务方法中的局部变量。
在<CATALINA-HOME>/work目录下,会发现对应目标组件的Servlet类未生成对应的class文件:
当客户端首次请求访问源组件include_source.jsp时,JSP容器按照以下流程响应客户请求:
- 解析include_source.jsp并把它翻译为Servlet源文件,include_source.jsp中的<jsp:include page="include_destination.jsp" />被翻译成如下程序代码:
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "include_destination.jsp", out, false);
- 把Servlet源文件编译为Servlet类。
- 初始化与include_source.jsp对应的Servlet,再运行它的服务方法。
- 当Servlet容器执行上面生成的include方法时,会解析include_destination.jsp。
- 如果没有语法错误,那么把include_destination.jsp翻译为Servlet源文件,再编译Servlet源文件。假定无编译错误,将生成Servlet类,再初始化该Servlet并调用它的服务方法。
- 当Servlet容器执行完源JSP组件的include方法后,继续执行源JSP组件后面的代码。
由此可见,动态包含发生在运行JSP源组件阶段,动态包含的目标租金啊可以为HTML文件,JSP文件,或者为Servlet。如股票目标组件为JSP,Servlet容器会在运行JSP源组件的过程中,运行与JSP目标组件对应的Servlet的服务方法。
JSP目标组件生成的响应结果被包含到JSP源组件的响应结果中。
<jsp:include>标签还有一个flush属性,可选值为true和false,如果flush属性为true,就表示源组件在包含目标组件之前,先把已经生成的响应正文提交给客户;flush属性默认为false。
将上面的动态包含语句改为:
<jsp:include page="include_destination.jsp" flush="true" />
再次在浏览器中请求访问该JSP,则浏览器显示为:
而生成的错误将被写到容器的log中。
将目标JSP组件改为:
<p>
Output is from include_destination.jsp<br/>
<%--
var = <%= var %><br/>
--%>
username = <%= request.getAttribute("username") %><br/>
</p>
再次访问,浏览器显示为:
无错误产生。
混合使用静态包含和动态包含
静态包含通常用来包含不会发生变化的网页内容;而动态包含通常用来包含会发生变化的网页内容。
目标组件路径值的区别:
- 在动态包含中,我们可以通过表达式<%=detinationjsppath_variable%>指定page的值,如:
<jsp:include page="<%=bodyfile%>" />
- 而对于include指令,如果使用类似的方法,Servlet容器会把字符串“<%=bodyfile%>”的字面内容直接理解为一个目标组件的URL,而且由于找不到相应的目标组件,会导致一个错误:
<%@ include file="<%=bodyfile%>" %>