從《Struts1.x系列教程(8):上傳單個文件》中給出的例子可以看出,在Struts1.x中上傳單個文件是非常簡單的,但在實際應用中,上傳文件的個數一般是不確定的,如在網絡硬盤中,用戶可以根據自己的需要上傳任意多個文件(當然,網絡硬盤一次上傳文件的數目一般也是有上限的,如50個,但用戶可以只上傳了3個文件,因此,在這種情況下,上傳文件的個數也是不確定的)。如果讀者用過“網易網盤”或其他類似的服務程序,它們的上傳文件功能基本上都是根據用戶選擇的文件多少來添加要上傳的文件(並不是一開始就在界面上放很多<input type=’file’>元素來讓用戶輸入上傳文件名)。為了讓讀者也可以使用Struts來實現這個功能,在本節將給出一個用Struts實現的類似“網易網盤”的上傳任意多個文件的Web程序。在實現Web程序之前,讓我們先看看圖1所示的主頁面。
圖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 + "]' onchange='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對象)。
【第3步】建立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