ErixHao 2011-03-30
最近在用commons-fileupload做文件上传的时候遇到了一点小的麻烦,不过最终在学友的帮助下解决,在写之前先说明一下几个错误,在群里面问了上传页面中file选择框的name是否可以相同,很多人说name是不能相同的,不然就不知道是哪个上传的了,这种理解是错误的:
普通表单项name可以相同,在后台接收的时候就用String[],而且在Struts2中我们也看到,在页面中相同名字的file框 name在Action中用File[] 接收,通过这两点分析,以及之后的实验发现,name完全可以相同,下面的FileItem分析 也可以说明这一点
先贴一下FileUpload的工具类,这是做了一个封装:
import java.io.File; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class FileUploadUtil { private Map fileField = new TreeMap(); private Map formField = new TreeMap(); private List<FileItem> list=new ArrayList<FileItem>(); private int memoryBlock = 2048; private File tempFolder = null; private boolean multipart = false; private HttpServletRequest request = null; private final int maxSize = (int) Common.getByteSizeByBKMG(JavaCenterHome.jchConfig.get("upload_max_filesize")); public FileUploadUtil(File tempFolder, int memeoryBlock) { this.tempFolder = tempFolder; this.memoryBlock = memeoryBlock; } public FileUploadUtil() { } public void parse(HttpServletRequest request, String charset) throws FileUploadException { this.request = request; multipart = FileUpload.isMultipartContent(request); if (multipart) { DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(memoryBlock); factory.setRepository(tempFolder); ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(maxSize); List items; items = upload.parseRequest(request); Iterator iterator = items.iterator(); while (iterator.hasNext()) { FileItem item = (FileItem) iterator.next(); if (item.isFormField()) { processFormField(item, charset); } else { processUploadedFile(item); } } } } private void processFormField(FileItem item, String charset) { try { String name = item.getFieldName(); String value = item.getString(charset); Object objv = formField.get(name); if (objv == null) { formField.put(name, value); } else { List values = null; if (objv instanceof List) { values = (List) objv; values.add(value); } else { String strv = (String) objv; values = new ArrayList(); values.add(strv); values.add(value); } formField.put(name, values); } } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException("the argument \"charset\" missing!"); } } private void processUploadedFile(FileItem item) { String name = item.getFieldName(); long size=item.getSize(); if(size>0) list.add(item); fileField.put(name, list); } public static boolean write2file(FileItem item, File file) { boolean flag = false; try { item.write(file); flag = true; } catch (Exception e) { } return flag; } public List<FileItem> getFileItemList(String name) { if (multipart) { return (List<FileItem>) fileField.get(name); } else { return null; } } public String getParameter(String name) { String value = null; if (multipart) { Object obj = formField.get(name); if (obj != null && obj instanceof String) { value = (String) obj; } } else if (request != null) { value = request.getParameter(name); } return value; } public String[] getParameterValues(String name) { String[] values = null; if (multipart) { Object obj = formField.get(name); if (obj != null) { if (obj instanceof List) { values = (String[]) ((List) obj).toArray(new String[0]); } else { values = new String[] {(String) obj}; } } } else if (request != null) { values = request.getParameterValues(name); } return values; } public File getRepository() { return this.tempFolder; } public int getSizeThreshold() { return this.memoryBlock; } public boolean isMultipart() { return this.multipart; } public int getMaxSize() { return maxSize; } }
这个工具类有改动,之前没考虑到多文件上传,在Map只是这样存:
String name = item.getFieldName(); fileField.put(name, item);
这样有二点缺点:
1、如果name相同的话,前面上传的文件就会被后面上传的文件覆盖
2、如果上传文件的size为0,并且在最后面,那么最终fileFiled存放的是一个size为0的FilteItem这显然是无效的
上面最后改进后,对于多文件上传也可以起作用了。
下面来分析一下,这句话后,items中存的东西是怎样的:
List items; items = upload.parseRequest(request);
上面的意思是解析request,下面来看在我项目中一个表单提交后得到的装有FileItem的List
[name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000054.tmp, size=1bytes, isFormField=true, FieldName=productcategory_id, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000055.tmp, size=0bytes, isFormField=true, FieldName=self_type_id, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000056.tmp, size=0bytes, isFormField=true, FieldName=brand_id, name=null,StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000057.tmp, size=18bytes, isFormField=true, FieldName=name, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000058.tmp, size=2bytes, isFormField=true, FieldName=productsn, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000059.tmp, size=1bytes, isFormField=true, FieldName=price, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000060.tmp, size=1bytes, isFormField=true, FieldName=marketprice, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000061.tmp, size=1bytes, isFormField=true, FieldName=weight, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000062.tmp, size=1bytes, isFormField=true, FieldName=weightunit, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000063.tmp, size=1bytes, isFormField=true, FieldName=base_sale_num, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000064.tmp, size=1bytes, isFormField=true, FieldName=product_unit, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000065.tmp, size=1bytes, isFormField=true, FieldName=store, name=http_imgloadCAEP58ES.jpg, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000066.tmp, size=141869bytes, isFormField=false, FieldName=productImages, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000067.tmp, size=16bytes, isFormField=true, FieldName=productImageParameterTypes, name=http_imgloadCAFH1MHX.jpg, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000068.tmp, size=70138bytes, isFormField=false, FieldName=productImages, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000069.tmp, size=16bytes, isFormField=true, FieldName=productImageParameterTypes, name=, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000070.tmp, size=0bytes, isFormField=false, FieldName=productImages, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000071.tmp, size=44bytes, isFormField=true, FieldName=description, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000072.tmp, size=0bytes, isFormField=true, FieldName=producttype_id, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000073.tmp, size=1bytes, isFormField=true, FieldName=valid_date, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000074.tmp, size=1bytes, isFormField=true, FieldName=ismarketable, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000075.tmp, size=1bytes, isFormField=true, FieldName=isbest, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000076.tmp, size=1bytes, isFormField=true, FieldName=isnew, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000077.tmp, size=1bytes, isFormField=true, FieldName=ishot, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000078.tmp, size=0bytes, isFormField=true, FieldName=metakeywords, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000079.tmp, size=0bytes, isFormField=true, FieldName=metadescription, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000080.tmp, size=8bytes, isFormField=true, FieldName=formhash, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000081.tmp, size=0bytes, isFormField=true, FieldName=id, name=null, StoreLocation=D:\Tomcat 6.0.20\webapps\JavaCenterHome\.\data\temp\upload_365228b4_12f048b1396__8000_00000082.tmp, size=1bytes, isFormField=true, FieldName=productsubmit]
上面每一行就是一个FiteItem中的内容,也就是说使用commons-fileupload上传组件后,对于表单中的每一项它都会解析后构造成一个个的FileItem,我们只要操作这写FileItem就行了。