从《Struts1.x系列教程(8):上传单个文件》中给出的例子可以看出,在Struts1.x中上传单个文件是非常简单的,但在实际应用中,上传文件的个数一般是不确定的,如在网络硬盘中,用户可以根据自己的需要上传任意多个文件(当然,网络硬盘一次上传文件的数目一般也是有上限的,如50个,但用户可以只上传了3个文件,因此,在这种情况下,上传文件的个数也是不确定的)。如果读者用过“网易网盘”或其他类似的服务程序,它们的上传文件功能基本上都是根据用户选择的文件多少来添加要上传的文件(并不是一开始就在界面上放很多<input type=‘file’>元素来让用户输入上传文件名)。为了让读者也可以使用Struts来实现这个功能,在本节将给出一个用Struts实现的类似“网易网盘”的上传任意多个文件的Web程序。在实现Web程序之前,让我们先看看图1所示的主页面。
在本程序中,用户通过在文本框中输入本地文件名或使用“浏览”按钮选择要上传的文件后,就会在界面的下方添加这个被录入的文件名,如果录入有误,或是不想上传某个文件,可以使用“删除”功能将当前文件删除。在确认正确录入所有的上传文件后,使用“上传”按钮开始上传文件。
实现这个Web程序的基本步骤和《Struts1.x系列教程(8):上传单个文件》一文中所给出的例子类似,我们可按下面五步来实现这个Web程序:
【第1步】建立上传文件的JSP页面
要想实现上述的功能,需要在JavaScript中使用DOM技术(关于JavaScript和DOM技术的相关内容已经超出本文讨论的范围,如果读者想了解JavaScript和DOM技术的细节部分,请参阅其他相关技术资料)。
在<samples工程目录>目录中建立一个uploadMoreFile.jsp文件,代码如下:
<%@ page pageEncoding="GBK"%> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%> <html> <head> <title>上传任意多个文件(总大小不能超过2M)</title> <script language="javascript"> // 在DOM中插入一个上传文件列表项(div元素)和一个<input type="file"/>元素 function insertNextFile(obj) { // 获取上传控制个数 var childnum = document.getElementById("files").getElementsByTagName("input").length; var id = childnum - 1; var fullName = obj.value; // 插入<div>元素及其子元素 var fileHtml = ''; fileHtml += '<div id = "file_preview' + id + '" style ="border-bottom: 1px solid #CCC;">'; fileHtml += '<img width =30 height = 30 src ="images/file.gif" title="' + fullName + '"/>'; fileHtml += '<a href="javascript:;" onclick="removeFile(' + id + ');">删除</a> '; fileHtml += fullName.substr(fullName.lastIndexOf('\\')+1) +' </div>'; var fileElement = document.getElementById("files_preview"); fileElement.innerHTML = fileElement.innerHTML + fileHtml; obj.style.display = 'none'; // 隐藏当前的<input type=”file”/>元素 addUploadFile(childnum); // 插入新的<input type=”file”/>元素 } // 插入新的<input type=”file”/>元素,适合于不同的浏览器(包括IE、FireFox等) function addUploadFile(index) { try // 用于IE浏览器 { var uploadHTML = document.createElement( "<input type='file' id='file_" + index + "' name='file[" + index + "]' οnchange='insertNextFile(this)'/>"); document.getElementById("files").appendChild(uploadHTML); } catch(e) // 用于其他浏览器 { var uploadObj = document.createElement("input"); uploadObj.setAttribute("name", "file[" + index + "]"); uploadObj.setAttribute("onchange", "insertNextFile(this)"); uploadObj.setAttribute("type", "file"); uploadObj.setAttribute("id", "file_" + index); document.getElementById("files").appendChild(uploadObj); } } function removeFile(index) // 删除当前文件的<div>和<input type=”file”/>元素 { document.getElementById("files_preview").removeChild(document.getElementById("file_preview" + index)); document.getElementById("files").removeChild(document.getElementById("file_" + index)); } function showStatus(obj) // 显示“正在上传文件”提示信息 { document.getElementById("status").style.visibility="visible"; } </script> </head> <body> <html:form enctype="multipart/form-data" action="uploadMoreFile"> <span id="files"> <%-- 在此处插入用于上传文件的input元素 --%> <input type="file" id="file_0" name="file[0]" onchange="insertNextFile(this)" /> </span> <html:submit value=" 上传 " onclick="showStatus(this);"/> </html:form> <p> <div id ="status" style="visibility:hidden;color:Red">正在上传文件</div> <p> <%-- 在此处用DOM技术插入上传文件列表项 --%> <div id="files_preview" style ="width:500px;height:500px; overflow :auto" ></div> </body> </html> |
在uploadMoreFile.jsp文件中使用了JavaScript和DOM技术来控制新加入的上传文件以及删除不需要的上传文件。并且在加入<input type=”file”/>元素时考虑了不同的浏览器的差异(详见addUploadFile)。
【第2步】建立ActionForm的子类
在<samples工程目录>\src\actionform目录中建立一个UploadMoreForm.java文件,代码如下:
package actionform; import org.apache.struts.action.*; import org.apache.struts.upload.FormFile; import java.util.*; public class UploadMoreForm extends ActionForm { private List<FormFile> myFiles = new ArrayList<FormFile>(); // 用于保存不定数量的FormFile对象 public FormFile getFile(int i) // 索引属性 { return myFiles.get(i); } public void setFile(int i, FormFile myFile) // 索引属性 { if (myFile.getFileSize() > 0) // 只有上传文件的字节数大于0,才上传这个文件 { myFiles.add(myFile); } } public int getFileCount() // 获得上传文件的个数 { return myFiles.size(); } } |
在UploadMoreFile类中使用了List对象来保存不定数量的FormFile对象。读者也可以使用其他的集合类来保存这些FormFile对象。而且在UploadMoreFile类中使用了带索引的属性,详见getFile和setFile方法。在这两个方法中,第一个参数是一个int类型的变量。要注意的是,索引属性的get和set方法的第一个参数必须是int类型的变量,否则系统会不认这个索引属性。这个索引属性用于和客户端不定数量的<input type=“file” />元素相对应,每一个索引项代表一个<input type=“file” />元素上传的文件(FormFile对象)。
c建立Struts动作类(Action的子类)
由于在《Struts1.x系列教程(8):上传单个文件》一文的例子中的UploadAction类中已经有了一个saveFile方法用于保存单个上传文件,因此,处理多个上传文件的Struts动作类可以从UploadAction类继承。在<samples工程目录>\src\action目录中建立一个UploadMoreAction.java文件,代码如下:
package action; import javax.servlet.http.*; import org.apache.struts.action.*; import org.apache.struts.upload.FormFile; import java.io.*; import actionform.*; public class UploadMoreAction extends UploadAction { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { UploadMoreForm umForm = (UploadMoreForm) form; PrintWriter out = null; int count = 0; try { response.setCharacterEncoding("GBK"); out = response.getWriter(); count = umForm.getFileCount(); // 获得上传文件的总数 for (int i = 0; i < count; i++) { saveFile(umForm.getFile(i)); // 开始保存每一个上传文件 } out.println("成功上传" + String.valueOf(count) + "个文件."); } catch (Exception e) { out.println(e.getMessage()); } return null; } } |
【第4步】配置struts-config.xml
在这一步来配置一下在第2步和第3步分别建立的ActionForm和Action的子类。打开struts-config.xml文件,在<form-beans>元素中加入如下的子元素:
<form-bean name="uploadMoreForm" type="actionform.UploadMoreForm" /> |
在<action-mappings>元素中加入如下的子元素:
<action name="uploadMoreForm" path="/uploadMoreFile" scope="request" type="action.UploadMoreAction" /> |
【第5步】复制gif图片
本例中使用了一个gif图,在Web根目录中建立一个images目录,并复制一个file.gif文件(30*30)到这个目录(读者可以使用自己喜欢的任何gif图片)。
由于在《Struts1.x系列教程(8):上传单个文件》一文的例子中已经设置了上传文件的保存路径和上传文件的大小限制,因此,在本例中仍然使用这一设置。但要注意的是,在上传多个文件时,最大上传文件尺寸指的是所有上传文件的尺寸之和,而不是指每个文件的尺寸。
启动Tomcat后,在IE地址栏中输入如下的URL来测试程序:
http://localhost:8080/samples/uploadMoreFile.jsp