JSP中主要包含三大指令,分别是page,include,taglib。本篇主要提及include指令。
include指令使用格式:<%@ include file="文件的绝对路径或相对路径"%>
file属性:指定被包含的文件,该属性不支持任何表达式,也不允许通过如下的方式来传递参数。
<%@ include file="welcome.jsp?name=Tom"%>下面用法将会抛出异常,也是不允许的:
<% String path="login.jsp";%>
<%@ include file="<%=path%>"%>
如果该属性值以”/“开头,那么指定的是一个绝对路径,将在当前应用的根目录下查找文件;如果是以文件名称或文件夹名开头,那么指定的是一个相对路径,将在当前页面的目录下查找文件。
JSP中常用的动作标识有
或者向被包含的动态页面中传递参数:
page属性:和include指令的file属性一样。
flush属性:表示当输出缓冲区满时,是否清空缓冲区。该属性值为boolean类型,默认值为false,通常情况下设为true。
处理方式不同:使用include指令,被包含的文件的内容会原封不动地插入到包含页中使用该指令地位置,然后JSP编译器再对这个合成地文件进行编译最终编译成的文件只有一个。使用include动作标识,该标识被执行时,程序会将请求转发到(注意是转发而不是请求重定向)被包含的页面,并将执行结果输出到浏览器中,然后返回包含页继续执行后面的代码。服务器执行的是两个文件,JSP编译器会分别对这两个文件进行编译。注:]请求转发,存储在request对象中的信息会被保留并被带到目标页面中;请求重定向,重新生成一个request请求,将该请求重定向到指定的URL,所以事先存储在request对象中的信息都不存在了。
包含方式不同:include指令,静态包含,最终服务器执行的是将两个文件合成后由JSP编译器编译成的一个class文件,若改变被包含的文件,则主文件的代码就发生了改变,服务器会重新编译主文件。include动作标识,动态包含,通常用来包含那些经常需要改动的文件。服务器执行的是两个文件,被包含文件的改动不会影响到主文件,服务器不需要对主文件进行重新编译,只需要重新编译被包含的文件即可,而只有当
约定不同:include指令的约定index.jsp文件的部分代码
1 <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 <%@ include file="top.jsp" %>
top.jsp文件的部分代码
1 <%@ page language="java" contentType="text/html; charset=GB2312"%>
访问index.jsp将会出现异常
1 <%@ page language="java" contentType="text/html; charset=GB2312"%> 2 <jsp:include page="top.jsp"/>
——————————————————————————————————————————————————————
关于include指令和include动作指令的介绍见JSP基本语法(三)
首先,我们来看一下include指令所包含的内容与当前页面是一个整体是什么意思。
我们在Tomcat安装目录下的webapps文件夹下新建一个文件夹includeTEST,在这里进行一些实验。
在includeTEST文件夹下新建一个include.jsp:
<%@ page language="java" import="java.util.*" contentType="text/html;charset=gb2312"%>
<html>
<head><title>includetitle>head>
<body>
现在是:<%@ include file="date.jsp" %>
body>
html>
在这个JSP页面中,我们用include指令静态包含了date.jsp,接下来我们就新建一个date.jsp放在和include.jsp相同的目录下/webapps/includeTEST/
date.jsp
<%
Date date = new Date();
%>
<%=
date.toString()
%>
接下来启动Tomcat,打开浏览器输入
localhost:8080/includeTEST/include.jsp
能够正常显示出当前时间。然后我们到Tomcat安装目录下的
\work\Catalina\localhost\includeTESTorg\apache\jsp
中去查找include.jsp页面生成的对应的java文件,事实上我们会在这个目录下找到inlucde_jsp.java以及include_jsp.class,没有date_jsp.java相关的文件,说明include.jsp页面包括静态包含的date.jsp,一起只生成了一个文件,include_jsp.java截取如下:
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write(" JSP-welcome \r\n");
out.write(" \r\n");
out.write(" 现在是:");
Date date = new Date();
out.write("\r\n");
out.write("\r\n");
out.print(
date.toString()
我们发现,在该include_jsp.java文件中,new了一个Date对象,然后进行打印输出,也就是直接将date.jsp中的内容合进来,生成了同一个文件。
作为对比,我们同样在includeTEST/下新建一个includeAction.jsp,我们这次试用jsp的include动作指令来包含date.jsp:
<%@ page language="java" import="java.util.*" contentType="text/html;charset=gb2312"%>
<html>
<head><title>includeActiontitle>head>
<body>
现在是:<jsp:include page="date.jsp"/>
body>
html>
此时,我们打开浏览器输入
localhost:8080/includeTEST/includeAction.jsp
出现了错误!
错误信息:
org.apache.jasper.JasperException: Unable to compile class for JSP:
An error occurred at line: 2 in the jsp file: /date.jsp
Date cannot be resolved to a type
1: <%
2: Date date = new Date();
3: %>
4:
5: <%=
错误原因很简单,Date不能识别!但是使用<%@ include file="date.jsp" %>
时可以识别,为什么此处
就不能识别?!
原因就在于那句话:include标签会把包含的部分和当前页面生成同一个整体!于是Date就被头部的<%@ page language="java" import="java.util.*" contentType="text/html;charset=gb2312"%>
中的import=”java.util.*”引进来了。但是使用
生成的是两个单独的实体,于是在date.jsp这个独立的实体中,Date将无法识别!
这时候我们再次打开以下目录:
\work\Catalina\localhost\includeTESTorg\apache\jsp
会发现,当前目录下生成了
在这里我们看到了date_jsp.java,includeAction_jsp.java以及includeAction_jsp.class文件。生成了includeAction对应的class文件,说明includeAction.jsp页面可以正常编译执行。再次说明,includeAction.jsp和date.jsp是两个单独的实体!同时,由于includeAction.jsp能够生成class文件,也说明了date_jsp.java的编译执行起码是在includeAction执行之后才进行的,实际上是执行到
现在是:
对应的语句的时候,date.jsp才第一次被请求。但是编译出错。
接下来我们做以下修改,我们把date.jsp做以下修改并另存为date1.jap:
<%@ page language="java" import="java.util.*" contentType="text/html;charset=gb2312"%>
<%
Date date = new Date();
%>
<%=
date.toString()
%>
再次在浏览器输入
localhost:8080/includeTEST/includeAction.jsp
此时,时间可以打印出来了!关于中文乱码问题我们暂时不管。
再次进入
\work\Catalina\localhost\includeTESTorg\apache\jsp
此时生成了对应的date1_jsp.java以及date1_jsp.class文件:
最后我们用打开includeAction_jsp.java,部分代码如下:
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write(" includeAction \r\n");
out.write(" \r\n");
out.write(" 现在是:");
org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "date1.jsp", out, false);
out.write("\r\n");
out.write(" \r\n");
out.write("");
这里我们可以清楚地看到,对date1.jsp的include是通过请求的方式进行的!
通过这个实验我们可以看到include指令和include动作指令的区别。更多细节的差异,可以类似地通过更多的实验来探索验证。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
include指令和include动作都能实现将外部文档包含到JSP文档中的功能,名称也很相似,非常容易混淆。include指令和include动作到底有什么分别,哪一种方式会更好呢?
1.include指令
include可以在JSP页面转换成Servlet之前,将JSP代码插入其中。它的主要优点是功能强大,所包含的代码可以含有总体上影响主页面的JSP构造,比如属性、方法的定义和文档类型的设定。它的缺点是难于维护只要被包含的页面发生更改,就得更改主页面,这是因为主页面不会自动地查看被包含的页面是否发生更改。
include指令的语法格式如下
<%@ include file="Relative Url"%>
2.include动作
jsp:include动作是在主页面被请求时,将次级页面的输出包含进来。尽管被包含的页面的输出中不能含有JSP,但这些页面可以是其他资源所产生的结果。服务器按照正常的方式对指向被包含资源的URL进行解释,因而这个URL可以是Servlet或JSP页面。服务器以通常的方式运行被包含的页面,将产生的输出放到主页面中,这种方式与RequestDispatcher类的include方法一致。它的优点是在被包含的页面发生更改时,无须对主页面做出修改。它的缺点是所包含的是次级页面的输出,而非次级页面的实际代码,所以在被包含的页面中不能使用任何有可能在整体上影响主页面的JSP构造。
jsp:include动作的完整语法如下
flush属性是一个可选的次级属性,默认值为false,它指定在将页面包含进来之前是否应该清空主页面的输出流。
注意:在JSP1.1中,flush是必需的属性,而且聚会只能是true。
3.两者的区别和比较
jsp:include动作和include指令之间的根本性的不同在于它们被调用的时间。jsp:include动作在请求期间被激活,而include指令在页面转换期间被激活。
两者之间的差异决定着它们在使用上的区别。使用include指令的页面要比使用jsp:include动作的页面难于维护。前面已经说过,使用JSP指令,如果包含的JSP页面发生变化,那么用到这个页面的所有页面都需要手动更新。在JSP服务器的相关规范中并没要求能够检测出包含的文件什么时候发生改变,实际上大多数服务器页都有去实现这种机制。这样就会导致十分严重的维护问题,需要记住所有包含某一个页面的其他页面,或者重新编译所有的页面,以使更改能够生效。在这点上,jsp:include就体现出了十分巨大的优势,它在每次请求时重新把资源包含进来。在实现文件包含上,应该尽可能地使用jsp:include动作。
jsp:include动作直比于include指令在维护上有着明显优势,而include指令仍然能够得以存在,自然在其他方面有特殊的优势。这个优势就是include指令的功能更强大,执行速度也稍快。include指令允许所包含的文件中含有影响主页面的JSP代码,比如响应报送的设置和属性方法的定义。以下表格就是两种包含方式的对比:
|
include指令 |
jsp:include动作 |
语法格式 |
<%@ include file=”..”%> |
|
发生作用的时间 |
页面转换期间 |
请求期间 |
包含的内容 |
文件的实际内容 |
页面的输出 |
转换成的Servlet |
主页面和包含页面转换为一个Servlet |
主页面和包含页面转换为独立的Servlet |
影响主页面 |
可以 |
不可以 |
|
include指令 |
jsp:include动作 |
发生更改时是否需要显式更改主页面 |
需要 |
不需要 |
编译时间 |
较慢-资源必须被解析 |
较快 |
执行时间 |
稍快 |
较慢-每次资源必须被解析 |
灵活性 |
较差-页面名称固定 |
更好-页面可以动态指定 |
了解到jsp:include动作和include指令各自的功能和区别,在使用时,就可以通过考虑各方面的因素,来决定使用哪一种方式。尽管各自都有一定的优缺点,在实际使用中,还是应优先考虑使用jsp:include动作,这是因为它在代码维护上的优势远胜过其在功能上的不足。