<html:html>
<html:html>标记可以说是Struts所有标记中最简单的了。它简单的在页面开始处和结尾处产生一个的标记。在Struts1.1以前的版本中,该标记有一个locale属性。如下所示:
<html:html locale="true">
该属性的作用是读取用户session中的locale属性并显示出来。比如用户使用的是zh-CN,那么,生成的页面代码将如下所示:
<html locale="zh-CN">
不过,从Struts1.2开始,该属性被lang所取代。原因是locale属性当其值为true时,会读取session中的locale信息。但是当HttpSession不存在时,它会强制创建一个新的session并将HTTP请求中的locale信息放入session中去。这种方式时显并不合理,因此,从Struts1.2开始,locale属性被lang属性所取代
<html:html lang="true">
当使用lang属性后,若没有session对象时,就根据Http请求中的locale信息来输出相应的语言信息。
<html:base>
<html:base>用于在网页的head部分生成一个base标记。它的用法很简单,只需在head部分加入如下标记就可以了
<html:base/>
当经过Web容器编译后,会生成如下的一段标记。
<base href="">
这也就是本网页的实际的URL地址。请记住,base标记将不会被显式的显示在网页上,只有通过查看生成的 html源代码才可以看得见。其实,base标记的含义不仅是生成本网页的URL,它更重要的功能是为该页面内的所有其它链接提供相对的位置。例如,在本网页使用了<html:base>标记后,生成了如上的URL地址。倘若此时需要指定一张图片,只须使用相对的位置链接就可以了。假设在taglib1的根目录下有一个image目录,里面有一张叫image.gif的图片,则引用的代码如下所示:
<img src="image/image.gif">
这张图片的实际URL就是:
<html:link>
<html:link>标记是用来生成HTML中的<a>标记的,它带有多种参数,可以和Struts框架结合生成多种不同形式的链接。
1.外部完整URL链接
<html:link>标记最简单的用法就是直接链到一个外部的完整URL链接,比如用户需要创建一个到新浪网的链接。可以使用href属性,代码如下:
<html:link href=""> 新浪网</html:link>
以上代码经编译后会生成如下html代码:
<a href="">新浪网</a>
2.相对URL链接
当需要从同一个应用中的某个网页链接到另一个网页时,可以使用page属性,代码如下:
<html:link page="/index.jsp"> 首页</html:link>
当需要向所链接的页面传输某些参数时,可以将参数直接加在请求的尾部就可以了。例如,下面的代码示例将向测试页面传递一个字符串参数和一个整型参数:
<html:link page="/test.do?testString=a+new+string&testInt=10000"> 测试页面</html:link>
由它生成的页面html代码如下所示:
<a href="/taglib1/test.do?testString=a+new+string&testInt=10000"> 测试页面</a>
下面的链接是一个测试,它向测试页面传递两个参数,一个是testString,它的值为"a new string",另一个是testInt,它的值为10000。
3.全局转发URL链接
在Struts的struts-config.xml文件中定义了<global-forward>全局转发变量,可以通过<html:link> 来链接到这种全局转发的URL链接,使用forward属性,示例代码如下所示:
<html:link forward="index"> 回到主页</html:link>
生成的页面html代码如下所示:
<a href="/taglib1/index.jsp"> 回到主页</a>
4.带有页面变量的URL链接
在创建链接时常常需要访问一些页面的变量,将它们的值作为参数传递给将要链到的网页。<html:link>标记也提供了这样的功能。
如果仅需传递单个参数,可以使用paramID与paramName这两个属性。以下为代码示例
<% String test1 = "testABC"; request.setAttribute("stringtest",test1);%><html:link page="/test.do" paramId="testString" paramName="stringtest"> 测试页面</html:link>
在这段程序中,首先定义一个变量为test1它的值为testABC。然后将它存入request对象中,命名为stringtest。接着,使用<html:link>标记的paramName属性指定欲从内建对象中读取值的变量名,此处也就是stringtest。然后,使用paramId属性指定传值的目标参数,此处为testString。点击下面的链接可以通过测试页面查看运行效果:
如果需要传递的参数有多个,则可使用<html:link>标记的name属性来实现,name属性的值是一个 java.util.HashMap类型的对象名称,它的每一个"键/值"对就代表一对的"参数名/参数值",以下为代码示例:
<% HashMap para_map = new HashMap(); para_map.put("testString","testABC"); para_map.put("testInt",new Integer(10000)); request.setAttribute("map1",para_map);%><html:link page="/test.do" name="map1">测试页面</html:link>
在上面的代码中,首先在页面上声明一个HashMap类型的变量para_map用来存储将要传递的参数,接着,向 para_map中存入两个对象。然后再将该对象存入页面的request对象中。使用<html:link>标记的name属性来将参数带入目标页面中。实际生成的html代码如下所示:
<a href="/taglib1/test.do?testString=testABC&testInt=10000">测试页面</a>
<html:rewrite>
<html:rewrite>标记是用来输出链接中的URI的。所谓URI就是指一个完整URL地址去掉协议,主机地址和端口号以后的部分。它的众多属性都和<html:link>一样,只是它输出的仅是一个URI字符串,而非链接。示例代码如下:
<html:rewrite page="/test.do?testString=testABC"/>
它生成的html如下:
/struts/test.do?testString=testABC
可以看出,它输出的内容只是实际URL中除去协议,主机地址和端口号以后的部分。实际的URL应为:
它也可以使用paramId和paramName等属性,如下面的例子:
<% String str = "testABC"; request.setAttribute("test1",str);%><html:rewrite page="/test.do" paramId="testString" paramName="test1" />
实际生成的html代码如下所示:
/struts/test.do?testString=testABC
下面的例子将演示当有多个参数要传递时<html:rewrite>生成的URI样式。它与<html:link> 一样,都使用name属性来传递多个参数。
<% HashMap para_map = new HashMap(); para_map.put("testString","testABC"); para_map.put("testInt",new Integer(10000)); request.setAttribute("map1",para_map);%><html:rewrite page="/test.do" name="map1"/>
实际生成的html代码如下所示:
/struts/test.do?testString=testABC&testInt=10000
这里有一点需要注意的,当从网页源代码上看生成的多参数链接时,在多个参数间连接符并不是简单的& 而是一个&,在html代码中它就代表&。
<html:img>
<html:img>标记是用来显示图片的,它的用法很简单,如下所示:
<html:img page="/a.jpg"/>
此处值得注意的一点是,在page属性后图片的路径并没有因为设定了<html:base>而使用了相对路径,而是依然使用了绝对路径。如果使用非Struts的<img src="a.jpg">标记则可以正确显示图片。
<html:form>
<html:form>标记生成页面表单,这个由Struts标记生成的表单和普通的HTML表单略有不同。普通的表单用法如下所示:
<form method="post" action="/loginServlet">
<input type="text" name="username"> <input type="text" name="username"></form>可以看到,在普通的form标记后的action属性的值是一个Servlet(当然也可以是一个JSP文件),而使用了<html:form> 标记后,代码则变成了下面的样子:
<html:form action="/test.do">
其中action属性后跟的是一个在struts-config.xml文件中定义的Action,而这个Action也必定要对应一个ActionForm才能完成其应有的功能。所以,对每个<html:form>标记来说,都该对应一个ActionForm。而这个ActionForm中的属性值也将和网页上的<html:form>表单中的各个表单项相对应。这些表单相将会是类似于<html:text>的一些表单元素。下面有一段示例代码:
<html:form action="/test.do">
输入字符串testString:<html:text property="testString"/> 提交:<html:submit property="submit"/></html:form>这段代码将在页面上显示一个文本框和一个提交按钮,当用户在文本框中输入一个字符串后并点击按钮,将会触发test这个Action。在初始化这个JSP页面时,JSP引擎在初始化<html:form>标记时将会初始化test这个Action所对应的ActionForm,当用户提交表单时,表单项中的testString刚好对应ActionForm中的这一项(只需名称相同)。
此处值得注意的一点是,在<html:form>表单中的各个表单项一定要在ActionForm可以找到一个对应的项,这样才能在提交的时候进行赋值,否则,Struts将会报一个错,显示无法找到某表单项在ActionForm的对应get方法
<html:text>
<html:text>标记比较简单,是用来在页面上生成一个文本框,该标记通常被用在一个<html:form>中。以下是一段示例代码:
<html:form action="/test.do">
输入字符串testString:<html:text property="testString"/> 输入整数testInt:<html:text property="testInt"/> <html:submit property="submit" value="submit"/></html:form>通常,<html:text property="testString"/>语句将生成以下的html代码:
<input type="text" name="testString">
可以看到,<html:text>标记的property属性指定了文本框的名称,如果它位于<html:form>表单内部,那么, property的值若刚好与ActionForm中的一项对应时,该文本框内的值就将被赋给该ActionForm中的该项。以test这个Action所对应的ActionForm为例,它其中就有这么一段代码刚好与上面的<html:text>相对应:
private String testString = null;
public void setTestString(String testString){ this.testString = testString;}public String getTestString(){ return testString;}从上面的代码可以看出用户在提交表单后,Struts会自动将property="testString"的<html:text>文本框的值赋给 ActionForm中的testString字段。
<html:password>
<html:password>用来在页面上产生一个密码框。所谓密码框其实就是一个文本框,只不过对它的任何输入都将显示为"*"。它的用法和<html:text>差不多,property属性用来表示它的名称。
<html:form action="/test.do">
<html:password property="testString"/> <html:submit property="submit" value="查看测试页面"/></html:form>上面的代码中将一个<html:password>标记放在一个表单中,这也是必须的,否则Struts框架会报错。以下是上面代码的运行效果,无论用户输入什么,都只会显示"*"。点击提交钮后,会在测试页面看到用户输入的内容。
<html:textarea>标记和&html:textarea基本相同,只不过它会产生一个更大的文本输入域。同样的,它也需要存在于一个<html:form>表单中,下面是示例代码:
<html:form action="/test.do">
<html:textarea property="testString" rows="8"/> <html:submit property="submit" value="查看测试页面"/></html:form><html:hidden>
<html:hidden>标记用于在网页上生成一个隐藏的字段。众所周知,网页上总有一些信息不希望被用户看到,但在提交的时候却需要传递到服务器上以帮助业务逻辑进行处理。在传统的html中,隐藏字段是用下面的方式表示的:
<input type="hidden" name="testString" value="hiddenString">
<html:hidden>标记不需要被限定在一个表单的内部来使用,以下的例子还是将它放在一个表单的内部。当用户点击 "查看测试页面"的按钮时,会看到测试页面中testString被赋与了"hiddenString"的值。
在<html:hidden>标记中有一个write属性,可以决定在页面上是否显示出这个隐藏的值,如下面的代码:
<html:hidden property="testString" value="hiddenString" write="true"/>
运行效果如下所示,虽然只有短短的一个字符串,但可以看出标记还是把testString的value打印出来了。
hiddenString
<html:submit>
<html:submit>标记生成一个提交按钮,用于提交表单。它的用法很简单,如下所示:
<html:submit property="submit" value="提交"/>
它会生成如下的html代码
<input type="submit" name="submit" value="提交">
另外,<html:submit>标记还可以写成如下的形式,它也将生成同样的html代码。
<html:submit>提交</html:submit>
<html:reset>
<html:reset>标记生成一个复位按钮,用于复位表单内的各项元素。代码如下:
<html:form action="/test.do">
<html:text property="testString"/><html:submit property="submit" value="Submit"/><html:reset property="reset" value="reset"/></html:form>
<html:cancel>
<html:cancel>标记将在网页上生成一个"取消"按钮,用户可以通过点击它触发一个取消事件。这个取消事件通常是在用户已经点击了"提交"按钮后,又临时想取消这次提交时生成的。因此,"取消"按钮并不只是简单的页面效果,而要深入后台,其实也就是调用一个Action来对用户的提交进行处理,做一些清除的工作。<html:cancel>按钮要使用在一个表单内部,可以用以下两种方式来使用该标记:
<html:cancel>Cancel</html:cancel>
或<html:cancel property="org.apache.struts.taglib.html.CANCEL" value="Cancel"/><br>
上面的代码生成的html代码如下所示:
<input type="submit" name="org.apache.struts.taglib.html.CANCEL" value="Cancel" οnclick="bCancel=true;">
可以看到,在生成的html标记最后有一个οnclick="bCancel=true;",这个onclick动作是在用户点击取消按钮时发生的,其实也就是运行一个javascript脚本,它给一个名为bCancel的变量赋值为true。为什么要这样呢?先看看以下代码,这是一段在用户点击cancel后执行的程序,其实它就是位于和提交表单后所执行的相同的Action内。因为cancel动作和submit动作在生成html代码后的类型都是一样的,都为"submit"。这一点从上面的介绍中可以看到。
......
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception{ ..... if (isCancelled(request)){ return mapping.findForward("cancelled"); } ......}这其中有一个isCancelled(),该函数的作用就是从request对象中取出bCancel变量,并且判断其是否为真,若为真则转发到相应的Action去处理,则不为真,则说明是普通的提交动作,继续下面的代码。这个isCancelled()方法被定义在Action 类中,其代码如下:
protected boolean isCancelled(HttpServletRequest request) {
return (request.getAttribute(Globals.CANCEL_KEY) != null);}这个Globals.CANCEL_KEY的值就是cancel按钮的name属性,也就是org.apache.struts.taglib.html.CANCEL
<html:checkbox>
<html:checkbox>生成网页上的选择框,它必须存在于一个表单范围内,因此也就说明在ActionForm必须使用一个字段来接收从表单传过来的值。一般情况下,在ActionForm中都使用布尔型变量来表示一个checkbox,这是因为它要么没被选中,要么就是被选中。以下是一段示例代码:
<html:form action="/test.do">
checkbox1:<html:checkbox property="checkbox1"/>checkbox2:<html:checkbox property="checkbox2"/><html:submit property="submit" value="测试"/> </html:form>这样一段代码生成的html如下所示:
<form name="testbean2" method="post" action="/taglib1/test.do">
checkbox1:<input type="checkbox" name="checkbox1" value="on">checkbox2:<input type="checkbox" name="checkbox2" value="on"><input type="submit" name="submit" value="测试"></form>可以看到,checkbox的value为on,这一点需要特别注意。当某个checkbox被选中时,使用checked属性来表示,代码如下:
<input type="checkbox" name="checkbox1" value="on" checked="checked">
另外,有一点需要特别注意。为了让checkbox能够正确的显示,应当在ActionForm的reset()方法中对其进行复位。也就是在ActionForm的reset()方法中加入如下代码:
public void reset(ActionMapping mapping, HttpServletRequest request){
this.checkbox1 = false; this.checkbox2 = false;}如果不对checkbox进行复位,那么一个checkbox一旦被选中,就会永远处于被选中的状态。发生这种情况的原因是,在html中浏览器不会向Web服务器发送一个类似于"某某选择框没有被选中"这样的信息,因此,当一个checkbox被选中后,即便下一次用户将它的勾去掉,Web服务器端也将认为它是被选中的。
运行效果如下所示:
checkbox1:
checkbox2:<html:multibox>
<html:multibox>标签生成网页上的复选框,其实它的功能和<html:checkbox>一样,所不同的是,在此复选框所在的ActionForm中使用一个数组来表示该复选框。先看看以下网页代码:
<html:form action="/test.do"> <html:multibox property="testStringArray" value="China"/>中国
<html:multibox property="testStringArray" value="USA"/>美国<html:multibox property="testStringArray" value="England"/>英国<html:multibox property="testStringArray" value="Germany"/>德国<html:multibox property="testStringArray" value="France"/>法国</html:form>当用户选中其中的几项并点击提交后,ActionForm中的testStringArray数组就会被赋上相应的值。这里有一点值得注意,例如用户选择了"中国"和"英国"两项,ActionForm中testStringArray的值就会是{"中国","英国"}。
中国美国英国德国法国
<html:radio>
<html:radio>标记生成一个单选框,示例代码如下:
<html:form action="/test.do">
<html:radio property="testRadio" value="testvalue1"/></html:form>它有一个value属性,用来指定当选中该单选框时ActionForm中对应的属性的值。下面是另一种单选框的用法:
<html:form action="/test.do">
<html:radio property="testRadio" value="value1">Choice1<html:radio property="testRadio" value="value2">Choice2<html:radio property="testRadio" value="value3">Choice3</html:form>在上面的代码中,单选框一共有三个,这三个单选框组成一个单选框组,只能选取其中一个。无论选中哪一个,它的值在提交表单后都将赋给ActionForm中相对应的属性,如果三个单选框一个都没有选中,那么该属性的值将为一个空串。
运行效果如下所示:
Choice1Choice2Choice3
<html:select>
<html:select>用来在网页上产生选择列表。通常它与<html:option>等选项标记连用。示例代码如下:
<html:select property="testString" size="1"> <html:option value="value1">Show Value1</html:option> <html:option value="value2">Show Value2</html:option> <html:option value="value3">Show Value3</html:option> <:html:submit property="submit" value="提交"/> </html:select>
其中,property表示该选择列表与ActionForm中对应的属性名。当用户点击提交后,会在测试页面看到用户所选中的选项的值。以下是代码的运行效果:
Show Value1 Show Value2 Show Value3
<html:select>有一个size属性,它表示同时显示的选项的数目,如上例中的size为1,则只同时显示一个选项。还有一个multiple属性,当其为true时,该选择列表就允许多选。用户可以通过鼠标的拖动,或是按住Ctrl键进行多选。
以下是multiple="true"和size="8"例子
value1 value2 value3 value4 value5 value6 value7 value8 value9 value10
当multiple属性为true时,在ActionForm中对应的属性应是一个数组类型以便同时向其赋上用户选中的多个值。
<html:option>
<html:option>标记是<html:select>标记的选项,每个<html:option>将在选择框中代表一个选项。有如下代码所示:
<html:select property="testString" size="1"> <html:option value="value1">Show Value1</html:option> <html:option value="value2">Show Value2</html:option> <html:option value="value3">Show Value3</html:option></html:select>
一个选项有两部分重要的内容。第一就是它所显示给用户的内容,这可以通过以下方式来指定:
<html:option value="value1">Show Value1</html:option>
可以看出,使用两个<html:option>间的部分来表示用户所见到的内容。当然,也可以使用<html:option> 所带的key和bundle等属性用来指定所在资源文件中的内容,以此来表示用户所见到的内容。其中,bundle和key属性的用法请参看"配置文件"相关章节。
另一个重要的内容就是它所传递给ActionForm的值。这是由标记的value属性指定的。如上面的例子中,value的值分别为 value1,value2和value3,当用户选中某个标记时,JSP页面就会将该标记所对应的value传给ActionForm中相应的属性。
以下是运行效果:
Show Value1 Show Value2 Show Value3
<html:options>
<html:options>标记用来表示一组选择项,也就是相当于一组的<html:option>标记。在一个 <html:select>标记中可以包含多个<html:options>标记。以下是一段代码示例:
<% ArrayList list = new ArrayList(); list.add(new org.apache.struts.util.LabelValueBean("Show value1","value1")); list.add(new org.apache.struts.util.LabelValueBean("Show value2","value2")); list.add(new org.apache.struts.util.LabelValueBean("Show value3","value3")); list.add(new org.apache.struts.util.LabelValueBean("Show value4","value4")); pageContext.setAttribute("valuelist",list);%><html:form action="/test.do"> <html:select property="testString"> <html:options collection="valueslist" property="value" labelProperty="label"/> </html:select></html:form>
这是一段<html:options>标记的应用方式。首先,页面创建一个ArrayList型的对象list,以此作为存放所有选项的容器。接下来,将四个org.apache.struts.util.LabelValueBean类型的对象放入list中,在初始化这四个LabelValueBean对象时,对每个对象的构造函数传入两个字符型参数。第一个参数将赋给LabelValueBean对象中的label变量,这个变量的值将成为页面选项中用户所见到的部分;第二个参数将赋给LabelValueBean对象中的value变量,该变量的值就是用户在选择页面中这个选项后传递给后台ActionForm的值,也就是<html:option>标记中value属性的值。
在四个对象都存入list对象后,程序把list对象放入pageContext中。这样做的目的是为了让<html:options>标记来引用它。<html:options>标记有一个collection属性,它可以在页面上下文pageContext中指定一个实现了List接口的对象,然后将该对象列表中所有存储的对象遍历,取出每一个对象相应的属性值,用来作为页面选项(也就是每一个option)的value和label。如在本例中,collection属性首先指定了从pageContext中取出valuelist对象,由于valuelist对象中存储的是一个 org.apache.struts.util.LabelValueBean类型的对象列表,所以,<:html:options>标记会将每个对象取出,用 org.apache.struts.util.LabelValueBean对象中的value属性值赋给标记的property属性,再用对象中的label属性值赋给标记的 labelProperty属性。这样就将存储在valuelist中的对象和页面上的每一个选项建立起了一一对应的关系,<:html:options> 的功能也就实现了。
以下是代码实际运行效果:
Show value1 Show value2 Show value3 Show value4
<html:optionsCollection>
<html:optionsCollection>标记用来表示一组选择项,与<html:options>所不同的是,它不从pageContext中取出对象,而是从与表单相关联的ActionForm中取出同名的数组,并将该数组中的各个对象当作选项表示出来。先看以下ActionForm中的代码片断:
private TestPageBean [] pagebean = new TestPageBean[4];public TestBean2 (){ super(); for (int i=0;i<4;i++){ pagebean[i]=new TestPageBean("name" + i,"value" + i); }}
在ActionForm中,定义一个叫做pagebean的数组对象,它的类型是TestPageBean,这个Bean只有两个属性,value和label。接下来,在ActionForm调用构造函数进行初始化时将这个pagebean数组对象进行初始化,存入四个TestPageBean类型的对象。这四个对象的value和label分别从value1到value4以及name1到name4。以下是TestPageBean的代码:
public class TestPageBean { private String name = ""; private String value = ""; public TestPageBean(String n, String v){ name = n; value = v; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getValue() { return value; } public void setValue(String value) { this.value = value; }}
以下是<html:optionsCollection>的使用方法:
<html:form action="/test.do"> <html:select property="testString" size="1"> <html:optionsCollection property="pagebean" label="name" value="value"/> </html:select> <html:submit property="submit" value="submit" /></html:form>
可以从代码中看到,<html:optionsCollection>标记使用property属性来指定ActionForm的数组属性,用label属性来指定数组元素对象中用于代表选项页面显示的值,而用value属性来指定数组元素对象中用于代表选项被选中后传入ActionForm 的值。
以下是以上代码的运行效果,若用户选择了name1则可在测试页面上看到与其对应的value1。
name0 name1 name2 name3
<html:file>
<html:file>标签用于上传文件。上传文件指的是从客户端将文件上传到服务器上,这一过程和通过表单提交请求到服务器端并没有本质上的不同。在这一过程中有以下两点需要注意:
1. 文件存储于客户端的机器上,因此在服务器端不能使用获得文件路径的方式来获取文件对象。
2. 由于使用GET方式提交表单时,可提交的串长度受到限制,所以,在上传文件时必须使用POST方式。
文件上传是一项从页面开始的工作,下面首先看一下页面上的代码:
<html:form action="/upload.do" enctype="multipart/form-data"><html:file property="file" /><html:submit property="submit" value="submit"/></html:form>您上传的文件是:<bean:write name="upload" property="filename"/>它的大小为:<bean:write name="upload" property="size"/>
上面的代码中使用了<html:file>标记来进行文件的上传。前面已经说过,上传过程实际上和通过表单提交请求到服务器没有不同,因此,该标记也必须存在于一个表单中。这个表单所进行的操作是/upload.do。通过查找struts-config.xml可以知道,该表单类型应为org.apache.struts.webapp.exercise.UploadBean,以下是它的代码:
public class UploadBean extends ActionForm{ private FormFile file = null; private String filename = ""; private String size = ""; public UploadBean(){ } public FormFile getFile() { return file; } public void setFile(FormFile file) { this.file = file; } public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public String getSize() { return size; } public void setSize(String size) { this.size = size; }}
在上面的代码中,定义了一个FormFile类型的对象file。这个FormFile类是Struts提供的专门用于文件上传的类。在这个ActionForm 中,FormFile类的对象file的名称与网页上<html:file>标记的property属性相对应,这一点非常重要!
用户点击上传按钮后执行的是upload的操作,这个操作与后台的UploadAction关联。以下是UploadAction的代码:
public class UploadAction extends Action { public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception { UploadBean filebean = (UploadBean) form; FormFile file = filebean.getFile(); if (file == null){ return mapping.findForward("input"); } String filename = file.getFileName(); filebean.setFilename(filename); String size = Integer.toString(file.getFileSize()) + "bytes"; filebean.setSize(size); InputStream is = file.getInputStream(); String store_path = servlet.getServletContext().getRealPath("/fileupload"); System.out.println(store_path); OutputStream os = new FileOutputStream(store_path + "/" + filename); int bytes = 0; byte [] buffer = new byte[8192]; while ((bytes = is.read(buffer,0,8192))!=-1){ os.write(buffer,0,bytes); } os.close(); is.close(); file.destroy(); return mapping.findForward("input"); }}
上面的代码首先从表单ActionForm中获取FormFile对象,然后创建输入流读取文件内容,再创建一个输出流,将上传的文件保存到工程目录下的fileupload目录中。最后关闭输出流和输入流,并将与客户端的文件连接断开。整个过程非常清楚,简单。其中,有两句代码分别将文件名和文件大小保存到UploadBean中去,这是为了在JSP页面上可以显示出文件名和文件大小。在上面的页面代码中可以看到这样两句:
您上传的文件是:<bean:write name="upload" property="filename"/>它的大小为:<bean:write name="upload" property="size"/>
这里使用了Struts Bean标记库的标签来显示与页面相关的ActionForm的变量值。
以下是程序的运行效果,用户可以在/tablig/fileupload目录下看到上传的文件。
<html:errors>
在Struts 1.1中该标签的使用方法
<html:errors>标签用来在网页上输出错误消息。以下是一段实际运行效果,当用户选中下面的选择框后并提交表单时,页面上就会显示错误消息,而当用户不选中直接点击时,会出现不同的错误消息。
选择框:
这里使用到的代码如下所示:
<html:form action="/testerr.do">选择框:<html:checkbox property="checkbox1"/><html:submit/></html:form><html:errors bundle="error"/>
错误信息是通过什么方式添加的呢,<html:errors>标记又是通过什么方式将错误信息显示出来的呢?在前面的章节中曾提到过ActionForm中的validate()方法,它的作用是检验用户的输入,当用户的输入不符合某种条件时,就返回一个 ActionErrors对象,倘若返回的对象不为空,Struts框架就会将请求发回页面。此时,倘若页面上有相应的显示错误的标记,就会将在validate()方法中所添加的错误显示出来。
另外,除了在ActionForm的validate()方法中可以添加ActionErrors外,在Action中也可以添加。通过查看struts-config.xml文件可以知道,与这个表单相关联的ActionForm和Action分别是ErrBean和ErrAction。以下先看看ErrBean的代码:
public class ErrBean extends ActionForm{ private boolean checkbox1; public boolean isCheckbox1() { return checkbox1; } public void setCheckbox1(boolean checkbox1) { this.checkbox1 = checkbox1; } public void reset(ActionMapping mapping, HttpServletRequest request){ this.setCheckbox1(false); } public ActionErrors validate(ActionMapping mapping, HttpServletRequest request){ ActionErrors errors = new ActionErrors(); if (checkbox1){ errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError("html.errors.error1")); errors.add("checkbox1",new ActionError("html.errors.error2")); } return errors; }}
在<html:checkbox>标记一节已经说过,用于在ActionForm中表示一个选择框的类型通常使用boolean型。此处在ErrBean中就声明了一个boolean型的变量checkbox1用于表示页面上的选择框。当用户在页面上点击了该选择框时,选择框的值被设置为true。然后用户点击提交按钮,此时,Struts框架从struts-config.xml文件中得知这个提交的ActionForm的validate属性为true,因此需要调用 ErrBean的validate()方法进行验证。
在ErrBean的validate()方法中,首先初始化一个ActionErrors对象,然后判断checkbox1是否被选中。若选中,则向ActionErrors 对象中添加两个ActionError。添加ActionError时采用的是ActionErrors的add()方法。该方法有两个参数,第一个参数是所添加ActionError 的key,然后是ActionError的值。这样做的原因是因为在ActionErrors内部保存了一个HashMap,以此来将所有的ActionError保存。其中,添加第一个ActionError的代码如下:
errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError("html.errors.error1"));
这里的ActionMessages.GLOBAL_MESSAGE的值是"org.apache.struts.action.GLOBAL_MESSAGE",它是一个常量,表示全局消息。对于每一个key来说,都可以存入多个ActionError。这是因为ActionErrors的内置的HashMap中并不是仅仅存入一个简单的ActionError 对象,而是存入一个List对象,再将多个ActionError对象存入该List中。ActionError的构造函数中的参数是资源文件中的key值,将来在页面上就将显示该key值对应的value。下面是添加第二个ActionError的代码:
errors.add("checkbox1",new ActionError("html.errors.error2"));
这个ActionError的key值为checkbox1,它表示和特定的表单元素相关的错误信息。在页面中的<html:errors>标签中使用 property属性来指定。
通过上面的代码可以看到,用户在提交表单时由ActionForm产生了错误信息,然后转交回页面。此时,就该由页面上的<html:errors> 来显示相应的错误信息了。这时,考虑另一种情形,如果页面上用户输入的信息并无错误,通过了ActionForm的validate()方法的检查,但在Action中经由业务逻辑处理后,返回了一些错误信息。此时,仍然需要将ActionErrors对象存储进request对象中。但Action中并无 validate方法了,该怎么办呢?Action类的saveErrors()方法解决了这一困难。看看下面ErrAction的execute()方法的代码:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionErrors errors = new ActionErrors(); errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionError("html.errors.error3")); saveErrors(request,errors); return mapping.findForward("input"); }
在Action类中提供了一个saveErrors()方法,可以将ActionErrors对象存入request中。通过这个方法<html:errors>标签可以在request中找到它并将其显示在网页上。
前面已经看到了页面上显示的代码,下面就来讲解一下<html:errors>标记的具体用法。
<html;errors>标记可以放在网页上的任何位置,它有以下三个比较重要的属性:
name属性:它指定了存放在request或session属性中的错误对象的值。我们知道,在request或session中,对象的存储一般都以键/值对的方式来进行。ActionErrors对象在request或session中的key默认为Globals.ERROR_KEY。
property属性:用于指定与ActionError对应的key值,如前面例中的checkbox1。
bundle属性:用于指定资源文件,即显示ActionErrors信息时去哪个资源文件中读取相应的消息文本。例如在taglib1中,struts-config.xml 文件中有这样一句代码:
<message-resources parameter="message" key="error"/>
则在页面的<html:errors>标签中使用下面的方式来引用这个资源文件
<html:errors bundle="error"/>
以下是几个代码示例:
<html:errors bundle="error"/>
上面的代码表示显示所有的错误信息。
<html:errors property="org.apache.struts.action.GLOBAL_MESSAGE" bundle="error"/>
上面的代码表示显示所有的全局消息,也就是在向ActionErrors中添加ActionError对象时,选用ActionMessages.GLOBAL_MESSAGE 做为该ActionError的key的对象。
在Struts 1.2中该标签的使用方法
到目前为止,所有有关<html:errors>标签的讨论都是基于Struts 1.1的核心。但在2005年Apache正式推出Struts 1.2后,有许多东西已经被改变。其中很重要的一个改动就是与<html:errors>标记相关的改动,主要就是已经不再推荐使用ActionError类和ActionErrors类,因此,如果要将现有的使用到与<html:errors>标记相关的代码从Struts 1.1下移至Struts 1.2下,需要作以下改动。
1. 将代码中使用到ActionError类的地方换为ActionMessage类。
2. 将除了在ActionForm的validate()方法以外使用到ActionErrors类的地方都替换为ActionMessages。
这样做的主要原因是,ActionError是ActionMessage的子类,而ActionErrors是ActionMessages的子类。开发者认为一个错误消息也是消息的一种,并没有必要专门将其分开存放。只需要使用Globals.MESSAGE_KEY,Globals.ERROR_KEY来进行区分就分。
例如,在ErrAction中,若要使其支持Struts1.2,则可将代码改为如下形式:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionMessages messages = new ActionMessages(); messages.add(ActionMessages.GLOBAL_MESSAGE,new ActionMessage("html.errors.error3")); saveErrors(request,messages); return mapping.findForward("input"); }