3.4 JSP动作元素
JSP动作元素(Action Element)和JSP指令元素不同,它是在客户端请求时动态执行的,是通过XML语法格式的标记来实现控制Servlet引擎行为的。JSP动作元素是一种特殊标签,并且以前缀jsp和其他的HTML标签相区别,利用JSP动作元素可以实现很多功能,包括动态地插入文件、重用JavaBean组件、把用户重定向到另外的页面、为Java插件生成HTML代码等。JSP定义了几个预设的Action Element标签,如表3-1所示。
表3-1 JSP预设Action Element标签
表3-1中第一部分的操作元素是在JSP网页中使用JavaBean及属性值存取的元素,这一部分在第6章中会有详细的说明。第三部分是JSP 2.0规格里新增的与XML有关的元素,本章接下来的部分将针对一般性的Action Element的使用方式进行说明。
3.4.1 <jsp:include>
<jsp:include>动作元素可以用来包含其他静态和动态页面。JSP有两种不同的包含方式:编译时包含和运行时包含。编译时包含只是将静态文件内容加到JSP页面中,其优点是速度快,如前面提到的<%@ include file="" %>指令。运行时包含指被包含的文件在运行时被JSP容器编译执行,<jsp:include>的包含就是运行时包含,同时支持编译时包含。
<jsp:include>有带参数和不带参数两种语法格式,分别如下:
<jsp:include page="relative URL" flush="true|false"/>
和
<jsp:include page="relative URL" flush="true|false"> <jsp:param name="attributeName" value="attributeValue"/> <jsp:param … </jsp:include>
其中,relative URL指代被包含文件的相对路径;属性flush为true时,表示实时输出缓冲区。<jsp:param>用于在包含文件时传递一些参数,一个<jsp:include>中可以包含一个或多个<jsp:param>动作元素。
下面通过一个具体的例子来阐述<jsp:include>动作元素的用法。
【例3-13】文件jsp_include.jsp静态包含文件static.html,动态包含文件action.jsp。
jsp_include.jsp代码如下:
其中,方法String request.getParameter("parameterName")以字符串的形式返回客户端传来的某一个请求参数的值,该参数名由parameterName指定。当传递给此方法的参数名没有实际参数与之对应时,返回null。
static.html代码如下:
action.jsp代码如下:
jsp_include.jsp执行时,它所静态包含的文件static.html显示的表单出现在页面的上方,而它动态包含的文件action.jsp出现在页面的下方,实际上包含进来的是action.jsp的执行结果。此时并未提交数据,所以a1和a2都显示为null,程序执行的结果如图3-16所示。当在表单中输入数据并单击login按钮提交后,页面下方的a1和a2显示输入的数据,说明参数传递已经成功,程序执行的结果如图3-17所示。从图中可以看出,action.jsp的内容是动态变化的,它的内容由a1和a2参数决定,而static.html文件的内容是不变的。
图3-16 jsp_include.jsp的执行结果
图3-17 jsp_include.jsp提交数据后的执行结果
如果通过超级链接跳转到action.jsp,页面的执行结果如图3-18所示,因为超级链接中并没有传递参数,所以a1和a2都显示为null。
图3-18 通过超级链接跳转到action.jsp页面的执行结果
由于<jsp:include>也可以包含静态文件,所以文件jsp_include.jsp中的代码<%@ include file="static.html"%>改为<jsp:include page="static.html" flush="true"/>,执行结果是一样的。
如果把【例3-12】中的<%@include%>改为<jsp:include>,则页面不能显示<%=formatter.Format(cal.getTime())%>的计算结果,正说明了两种包含的区别。
注意
• 使用操作元素的单行语句,必须在该元素语句后加上斜线(/)。
• 与使用<%@ include %>的注意事项相同,被包含的文件中不要重复出现某些HTML标记,以免出错。
JSP中include指令与include动作的区别如下:
include指令是指把其他页面的Java代码(源码)加进来,跟本页面的代码合并在一起,相当于把源代码从原页面复制到本页面中来,然后再编译。由于本页面在编译时已经包含了别的文件的源代码,所以以后其他页面更改时,本页面并不理会,因为已经编译过了。
include动作是指两个页面的代码运行完以后,再把包含的那个页面运行后的HTML结果页面,加到本页面运行后的HTML结果页面中来,所以是运行时包含,并且还可以传递参数给被包含的页面。
表3-2列出了include指令与include动作的主要区别。
表3-2 include指令与include动作的主要区别
3.4.2 <jsp:forward>
<jsp:forward>用于在服务器端结束当前页面的执行,并从当前页面跳转到其他指定页面,转向的目标页面可以是静态的HTML页面、JSP文件或Servlet类。这个元素的使用语法和<jsp:include>类似。
<jsp:forward>既可以带参数,也可以不带参数,它们的语法格式分别如下:
<jsp:forward page="pageURL"/>
和
<jsp:forward page="pageURL"> <jsp:param name="attributeName" value="attributeValue"/> <jsp:param … </jsp:forward>
【例3-14】usingForward.jsp重定向到页面forwardTo.jsp,可以很清楚地了解<jsp:forward>操作元素的使用方法与功能。
usingForward.jsp代码如下:
使用<jsp:forward>元素将网页重定向到程序forwardTo.jsp,且不传递任何参数。
forwardTo.jsp代码如下:
执行结果如图3-19所示,其中地址栏显示为usingForward.jsp,但是由于指令<jsp:forward>执行的关系,显示的却是forwardTo.jsp网页的内容,并且指令<jsp:forward>后面的文字“此行代码将不能显示!”没有显示出来。
图3-19 usingForward.jsp执行结果
<jsp:forward>操作典型的使用就是登录,如进行权限验证的页面。当验证通过后,就把页面forword到登录成功页面;当验证不通过时,就把页面forword到登录页面。
【例3-15】login.jsp是用户登录界面,checklogin.jsp是登录验证界面,如果验证成功,它把页面forword到success.jsp页面;如果不成功,它把页面forword到login.jsp页面进行重新验证。
login.jsp代码如下:
checklogin.jsp代码如下:
success.jsp代码如下:
<%@page contentType="text/html;charset=gb2312"%> 登录成功 <br> 欢迎你, <%=request.getParameter("user") %>
login.jsp执行的结果如图3-20所示,输入正确的用户名和密码,单击login按钮提交后,经checklogin.jsp验证,验证成功,它把页面forword到success.jsp页面,如图3-21所示。如果输入错误的用户名和密码,checklogin.jsp把页面forword到login.jsp页面进行重新验证,如图3-22所示。输入的用户名作为参数,通过checklogin.jsp传递给login.jsp和success.jsp。
图3-20 login.jsp执行结果
图3-21 验证成功forword到sucess.jsp的执行结果
图3-22 验证失败forword到login.jsp的执行结果
在页面重定向的过程中,图3-21和图3-22地址栏中的地址并没有发生变化,这样防止用户跳过登录验证页面而直接进入到其他网页。另外,由于地址不变,就不会产生新的request,可以在页面重定向的时候不传递参数,而使用request.getParameter("name"),注意此参数名是name,就是表单中的用户名,程序执行的结果是一样的。读者可以更改程序代码,查看运行结果,体会forword的含义。在4.3.2节,通过forword和sendRedirect的比较,读者将能更加清楚地理解重定向的本质。
3.4.3 <jsp:param>
<jsp:param>元素主要用来传递参数给JSP程序,而由程序取得参数值,在程序中便是一个变量值。此操作元素的语法如下:
<jsp:param name="attributeName" value="attributeValue"/>
<jsp:param>元素在使用时必须要设置其name属性,表示传递参数的名称,并通过value属性来设置该参数的值。JSP操作元素和HTML不同,要设置元素的属性则必须加上双引号,否则执行时会出现错误。
使用<jsp:param>元素来传递参数,在JSP程序中则是以如下的程序代码来取得此参数的值,这与取得用户输入数据的方式相同,是通过使用预设对象request的getParameter()方法来取得<jsp:param>所设置的参数值。
request.getParameter("attributeName ");
<jsp:param>操作元素的使用必须配合<jsp:include>、<jsp:forward>及<jsp:plugin>等元素,在加载外部程序或是网页转换的时候,传递参数给另一个JSP程序。
3.4.4 <jsp:useBean>、<jsp:setProperty>和<jsp:getProperty>动作
1. <jsp:useBean>
<jsp:useBean>用来加载JSP页面中使用的JavaBean,其语法格式如下:
<jsp:useBean id="beanInstanceName" scope="page|request|session|application" class="package.class" ></useBean>
其中,id指定该JavaBean的实例变量的名称,scope指定该Bean变量的有效范围。page指只在当前JSP页面中有效;request指在任何执行相同请求的JSP文件中使用Bean,直到页面执行完毕;session指从创建该Bean开始,在相同session下的JSP页面中可以使用该Bean;application指从创建该Bean开始,在相同application下的JSP页面中可以使用该Bean。class属性指定Bean的类路径和类名,不可接受动态值,不能是抽象的,表3-3说明了这些属性的用法。
表3-3 <jsp:useBean>的属性和用法
注意
包含Bean的类文件应该放到服务器正式存放Java类的目录下,而不是保留给修改后能够自动装载的类的目录。
【例3-16】<jsp:useBean>动作实例useBean.jsp代码如下:
useBean.jsp运行结果如图3-23所示。
图3-23 useBean.jsp运行结果
<jsp:useBean>的bean属性用于指定Bean的名字,可以接受动态值。beanName属性必须与type属性结合使用,不能与Class属性同时使用。
【例3-17】<jsp:useBean>动作实例useBeanBeanName.jsp代码如下:
useBeanBeanName.jsp运行结果如图3-24所示。
图3-24 useBeanBeanName.jsp运行结果
2. <jsp:setProperty>
<jsp:setProperty>用于设置Bean的属性值。语法格式如下:
<jsp:setProperty>动作用来设置已经实例化的Bean对象的属性,它有以下两种用法。
(1)可以在<jsp:useBean>元素的外面(后面)使用<jsp:setProperty>。
<jsp:useBean id="myName" ... /> ... <jsp:setProperty name="myName" property="someProperty" ... />
此时,不管<jsp:useBean>是找到了一个现有的Bean,还是新创建了一个Bean实例,<jsp:setProperty>都会执行。
(2)把<jsp:setProperty>放入<jsp:useBean>元素的内部。
<jsp:useBean id="myName" ... > ... <jsp:setProperty name="myName" property="someProperty" ... /> </jsp:useBean>
此时,<jsp:setProperty>只有在新建Bean实例时才会执行,如果使用现有实例,则不执行<jsp:setProperty>。
<jsp:setProperty>动作有4个属性,这4个属性及其用法如表3-4所示。
表3-4 <jsp:setProperty>的属性和用法
<jsp:setProperty>元素使用Bean给定的set方法,在Bean中设置一个或多个属性值。在使用这个元素之前必须首先使用<jsp:setProperty>声明此Bean。因为<jsp:useBean>和<jsp:setProperty>是联系在一起的,同时使用Bean实例的名字也应当相匹配。就是说,在<jsp:setProperty>中的name值应当和<jsp:useBean>中的id值相同,且大小写敏感。
可以使用以下方法来设定<jsp:setProperty>属性值:
通过用户输入的所有值(被作为参数存储在request对象中)来匹配Bean中的属性。
通过用户输入的指定值来匹配Bean中指定的属性。
在运行时使用一个表达式来匹配Bean的属性。
每一种设定属性值的方法都有其特定的语法,使用时应注意以下几个方面:
在Bean中的属性名字必须和request对象中的参数名一致。
如果request对象的参数值中有空值,那么对应的Bean属性将不会设定任何值。同样,如果Bean中有一个属性没有与之对应的request参数值,那么这个属性同样也不会设定。
如果Bean属性和request参数的名字不同,那么用户就必须得指定property和param,如果它们同名,那么只需要指明property即可。
如果参数值为空(或未初始化),则对应的Bean属性不用被设定。
如果用户使用了property="*",那么Bean的属性没有必要按HTML表单中的顺序排序,只要名称正确就可以了。
【例3-18】<jsp:setProperty>的属性和用法,useBeanParam.jsp代码如下:
useBeanParam.jsp运行结果如图3-25所示。
图3-25 useBeanParam.jsp运行结果
3. <jsp:getProperty>
使用<jsp:getProperty>可获取Bean的属性值,并在页面中显示。其语法格式如下:
<jsp:getProperty name="beanInstanceName" property= "propertyName" />
<jsp:getProperty>语法属性的含义如下。
(1)name="beanInstanceName"
Bean的名字由<jsp:useBean>指定。
(2)property="propertyName"
指定Bean的属性名,例如:
<jsp:useBean id="calendar" scope="page" class="employee.Calendar" /> <jsp:getProperty name="calendar" property="username" />
<jsp:getProperty>元素可以获得Bean的属性值,并可以将其使用或显示在JSP页面中。在使用<jsp:getProperty>之前,必须有由<jsp:useBean>所创建的Bean对象。
使用<jsp:getProperty>元素时注意以下限制:首先不能使用<jsp:getProperty>来检索一个已经被索引了的属性;其次,能够和JavaBean组件一起使用<jsp:getProperty>,但是不能与Enterprise Bean(企业级Bean)一起使用。
在Sun公司的JSP参考中提到,如果使用<jsp:getProperty>来检索的值是空值,那么将会产生NullPointerException;如果使用程序段或表达式来检索值,那么在浏览器上出现的将是null(空值)。
【例3-19】通过一个用户注册的例子来具体介绍这三个动作元素的使用方法,因为使用之前先要创建一个JavaBean,在ch03项目中建立一个名为TestBean的Java类(关于JavaBean的概念及具体的创建方法,会在第6章详细介绍)。
TestBean.java代码如下:
从面向对象角度来看,这个TestBean类代表了用户,它具有用户名、用户密码、年龄等属性。这个JavaBean的方法都是setProperty()和getProperty()类型的,主要用来配合JSP页面中的<jsp:setProperty>和<jsp:getProperty>动作元素。这些方法在Eclipse开发环境中可以自动生成,不需要一个一个写出来,具体方法在后面章节中会介绍。创建这个类的实例可以代表一个一个不同的用户。
用户登录文件register.html的代码如下:
register.jsp显示注册成功的用户的提交信息,代码如下:
register.jsp文件使用<jsp:useBean>、<jsp:setProperty>和<jsp:getProperty>这3个动作元素来处理用户填写的信息,并将结果显示在页面上。
程序register.html执行结果如图3-26所示,输入注册信息并提交。成功后,注册信息通过register.jsp页面显示出来,如图3-27所示。
图3-26 register.html的执行结果
图3-27 register.jsp的执行结果
在本例中,register.jsp中的代码<jsp:useBean id="user" scope="page" class="ch03.TestBean" />指定在本页面中使用JavaBean,此JavaBean的类为ch03.TestBean,id为user。
在register.html中表单的参数名和TestBean.java中的属性名完全一样,所以在register.jsp中可以通过<jsp:setProperty name="user" property="*" />把用户从表单提交的数据传递给TestBean的对象user。
在register.jsp中,可以通过user.getUserName()方法获得用户名信息,也可以通过<jsp:getProperty name="user" property="userName" />获得JavaBean的属性,两种方法的执行结果是一样的。
为了理解<jsp:getProperty>的使用,并演示form参数和JavaBean属性的关系,把【例3-19】做以下两种更改。
(1)把register.html中表单参数userName改为xingming(即和JavaBean的属性名不一致),修改后的代码如下:
<td>姓名:<input name="xingming" type="text"></td>
其他代码保持不变,把它保存为register2.html。重新执行程序,可以看到,由于表单参数xingming和Bean属性名不一致,使用<jsp:setProperty name="user" property="*" />指令为JavaBean设置属性时并没有设置xingming属性,所以造成user.getUserName()方法返回空的结果。程序执行结果如图3-28所示。
图3-28 测试form参数和Bean属性不一致的执行结果
此时需要更改register.jsp,代码如下:
<jsp:setProperty name="user" property="userName" param="xingming"/> <jsp:setProperty name="user" property="*" />
而其他的两个属性没有任何变化,所以依然用<jsp:setProperty name="user" property="*" />即可。把更改过的文件保存为register2.jsp,然后register2.html把信息提交给register2.jsp处理。
<form method="get" action="register2.jsp">
再次执行程序,输入一些信息并提交,这次可以把form的参数和Bean的属性进行重新映射,程序执行结果如图3-29所示。
图3-29 测试form参数和Bean属性一致的执行结果
(2)把register2.jsp中的
<jsp:setProperty name="user" property="userName" param="xingming"/>
改为
<jsp:setProperty name="user" property="userName" value="xingming"/>
重新执行程序,输入数据并提交,可以看出,不管在表单中输入的用户名是什么,在执行register.jsp后,用户名信息都是xingming。程序执行结果如图3-30所示。
图3-30 测试value属性的执行结果
通过上面的两个实例,读者应该能够理解param和value标记的作用了。
需要注意的是,<jsp:setProperty>元素使用Bean给定的set()方法,在Bean中设置一个或多个属性值,是按照设置的先后顺序来确定的,再把【例3-19】做以下两种更改。
(1)register.html保持不变,此时需要更改register.jsp,代码如下:
<jsp:setProperty name="user" property="age" value="30"/> <jsp:setProperty name="user" property="*" />
把更改过的文件保存为register3.jsp。然后register.html把信息提交给register3.jsp处理。
<form method="get" action="register3.jsp">
再次执行程序,输入一些信息并提交。注意,此次填写年龄为25,form的参数和Bean的属性进行重新映射。程序执行结果如图3-31所示。
图3-31 测试属性先后设置的执行结果
(2)register.html保持不变,把register3.jsp的两行代码顺序交换,代码如下:
<jsp:setProperty name="user" property="*" /> <jsp:setProperty name="user" property="age" value="30"/>
把更改过的文件保存为register4.jsp,然后register.html把信息提交给register4.jsp处理。
<form method="get" action="register4.jsp">
再次执行程序,输入一些信息并提交。注意,此次填写年龄仍然为25,form的参数和Bean的属性进行重新映射。程序执行结果如图3-32所示。比较这两次程序执行的结果发现,年龄的值第一次是从表单提交得来的数据,而第二次是固定值30,这与set方法设置的先后顺序有关。
图3-32 代码顺序交换后的执行结果
3.4.5 <jsp:plugin>
<jsp:plugin>操作元素的功能在于从JSP网页中加载Java Applet或JavaBean程序组件,与HTML的<Applet>与<Object>标签有着类似的功能。这个元素有许多属性设置,以下是此元素的使用语法。
<jsp:plugin type="bean|applet" code="classFileName" codebase="classFileDirectoryName" name="instanceName" align="left|right|top|middle|bottom" width="width" height="height" hspace="horizontalSpace" vspace="verticalSpace" archive="archiveURL,…" > <jsp:params> <jsp:param name="propertyName" value="propertyValue"/> … </jsp:params> <jsp:fallback>text message</jsp:fallback> </jsp:plugin>
<jsp:plugin>元素的属性如表3-5所示。
表3-5 <jsp:plugin>元素属性
【例3-20】演示<jsp:plugin>元素的用法。使用<jsp:plugin>加载两个Java Applet程序,其中一个Applet程序将指定的图片显示在窗口中,另一个Applet程序则会取得几个<jsp:param>所设置的参数,并将参数的内容输出到窗口中。
showmsg.java代码如下:
为了演示<jsp:plugin>,设计一个名称为howmsg的applet,主要是用来取得JSP网页中所设置的各个参数:msg1、msg2及msg3。然后将这些参数的内容显示在该Applet在网页中所显示的区域中。
usingPlugin.jsp代码如下:
程序代码引用<jsp:plugin>,将上述程序showmsg.java编译的Applet组件showmsg.class加载至网页当中,<jsp:plugin type = "applet" code = "ch03/showmsg.class" height = "200" width = "200">表示在JSP页面中插入Applet类型的小程序,该小程序的字节码文件"ch03/showmsg.class"存放在与JSP页面相同的目录下,小程序在浏览器的显示为高200像素,宽200像素大小。<jsp:params>语句依次设置每个要传递给Applet程序的参数,分别是3个程序语言的名称,其执行结果如图3-33所示。
图3-33 usingPlugin.jsp执行结果