zoukankan      html  css  js  c++  java
  • JSP 文件上传下载系列之二[Commons fileUpload]

    前言

    关于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
            ...
        }
    }


  • 相关阅读:
    LSMW TIPS
    Schedule agreement and Delfor
    Running VL10 in the background 13 Oct
    analyse idoc by creation date
    New Journey Prepare
    EDI error
    CBSN NEWS
    Listen and Write 18th Feb 2019
    Microsoft iSCSI Software Target 快照管理
    通过 Microsoft iSCSI Software Target 提供存储服务
  • 原文地址:https://www.cnblogs.com/pangblog/p/3329096.html
Copyright © 2011-2022 走看看