就在前段时间,还在苦于找到不到合适的上传组件,虽然很早就知道了 common-fileupload,但当时却因为没有找到如何获取表单参数的方法而使用 jspSmartUpload,历尽艰辛终于找到了它的 jar,可是使用后才发现此东西对中文参数支持奇差,甚至需要修改源代码才能解决问题,可是jspSmartUpload并不是开源的项目,而且开发团队也不再对它进行更新,连官方网站都关门大吉了,情急之下使用JadClipse 反编译了它的jar包,原以为问题算是得到解决了,谁知道后来却发现获取到的参数经常出现部分中文乱码,而且还不是固定的汉字出现乱码,仔细研究加Google后才找出了规律,原来是奇数字数的中文会出现乱码,而偶数字数的则正常,阅读了源代码,终于还是没耐心阅读下去,而且看到网上还有评论说该组件有内存泄露的问题,于是才下定决定搞定common-fileupload。
于是从 下载到了最新版的 FileUpload 1.2,阅读了部分文档跟例子,终于找到了获取表单中参数的方法并对该组件做了进一点封装,使其更容易使用,并支持单文件上传和多文件上传两种方式,首先定义一个基类放置公共属性:FileUploadBase.java import java.io.File;import java.util.HashMap;import java.util.Map;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.disk.DiskFileItemFactory;publicabstractclass FileUploadBase { protected Map<String, String> parameters =new HashMap<String, String>();// 保存普通form表单域 protected String encoding ="utf-8"; // 字符编码,当读取上传表单的各部分时会用到该encodingprotected UploadFileFilter filter =null; // 文件过滤器, 默认为NULL 不过滤 /** *//** * The directory in which uploaded files will be stored, if stored on disk.*/protectedint sizeThreshold = DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD;/** *//** * * The maximum size permitted for the complete request, as opposed to * * { @link #fileSizeMax}. A value of -1 indicates no maximum. * */protectedlong sizeMax =-1;/** *//** * The directory in which uploaded files will be stored, if stored on disk.*/protected File repository;public String getParameter(String key) { return parameters.get(key); }public String getEncoding() { return encoding; }publicvoid setEncoding(String encoding) { this.encoding = encoding; }/** *//** * 获取上传文件最大的大小,单位为Byte(字节),为-1时表示无限制 * @return*/publiclong getSizeMax() { return sizeMax; }/** *//** * 设置上传文件最大的大小,单位为Byte(字节),为-1时表示无限制 * @param sizeMax*/publicvoid setSizeMax(long sizeMax) { this.sizeMax = sizeMax; }publicint getSizeThreshold() { return sizeThreshold; }publicvoid setSizeThreshold(int sizeThreshold) { this.sizeThreshold = sizeThreshold; }/** *//** * Returns the directory used to temporarily store files that are larger * than the configured size threshold. * * @return The directory in which temporary files will be located. * * @see #setRepository(java.io.File) * */public File getRepository() { return repository; }/** *//** * Sets the directory used to temporarily store files that are larger than * the configured size threshold. * * @param repository * The directory in which temporary files will be located. * * @see #getRepository() * */publicvoid setRepository(File repository) { this.repository = repository; }/** *//** * 获取参数列表 * @return*/public Map<String, String> getParameters() { return parameters; }/** *//** * 获取过滤器 * @return*/public UploadFileFilter getFilter() { return filter; }/** *//** * 设置文件过滤器,不符合过滤器规则的将不被上传 * @param filter*/publicvoid setFilter(UploadFileFilter filter) { this.filter = filter; }/** *//** * 验证文件是否有效 * @param item * @return*/protectedboolean isValidFile(FileItem item){ return item ==null|| item.getName() ==""|| item.getSize() ==0|| (filter !=null&&!filter.accept(item.getName())) ?false : true; }}
支持单文件上传的 SingleFileUpload 类:SingleFileUpload.java import java.io.File;import java.io.UnsupportedEncodingException;import java.util.List;import javax.servlet.http.HttpServletRequest;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;publicclass SingleFileUpload extends FileUploadBase { private FileItem fileItem;/** *//** * * @param request * @throws UnsupportedEncodingException*/publicvoid parseRequest(HttpServletRequest request)throws UnsupportedEncodingException { DiskFileItemFactory factory =new DiskFileItemFactory(); factory.setSizeThreshold(sizeThreshold);if (repository !=null) factory.setRepository(repository); ServletFileUpload upload =new ServletFileUpload(factory); upload.setHeaderEncoding(encoding);try{ List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) { if (item.isFormField()) { String fieldName = item.getFieldName(); String value = item.getString(encoding); parameters.put(fieldName, value); }else{ if (!super.isValidFile(item)) { continue; }if (fileItem ==null) fileItem = item; } } }catch (FileUploadException e) { e.printStackTrace(); } }/** *//** * 上传文件, 调用该方法之前必须先调用 parseRequest(HttpServletRequest request) * @param fileName 完整文件路径 * @throws Exception*/publicvoid upload(String fileName) throws Exception { File file =new File(fileName); uploadFile(file); }/** *//** * 上传文件, 调用该方法之前必须先调用 parseRequest(HttpServletRequest request) * @param parent 存储的目录 * @throws Exception*/publicvoid upload(File parent) throws Exception { if (fileItem ==null)return; String name = fileItem.getName(); File file =new File(parent, name); uploadFile(file); }privatevoid uploadFile(File file) throws Exception{ if (fileItem ==null)return;long fileSize = fileItem.getSize();if (sizeMax >-1&& fileSize >super.sizeMax){ String message = String.format("the request was rejected because its size (%1$s) exceeds the configured maximum (%2$s)", fileSize, super.sizeMax);thrownew org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException(message, fileSize, super.sizeMax); } String name = fileItem.getName(); fileItem.write(file); }/** *//** * 获取文件信息 * 必须先调用 parseRequest(HttpServletRequest request) * @return*/public FileItem getFileItem() { return fileItem; }}
支持多文件上传的 MutiFileUpload 类:MutiFileUpload.java import java.io.File;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.commons.fileupload.FileItem;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;publicclass MutiFileUpload extends FileUploadBase { private Map<String, FileItem> files;// 保存上传的文件privatelong filesSize =0; // 所有文件的总大小publicvoid parseRequest(HttpServletRequest request)throws UnsupportedEncodingException { files =new HashMap<String, FileItem>();// Create a factory for disk-based file items DiskFileItemFactory factory =new DiskFileItemFactory(); factory.setSizeThreshold(sizeThreshold);if (repository !=null) factory.setRepository(repository); ServletFileUpload upload =new ServletFileUpload(factory); upload.setHeaderEncoding(encoding);try{ List<FileItem> items = upload.parseRequest(request);for (FileItem item : items) { if (item.isFormField()) { String fieldName = item.getFieldName(); String value = item.getString(encoding); parameters.put(fieldName, value); }else{ if (super.isValidFile(item)) { continue; } String fieldName = item.getFieldName(); files.put(fieldName, item); filesSize += item.getSize(); } } }catch (FileUploadException e) { e.printStackTrace(); } }/** *//** * 上传文件, 调用该方法之前必须先调用 parseRequest(HttpServletRequest request) * @param parent 文件存储的目录 * @throws Exception*/publicvoid upload(File parent) throws Exception { if (files.isEmpty())return;if (sizeMax >-1&& filesSize >super.sizeMax){ String message = String.format("the request was rejected because its size (%1$s) exceeds the configured maximum (%2$s)", filesSize, super.sizeMax);thrownew SizeLimitExceededException(message, filesSize, super.sizeMax); }for (String key : files.keySet()) { FileItem item = files.get(key); String name = item.getName(); File file =new File(parent, name); item.write(file); } }public Map<String, FileItem> getFiles() { return files; }}
当然还少不了过滤器 UploadFileFilter:UploadFileFilter.java publicinterface UploadFileFilter { /** *//** * 通过文件名后缀判断文件是否被接受 * @param filename 文件名,不包括路径 * @return*/publicboolean accept(String filename);}
这样在 Servlet 中我们就可以通过简单的代码实现文件的上传了: SingleFileUpload upload =new SingleFileUpload(); upload.parseRequest(request); File parent =new File("C:\\upload\\"); try{ upload.upload(parent); }catch(org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e){ // 文件大小超出最大值 e.printStackTrace(); }catch (Exception e) { e.printStackTrace(); }
相比 jspSmartUpload 我觉得 common-fileupload 有如下的优点:1、开源;2、Jakarta项目组的支持,开发十分活跃,而 jspSmartUpload 则已经停止开发了;3、不需要写入文件之前即可获取到参数和文件信息,jspSmartUpload 则需要在获取之前调用 upload 方法;4、对中文支持友好。 转自: