最新消息:

使用common-fileupload实现文件上传

Java 观测者 1438浏览

一、准备
1. 下载 commons-fileupload 库,下载地址:http://commons.apache.org/fileupload/
2. 下载 commons-fileupload 依赖库 commons-io,下载地址:http://commons.apache.org/io/

二、代码
该组件支持单文件上传和多文件上传两种方式,首先定义一个基类放置公共属性:

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;

public abstract class FileUploadBase {
   protected Map<String, String> parameters = new HashMap<String, String>();// 保存普通form表单域
   
   protected String encoding = "utf-8"; // 字符编码,当读取上传表单的各部分时会用到该encoding

   protected UploadFileFilter filter = null; // 文件过滤器, 默认为NULL 不过滤
   
   /**
    * The directory in which uploaded files will be stored, if stored on disk.
    */
   protected int 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.
    *
    */
   protected long 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;
   }

   public void setEncoding(String encoding) {
       this.encoding = encoding;
   }

   /**
    * 获取上传文件最大的大小,单位为Byte(字节),为-1时表示无限制
    * @return
    */
   public long getSizeMax() {
       return sizeMax;
   }

   /**
    * 设置上传文件最大的大小,单位为Byte(字节),为-1时表示无限制
    * @param sizeMax
    */
   public void setSizeMax(long sizeMax) {
       this.sizeMax = sizeMax;
   }

   public int getSizeThreshold() {
       return sizeThreshold;
   }

   public void 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()
    *
    */
   public void setRepository(File repository) {
       this.repository = repository;
   }
   
   /**
    * 获取参数列表
    * @return
    */
   public Map<String, String> getParameters() {
       return parameters;
   }

   /**
    * 获取过滤器
    * @return
    */
   public UploadFileFilter getFilter() {
       return filter;
   }

   /**
    * 设置文件过滤器,不符合过滤器规则的将不被上传
    * @param filter
    */
   public void setFilter(UploadFileFilter filter) {
       this.filter = filter;
   }
   
   /**
    * 验证文件是否有效
    * @param item
    * @return
    */
   protected boolean isValidFile(FileItem item){
       return item == null || item.getName() == "" || item.getSize() == 0 || (filter != null && !filter.accept(item.getName())) ? false : true;
   }
}

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;

public class SingleFileUpload extends FileUploadBase {
   private FileItem fileItem;

   /**
    *
    * @param request
    * @throws UnsupportedEncodingException
    */
   public void 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
    */
   public void upload(String fileName) throws Exception {
       File file = new File(fileName);
       uploadFile(file);
   }

   /**
    * 上传文件, 调用该方法之前必须先调用 parseRequest(HttpServletRequest request)
    * @param parent 存储的目录
    * @throws Exception
    */
   public void upload(File parent) throws Exception {
       if (fileItem == null)
           return;

       String name = fileItem.getName();
       File file = new File(parent, name);
       uploadFile(file);
   }
   
   private void 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);
                   
           throw new 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.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;

public class MutiFileUpload extends FileUploadBase {

   private Map<String, FileItem> files;// 保存上传的文件
   private long filesSize = 0; // 所有文件的总大小

   public void 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
    */
   public void 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);
                   
           throw new 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.java

public interface UploadFileFilter {
   /**
    * 通过文件名后缀判断文件是否被接受
    * @param filename 文件名,不包括路径
    * @return
    */
   public boolean 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();
}

三、FileItem类的常用方法
1. boolean isFormField()
isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。如果是普通文本表单字段,返回一个true否则返回一个false。因此可以用该方法判断是否是普通表单域还是文件上传表单域。

2. String getName()
getName方法用来获得文件上传字段中的文件名。

3. String getFieldName()
getFieldName方法用来返回表单标签的name属性的值。

4. void write(File file)
write方法将FileItem对象中的内容保存到某个指定的文件中。如果FileItem对象中的内容是保存在某个临时文件中,该方法完成后,临时文件可以会被删除。该方法也可以将普通表单字段保存在一个文件中,但最主要的用途是把上传的文件内容保存在本地文件系统中。

5. String getString()
getString()方法将FileItem对象中保存的数据流内容以一个字符串返回。它有两个重载形式:public java.lang.String getString()和public java.lang.String getString(java.lang.String encodeing) throws java.io.UnsupportedEncodingException。前者使用缺省的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码。如果在读取普通表单字段元素的内容时,出现了乱码现象,可以调用第二个方法,并传入正确的字符集编码名称。

6. String getContentType()
此方法用来获得上传文件的类型,即标段字段元素描述头属性“content-type”的值,如image/jpeg。如果FileItem对象对应的是普通的表单字段,将返回null。

7. boolean isInMemory()
判断FileItem对象封装的数据是保存在内存中还是硬盘中。

8. void delete()
此方法用来清空FileItem对象中封装的主体内容,如果内容是被保存在临时文件中,该方法会把临时文件删除。

9. InputStream getInputStream()
以流的形式返回上传文件的主体内容。

10. long getSize()
返回上传文件的大小。

四、备注
1. 在表单里加了 ENCTYPE="multipart/form-data" ,直接用request.getParameter( "name "); 是取不到值的。因为common-fileupload又将参数值进行了一次封装,所以,直接取是没法取到的。需采用上述代码中获取参数的方法。
2. 相比jspSmartUpload,我觉得common-fileupload有如下的优点:
1) 开源;
2) Jakarta项目组的支持,开发十分活跃,而 jspSmartUpload 则已经停止开发了;
3) 不需要写入文件之前即可获取到参数和文件信息,jspSmartUpload 则需要在获取之前调用 upload 方法;
4) 对中文支持友好。

参考文档:使用common-fileupload.jar实现文件上传

转载请注明:观测者 » 使用common-fileupload实现文件上传