前言

关于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 必须设置成如下:

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

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

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

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

最简单的状况

最简单的使用场景如下:

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

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

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

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

看个实例:

// Create a factory for disk-based file items
FileItemFactory factory = new DiskFileItemFactory(); // Configure a repository (to ensure a secure temp location is used)
ServletContext servletContext = this.getServletConfig().getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository); // Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request
List<FileItem> items = upload.parseRequest(request);

更多的控制

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

// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory(); // Set factory constraints
factory.setSizeThreshold(yourMaxMemorySize);
factory.setRepository(yourTempDirectory); // Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory); // Set overall request size constraint
upload.setSizeMax(yourMaxRequestSize); // Parse the request
List<FileItem> items = upload.parseRequest(request);

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

设置方式也可以这样:

DiskFileItemFactory factory =newDiskFileItemFactory(yourMaxMemorySize, yourTempDirectory);

处理上传的item

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

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

// Process the uploaded items
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next(); if (item.isFormField()) {
processFormField(item);
} else {
processUploadedFile(item);
}
}

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

// Process a regular form field
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
...
}

对于文件类型的话, 可以

// Process a file uploadif(!item.isFormField()){
    String fieldName = item.getFieldName();
    String fileName = item.getName();
    String contentType = item.getContentType();
    boolean isInMemory = item.isInMemory();
    long sizeInBytes = item.getSize();
    ...}

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

// Process a file uploadif(writeToFile){
    File uploadedFile =newFile(...);
    item.write(uploadedFile);}else{
    InputStream uploadedStream = item.getInputStream();
    ...
    uploadedStream.close();}

得到文件

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

资源清除

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

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

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

<web-app>
  ...
  <listener>
    <listener-class>
      org.apache.commons.fileupload.servlet.FileCleanerCleanup
    </listener-class>
  </listener>
  ...
</web-app>

 

创建一个 DiskFileItemFactory

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

publicstaticDiskFileItemFactory newDiskFileItemFactory(ServletContext context,
                                                         File repository){
    FileCleaningTracker fileCleaningTracker
        =FileCleanerCleanup.getFileCleaningTracker(context);
    DiskFileItemFactory factory
        =newDiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,
                                  repository);
    factory.setFileCleaningTracker(fileCleaningTracker);
    return factory;}

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

与病毒扫描软件的问题

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

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

查看上传进度

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

或者

//Create a progress listenerProgressListener progressListener =newProgressListener(){
   privatelong megaBytes =-1;
   publicvoid update(long pBytesRead,long pContentLength,int pItems){
       long mBytes = pBytesRead /1000000;
       if(megaBytes == mBytes){
           return;
       }
       megaBytes = mBytes;
       System.out.println("We are currently reading item "+ pItems);
       if(pContentLength ==-1){
           System.out.println("So far, "+ pBytesRead +" bytes have been read.");
       }else{
           System.out.println("So far, "+ pBytesRead +" of "+ pContentLength
                              +" bytes have been read.");
       }
   }};

Streaming API

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

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(); // Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value "
+ Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name "
+ item.getName() + " detected.");
// Process the input stream
...
}
}

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. PM产品经理练级攻略(1-5等级)

    大家都叫“PM”,但做的事情却完全不同? “PM”这个词到底是什么意思? 这个话题恐怕也是各位同行都一直在想,也一直想不清楚的吧,我也是. 每次看到各种“产品经理的能力模型”,我都觉得有点扯淡,总觉得 ...

  2. Android之用PopupWindow实现弹出listview形式菜单

    Android 4.0之前的菜单使用非常广泛,但是在android4.0之后,很少使用先前的菜单样式了.那如何实现下图的样式了? 我们简单模拟一下. (1)屏蔽系统弹出的菜单: 1.首先创建至少一个系 ...

  3. unity3D 锁屏再开程序崩溃

    在Uniyt3d 调用Android Plugin 的时候,会出现锁屏后再开,程序就崩溃的的现象,解决办法就是在 AndroidManifest.xml 加入  android:configChang ...

  4. JavaScript声音播放

    方式一: /** * 播放音频(Chrome.opera)支持 * @param file:支持 rm,mid,wav */ function playAudio(file) { var embed= ...

  5. 关于k-means聚类算法的matlab实现

    在数据挖掘中聚类和分类的原理被广泛的应用. 聚类即无监督的学习. 分类即有监督的学习. 通俗一点的讲就是:聚类之前是未知样本的分类.而是根据样本本身的相似性进行划分为相似的类簇.而分类 是已知样本分类 ...

  6. Nim游戏博弈

    Nim游戏的概述: 还记得这个游戏吗? 给出n列珍珠,两人轮流取珍珠,每次在某一列中取至少1颗珍珠,但不能在两列中取.最后拿光珍珠的人输. 后来,在一份资料上看到,这种游戏称为"拈(Nim) ...

  7. 网易云课堂_艾叔:零基础一站式C语言|C程序设计精讲_章节12:指针

    课时63指针操作数组 二维数组 #include <stdio.h> #include <stdlib.h> int main() { int age[2][4] = { 1, ...

  8. Vim应用

    :q!不保存退出 :set number显示行数 :wq保存并退出 ==先输入100,再输入==.从这行开始向下100行,进行自动缩进对齐

  9. 浅析C# 中object sender与EventArgs e (转)

    一.了解C#中的预定义事件处理机制    在写代码前我们先来熟悉.net框架中和事件有关的类和委托,了解C#中预定义事件的处理. EventArgs是包含事件数据的类的基类,用于传递事件的细节. Ev ...

  10. URAL 1736 Chinese Hockey 网络流+建图

    题目链接:点击打开链接 题意: 给定n个队伍的得分情况,输出随意一个可行解. n个队伍随意2个队伍 a, b 间有且仅有一场比赛. 比赛结果分4种: 1.a +3, b +0 2.a +0, b +3 ...