前言

关于JSP 文件上传的基础和原理在系列一中有介绍到。 这里介绍一个很流行的组件commons fileupload,用来加速文件上传的开发。

官方的介绍是:  让添加强壮,高性能的文件到你的servlet和Web应用程序变得容易。

官方项目地址:

http://commons.apache.org/proper/commons-fileupload/

FileUpload分析request 里的数据,  生成一些独立的上传items. 每一个item都继承自 FileItem 这个接口。

下载导入

1. 可以到 http://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi 这个地址下载最新的版本。

2. 另外还需要下载 commons-io的 jar 包,下载地址:

http://commons.apache.org/proper/commons-fileupload/dependencies.html

在servlet 和portlet中都可以使用FileUpload, 以下以servlet的使用来介绍

分析请求(request)

首先,需要判断request 是否是文件上传的request.

系列一也有提,文件上传的form 必须设置成如下:

  1. <form method="POST" enctype="multipart/form-data" action="fileUploadServlet">

这里有提供一个方法判断request 是否是正确的类型

  1. // Check that we have a file upload request
  2. boolean isMultipart = ServletFileUpload.isMultipartContent(request);

例如这里, 如果form 中移除enctype="multipart/form-data", 返回值就是false 了。

最简单的状况

最简单的使用场景如下:

1. 如果上传的文件足够小的话应该保存在内存中

2. 大的文件应该写到临时文件中

3. 超大的文件上传请求应该不被允许

4. 内存中的文件最大值,允许上传的文件最大尺寸和临时文件目录的接收默认的设置。

看个实例:

  1. // Create a factory for disk-based file items
  2. FileItemFactory factory = new DiskFileItemFactory();
  3.  
  4. // Configure a repository (to ensure a secure temp location is used)
  5. ServletContext servletContext = this.getServletConfig().getServletContext();
  6. File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
  7. factory.setRepository(repository);
  8.  
  9. // Create a new file upload handler
  10. ServletFileUpload upload = new ServletFileUpload(factory);
  11.  
  12. // Parse the request
  13. List<FileItem> items = upload.parseRequest(request);

更多的控制

也可以进行更多的设置, 看例子

  1. // Create a factory for disk-based file items
  2. DiskFileItemFactory factory = new DiskFileItemFactory();
  3.  
  4. // Set factory constraints
  5. factory.setSizeThreshold(yourMaxMemorySize);
  6. factory.setRepository(yourTempDirectory);
  7.  
  8. // Create a new file upload handler
  9. ServletFileUpload upload = new ServletFileUpload(factory);
  10.  
  11. // Set overall request size constraint
  12. upload.setSizeMax(yourMaxRequestSize);
  13.  
  14. // Parse the request
  15. List<FileItem> items = upload.parseRequest(request);

这里设置了最大内存大小,临时文件路径和文件最大值。

设置方式也可以这样:

  1. DiskFileItemFactory factory =newDiskFileItemFactory(yourMaxMemorySize, yourTempDirectory);

处理上传的item

需要再提一下的是: FileUpload 不仅会把一个file 的input 放入一个 FileItem, 一般的Form text input 也会放入一个FileItem.

所以在分析完之后接下来就是如何处理这些FileItem 了。

  1. // Process the uploaded items
  2. Iterator<FileItem> iter = items.iterator();
  3. while (iter.hasNext()) {
  4. FileItem item = iter.next();
  5.  
  6. if (item.isFormField()) {
  7. processFormField(item);
  8. } else {
  9. processUploadedFile(item);
  10. }
  11. }

对于一般的form field 来说(text input), 无非就是取它的name 和value  了。

  1. // Process a regular form field
  2. if (item.isFormField()) {
  3. String name = item.getFieldName();
  4. String value = item.getString();
  5. ...
  6. }

对于文件类型的话, 可以

  1. // Process a file uploadif(!item.isFormField()){
  2.     String fieldName = item.getFieldName();
  3.     String fileName = item.getName();
  4.     String contentType = item.getContentType();
  5.     boolean isInMemory = item.isInMemory();
  6.     long sizeInBytes = item.getSize();
  7.     ...}

看是否需要写入到某个文件中:

  1. // Process a file uploadif(writeToFile){
  2.     File uploadedFile =newFile(...);
  3.     item.write(uploadedFile);}else{
  4.     InputStream uploadedStream = item.getInputStream();
  5.     ...
  6.     uploadedStream.close();}

得到文件

  1. // Process a file upload in memorybyte[] data = item.get();...

资源清除

如果使用DiskFileItem, 或者说在处理上传文件之前写入临时文件的话,就要考虑资源清除了。

临时文件不再使用的话,是会自动被删除的。org.apache.commons.io.FileCleaner 这个类会启动一个回收线程。

如果不再需要这个回收线程的话, 可以停止它。 方法是在xml 中加入:

  1. <web-app>
  2.   ...
  3.   <listener>
  4.     <listener-class>
  5.       org.apache.commons.fileupload.servlet.FileCleanerCleanup
  6.     </listener-class>
  7.   </listener>
  8.   ...
  9. </web-app>

 

创建一个 DiskFileItemFactory

FileCleanerCleanup提供了一个org.apache.commons.io.FileCleaningTracker的实例,如果创建一个org.apache.commons.fileupload.disk.DiskFileItemFactory则需要这个实例。像

  1. publicstaticDiskFileItemFactory newDiskFileItemFactory(ServletContext context,
  2.                                                          File repository){
  3.     FileCleaningTracker fileCleaningTracker
  4.         =FileCleanerCleanup.getFileCleaningTracker(context);
  5.     DiskFileItemFactory factory
  6.         =newDiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,
  7.                                   repository);
  8.     factory.setFileCleaningTracker(fileCleaningTracker);
  9.     return factory;}

如果不想删除临时文件的话, 设置 FileCleaningTracker为null 就可以了。 因此,创建的文件将不再被跟踪。特别是,它们将不再被自动删除。

与病毒扫描软件的问题

病毒扫描软件可能会导致FileUpload 的一些异常状况。

解决方式就是让扫描软件不要监视某些特定的目录。

查看上传进度

  1. //Create a progress listenerProgressListener progressListener =newProgressListener(){
  2.    publicvoid update(long pBytesRead,long pContentLength,int pItems){
  3.        System.out.println("We are currently reading item "+ pItems);
  4.        if(pContentLength ==-1){
  5.            System.out.println("So far, "+ pBytesRead +" bytes have been read.");
  6.        }else{
  7.            System.out.println("So far, "+ pBytesRead +" of "+ pContentLength
  8.                               +" bytes have been read.");
  9.        }
  10.    }};
  11. upload.setProgressListener(progressListener);

或者

  1. //Create a progress listenerProgressListener progressListener =newProgressListener(){
  2.    privatelong megaBytes =-1;
  3.    publicvoid update(long pBytesRead,long pContentLength,int pItems){
  4.        long mBytes = pBytesRead /1000000;
  5.        if(megaBytes == mBytes){
  6.            return;
  7.        }
  8.        megaBytes = mBytes;
  9.        System.out.println("We are currently reading item "+ pItems);
  10.        if(pContentLength ==-1){
  11.            System.out.println("So far, "+ pBytesRead +" bytes have been read.");
  12.        }else{
  13.            System.out.println("So far, "+ pBytesRead +" of "+ pContentLength
  14.                               +" bytes have been read.");
  15.        }
  16.    }};

Streaming API

上面提到的API (传统API) 是在使用前完全把Item  读到某个地方(内存或是文件),使用Streaming 的话,可以逐步的读取, 性能和内存使用都会大大提升。

  1. // Create a new file upload handler
  2. ServletFileUpload upload = new ServletFileUpload();
  3.  
  4. // Parse the request
  5. FileItemIterator iter = upload.getItemIterator(request);
  6. while (iter.hasNext()) {
  7. FileItemStream item = iter.next();
  8. String name = item.getFieldName();
  9. InputStream stream = item.openStream();
  10. if (item.isFormField()) {
  11. System.out.println("Form field " + name + " with value "
  12. + Streams.asString(stream) + " detected.");
  13. } else {
  14. System.out.println("File field " + name + " with file name "
  15. + item.getName() + " detected.");
  16. // Process the input stream
  17. ...
  18. }
  19. }

JSP 文件上传下载系列之二[Commons fileUpload]的更多相关文章

  1. jsp文件上传下载组件

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...

  2. SpringMVC 文件上传下载

    目录 文件上传 MultipartFile对象 文件下载 上传下载示例 pom.xml增加 创建uploadForm.jsp 创建uploadForm2.jsp 创建userInfo.jsp spri ...

  3. 基于struts2--实现文件上传下载

    1. 文件的上传: 1). 表单需要注意的 3 点 ①. method="post"     ②. enctype="mulitipart/form-data" ...

  4. JAVA Web 之 struts2文件上传下载演示(二)(转)

    JAVA Web 之 struts2文件上传下载演示(二) 一.文件上传演示 详细查看本人的另一篇博客 http://titanseason.iteye.com/blog/1489397 二.文件下载 ...

  5. 使用Typescript重构axios(二十五)——文件上传下载进度监控

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  6. SpringBoot入门一:基础知识(环境搭建、注解说明、创建对象方法、注入方式、集成jsp/Thymeleaf、logback日志、全局热部署、文件上传/下载、拦截器、自动配置原理等)

    SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,SpringBoot致力于在蓬勃发 ...

  7. salesforce 零基础学习(四十二)简单文件上传下载

    项目中,常常需要用到文件的上传和下载,上传和下载功能实际上是对Document对象进行insert和查询操作.本篇演示简单的文件上传和下载,理论上文件上传后应该将ID作为操作表的字段存储,这里只演示文 ...

  8. jsp+servlet实现文件上传下载

    相关素材下载 01.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" ...

  9. SpringMVC文件上传下载

    在Spring MVC的基础框架搭建起来后,我们测试了spring mvc中的返回值类型,如果你还没有搭建好springmvc的架构请参考博文->http://www.cnblogs.com/q ...

随机推荐

  1. 闲来瞎扯 -- 在vs2008下编写linux程序

    虽说vim很强大,但是个人感觉器代码提示功能不如visual assist来的强大.如何使用visual assist来实现代码的提示功能呢? 首先说明我的环境 : 宿主机是xp(O(∩_∩)O~还是 ...

  2. linux的NetworkManager服务(转)

    在开启NetworkManager服务的情况下,在终端下敲“service network restart”命令: 正在关闭接口 eth0: 设备状态:3 (断开连接) [确定] 正在关闭接口 eth ...

  3. cf459C Pashmak and Buses

    C. Pashmak and Buses time limit per test 1 second memory limit per test 256 megabytes input standard ...

  4. 如何将Oracle安装为Linux服务

    方法一:使用oracle自带的启动和关闭脚本 1. oracle用户修改/etc/oratab 文件: $ vi /etc/oratab orcl:/oracle/app/product/10.2.0 ...

  5. poj 1328 Radar Installation_贪心

    翻出一年多前的代码看,发现以前的代码风格很糟糕 题意:给你n个点 m为圆的半径,问需要多少个圆能把全部点圈到 #include <iostream> #include <algori ...

  6. PHP - Mysql数据库备份类

    使用方法: require_once("backdata.class.php"); $link =@mysql_connect("localhost",&quo ...

  7. malloc用法

    malloc用法三部曲:(#include<stdlib.h>下的库函数) 1.malloc eg.ps=(char*)malloc(sizeof(char)*20)的意思是,动态分配空间 ...

  8. Mysql数据库启动

    1.改变数据库的访问ip: vim /etc/mysql/my.cnf 找到下面选项: bind-address            = 192.168.1.128 修改即可. 2.mysql启动命 ...

  9. H264 编码详解

    H264 编码详解(收集转载) (1)       x264_param_default( x264_param_t *param ) 作用: 对编码器进行参数设定 cqm:量化表相关信息 csp: ...

  10. Vbox 未指定XXX网络名称 找不到网卡问题

    链接方式不止Host-Only 我一般选桥连 选择 VBoxNetFltM.inf VBoxNetFltM.inf VirtualBox的桥接网络驱动程序的INF文件(Miniport:端口) VBo ...