struts的附件管理是通過org.apache.struts.upload.FormFile這個介面實現的,在通過ActionServlet及RequestProcessor中利用MultipartRequestHandler對其進行了封裝解析。其後台也是通過ASF的commons-fileupload.jar包來實現的。其實我們也可以直接用這個包中的DiskFileUpload和FileItem等類來自行實現。
1、首先是ActionForm
public class AttachForm extends BaseForm {
private List attachFiles = new ArrayList();
public List getAttachFiles() {
return attachFiles;
}
public void setAttachFiles(List attachFiles) {
this.attachFiles = attachFiles;
}
public AttachFile getAttachFile(int index) {
// ActionServlet在populate form的時候調用getAttachFile
// 不過index的順序具有不確定性, 經調試3個控制項時順序為2/0/1
// 因此不管順序如何都先添加一個然後取最大的一個
this.attachFiles.add(new AttachFile());
return (AttachFile) this.attachFiles.get(this.attachFiles.size() - 1);
}
}
2、然後是AttachFile
非常簡單,只是實現對FormFile的封裝
public class AttachFile implements Serializable {
private FormFile file;
public FormFile getFile() {
return file;
}
public void setFile(FormFile file) {
this.file = file;
}
}
3、接著來看看jsp
關鍵點一個是動態添加指令碼,一個是迭代產生的file控制項。這裡沒有用到惱人的nested標籤,直接用的logic和html的更容易理解。
<script type=”text/javascript”>
function addAttach() {
var iNumOfFiles = 0;
var files = document.getElementsByTagName(”input”);
for (var i = 0; i < files.length; i++) {
if (files[i].type == “file”) iNumOfFiles ++;
}
var tbAttach = document.getElementById(”tbAttach”);
var trAttach = document.createElement(”<tr/>”);
tbAttach.tBodies[0].appendChild(trAttach);
var tdAttach = document.createElement(”<td/>”);
trAttach.appendChild(tdAttach);
var sHtml = “<input type=/”file/” name=/”attachFile[” + iNumOfFiles + “].file/” value=/”/”>”;
tdAttach.innerHTML = sHtml;
}
function saveAttach() {
var sURL = “&action=save”;
doAction(sURL);
}
</script>
<html:form method=”post” action=”/attachAction” enctype=”multipart/form-data”>
<div class=”divAction”>
<html:button property=”btnSave” value=”添加” onclick=”addAttach()” />
<html:button property=”btnSave” value=”儲存” onclick=”saveAttach()” />
</div>
<TABLE border=”1″ width=”100%” id=”tbAttach”>
<TR>
<TD>選擇檔案</TD>
</TR>
<logic:iterate id=”attachFile” name=”attachForm” property=”attachFiles” indexId=”index”>
<TR>
<TD><html:file property=”file” name=”attachFile” indexed=”true” />
</TD>
</TR>
</logic:iterate>
</TABLE>
</html:form>
產生的HTML為:
<TABLE border=”1″ width=”100%” id=”tbAttach”>
<TR>
<TD>選擇檔案</TD>
</TR>
<TR>
<TD><input type=”file” name=”attachFile[0].file” value=”"></TD>
</TR>
</TABLE>
注意<html:file property=”file” name=”attachFile” indexed=”true” />的property和name屬性。很明顯,populate時是通過調用attachForm.getAttachFile(index).setFile來完成的。
4、最後看看Action,這裡用的是DispathAction。
在add()時可以通過attachForm.setAttachFiles()指定預設的控制項數量;在save()中儲存附件到伺服器上,這裡時放到servletContext下的upload檔案夾下。
/**
* 添加
*/
public ActionForward add(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
AttachForm attachForm = (AttachForm) form;
List attachFiles = new ArrayList();
for (int i = 0; i < 1; i ++) {
attachFiles.add(new AttachFile());
}
attachForm.setAttachFiles(attachFiles);
return mapping.findForward(”add”);
}
/**
* 儲存
*/
public ActionForward save(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
AttachForm attachForm = (AttachForm) form;
List attachFiles = attachForm.getAttachFiles();
for (int i = 0; i < attachFiles.size(); i++) {
AttachFile attachFile = (AttachFile) attachFiles.get(i);
FormFile file = attachFile.getFile();
if (file != null) {
InputStream in = file.getInputStream();
String filePath = this.getServlet().getServletContext().getRealPath(”/”);
this.logger.info(”file path: ” + filePath + “upload//” + file.getFileName());
OutputStream out = new FileOutputStream(filePath + “//” + file.getFileName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
out.close();
in.close();
this.logger.info(”file size:” + file.getFileSize());
} else {
this.logger.info(”file is null”);
}
}
return mapping.findForward(”success”);
}
類似的博文可以參見:http://blog.csdn.net/wts/archive/2006/03/20/630083.aspx