zoukankan      html  css  js  c++  java
  • java FileUpload 组件上传文件

    Commons FileUpload

    Apache提供的一个组件,可以很方便的让我们处理客户端上传的文件,

    下载地址 http://commons.apache.org/proper/commons-fileupload/

    下载commons-fileupload.jar,还有其依赖包 commons-io.jar一同下载好,导入工程

    有点奇葩的是,在tomcat下已经把這个组建集成了,但是不能正常使用,其源码基本上是一样的。

    正确的包名应该是這个:org.apache.commons.fileupload.

    而不是org.apache.tomcat.util.http.fileupload.下面的

    最简单的使用

     1 protected void doPost(HttpServletRequest request,
     2             HttpServletResponse response) throws ServletException, IOException {
     3 
     4         ServletContext servletContext = this.getServletContext();
     5 
     6         // 指定保存文件的位置,放在WEB-INF目录下是为了保证系统的安全性
     7         String savePath = servletContext.getRealPath("/WEB-INF/upload");
     8         System.out.println("savePath=" + savePath);
     9 
    10         if (ServletFileUpload.isMultipartContent(request)) {
    11 
    12             try {
    13                 // 创建FileItem的工厂
    14                 DiskFileItemFactory factory = new DiskFileItemFactory();
    24                 // 创建一个FileItem的解析器,根据前面设置好的工厂得到
    25                 ServletFileUpload upload = new ServletFileUpload(factory);
    26 
    27                 // 解析出FIleItem项,parserRequest接收的类型是
    28                 // javax.servlet.http.HttpServletRequest
    29                 List<FileItem> items = upload.parseRequest(request);
    30 
    31                 // 遍历FileItem,检查是否为普通字符还是文件流
    32                 for (FileItem item : items) {
    33 
    34                     // 普通表单文字
    35                     if (item.isFormField()) {
    36                         // 表单上的name
    37                         String name = item.getFieldName();
    38                         // 表单上的value
    39                         String value = item.getString();
    40 
    41                         System.out.println("name=" + name
    42                                 + "   ----------   value=" + value);
    43 
    44                         // 数据库操作。。
    45                     } else {
    46                         // 文件一般从网络上传后存放到数据库,而原来的文件将采用不重复的命名方案存放
    47                         String fileName = item.getName();// 文件名,可能是带全路径的或者就是文件名
    48                         System.out.println("上传文件全路径:" + fileName);
    49                         fileName = fileName.substring(fileName
    50                                 .lastIndexOf("\") + 1);// IE
    51                                                         // 、Opera
    52                         System.out.println("上传文件名:" + fileName);
    53 
    54                         // 没有上传文件
    55                         if (fileName.equals("")) {
    56                             break;
    57                         }
    58                         InputStream in = item.getInputStream();
    59                         FileOutputStream fos = new FileOutputStream(savePath
    60                                 + "\" + fileName);
    61 
    62                         byte[] b = new byte[1024];
    63                         int len = 0;
    64                         while ((len = in.read(b)) != -1) {
    65                             fos.write(b, 0, len);
    66                         }
    67 
    68                         in.close();
    69                         fos.close();
    70 
    71                     }
    72                 }
    73 
    74             } catch (FileUploadException e) {
    75                 // TODO Auto-generated catch block
    76                 e.printStackTrace();
    77             }
    78 
    79         } else {
    80             response.getWriter().write("no multipart/form-data submit");
    81         }
    82     }
    83     

    设置一下高级的用法:

    修改默认设置,设置限制上传大小,返回当前上传进度。。

    protected void doPost(HttpServletRequest request,
                final HttpServletResponse response) throws ServletException,
                IOException {
            response.setContentType("text/html;charset=UTF-8");
            ServletContext servletContext = this.getServletContext();
    
            // 指定保存文件的位置,放在WEB-INF目录下是为了保证系统的安全性
            String savePath = servletContext.getRealPath("/WEB-INF/upload");
            System.out.println("savePath=" + savePath);
    
            if (ServletFileUpload.isMultipartContent(request)) {
    
                try {
                    // 创建FileItem的工厂
                    DiskFileItemFactory factory = new DiskFileItemFactory();
    
                    // 设置FileItem工厂的一些属性
                    File repository = (File) servletContext
                            .getAttribute("javax.servlet.context.tempdir"); // 得到用户临时文件夹
                    System.out.println("temp position:" + repository.getPath());
    
                    factory.setRepository(repository); // 设置临时的存储位置
                    factory.setSizeThreshold(1024 * 100);// 设置缓存大小为100kb,默认为10K,以字节为单位
    
                    // 创建一个FileItem的解析器,根据前面设置好的工厂得到
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    // 设置允许上传的最大值,超出则拒绝上传
                    upload.setSizeMax(1024 * 1000);
                    // 设置上传时的进度条监听器
                    ProgressListener pListener = new ProgressListener() {
    
                        @Override
                        public void update(long pBytesRead, long pContentLength,
                                int pItems) {
                            try {
                                response.getWriter().write(
                                        "上传第"
                                                + pItems
                                                + "文件      上传进度:"
                                                + (pBytesRead * 1.0
                                                        / pContentLength * 100)
                                                + "%<br/>");
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    upload.setProgressListener(pListener);
    
                    // 解析出FIleItem项,parserRequest接收的类型是
                    // javax.servlet.http.HttpServletRequest
                    List<FileItem> items = upload.parseRequest(request);
    
                    // 遍历FileItem,检查是否为普通字符还是文件流
                    for (FileItem item : items) {
    
                        // 普通表单文字
                        if (item.isFormField()) {
                            // 表单上的name
                            String name = item.getFieldName();
                            // 表单上的value
                            String value = item.getString();
    
                            System.out.println("name=" + name
                                    + "   ----------   value=" + value);
    
                            // 数据库操作。。
    
                        } else {
                            // 文件一般从网络上传后存放到数据库,而原来的文件将采用不重复的命名方案存放,System.currentTime
                            String fileName = item.getName();// 文件名,可能是带全路径的或者就是文件名
                            System.out.println("上传文件全路径:" + fileName);
                            fileName = fileName.substring(fileName
                                    .lastIndexOf("\") + 1);// IE
                                                            // 、Opera
                            System.out.println("上传文件名:" + fileName);
    
                            // 没有上传文件
                            if (fileName.equals("")) {
                                break;
                            }
                            InputStream in = item.getInputStream();
                            FileOutputStream fos = new FileOutputStream(savePath
                                    + "\" + getFileName(fileName));
    
                            byte[] b = new byte[1024];
                            int len = 0;
                            while ((len = in.read(b)) != -1) {
                                fos.write(b, 0, len);
                            }
    
                            in.close();
                            fos.close();
    
                        }
                    }
    
                } catch (SizeLimitExceededException e1) {
                    response.getWriter().write("超出大小啦。。");
                } catch (FileUploadException e) {
                    response.getWriter().write("上传失败了。。");
                    e.printStackTrace();
                }
    
            } else {
                response.getWriter().write("no multipart/form-data submit");
            }
        }
    
        String getFileName(String fileName) {
            Date date = new Date(System.currentTimeMillis());
            String result = DateFormat.getDateInstance(DateFormat.SHORT).format(
                    date)
                    + "_" + fileName;
            return result;
        }
    這个组建的目录结构如图



    ServletFileUpload.isMultipartContent(request) 判断是否带有文件数据的表单

    其内部其实还是调用了request.getContentType()的方法的

    ServletUpload
    1     public static final boolean isMultipartContent(
    2             HttpServletRequest request) {
    3         if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {
    4             return false;
    5         }
    6         return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
    7     }

    FileUploadBase

     1   public static final boolean isMultipartContent(RequestContext ctx) {
     2         String contentType = ctx.getContentType();
     3         if (contentType == null) {
     4             return false;
     5         }
     6         if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
     7             return true;
     8         }
     9         return false;
    10     }

     //获取迭代器,效率最高的

    FileItemIterator  fIterator = upload.getItemIterator(request);

    //获取List集合,调用迭代器转换而来的

    List<FileItem> items = upload.parseRequest(request);

    //获取Map集合,调用list集合转换的

    parseParameterMap(request)

    迭代器实现过程:

     1   FileItemIteratorImpl(RequestContext ctx)
     2                 throws FileUploadException, IOException {
     3             if (ctx == null) {
     4                 throw new NullPointerException("ctx parameter");
     5             }
     6 
     7             String contentType = ctx.getContentType();
     8             if ((null == contentType)
     9                     || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) {
    10                 throw new InvalidContentTypeException(
    11                         format("the request doesn't contain a %s or %s stream, content type header is %s",
    12                                MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType));
    13             }
    14 
    15             InputStream input = ctx.getInputStream();
    16 
    17             @SuppressWarnings("deprecation") // still has to be backward compatible
    18             final int contentLengthInt = ctx.getContentLength();
    19 
    20             final long requestSize = UploadContext.class.isAssignableFrom(ctx.getClass())
    21                                      // Inline conditional is OK here CHECKSTYLE:OFF
    22                                      ? ((UploadContext) ctx).contentLength()
    23                                      : contentLengthInt;
    24                                      // CHECKSTYLE:ON
    25 
    26             if (sizeMax >= 0) {
    27                 if (requestSize != -1 && requestSize > sizeMax) {
    28                     throw new SizeLimitExceededException(
    29                         format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
    30                                 Long.valueOf(requestSize), Long.valueOf(sizeMax)),
    31                                requestSize, sizeMax);
    32                 }
    33                 input = new LimitedInputStream(input, sizeMax) {
    34                     @Override
    35                     protected void raiseError(long pSizeMax, long pCount)
    36                             throws IOException {
    37                         FileUploadException ex = new SizeLimitExceededException(
    38                         format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
    39                                 Long.valueOf(pCount), Long.valueOf(pSizeMax)),
    40                                pCount, pSizeMax);
    41                         throw new FileUploadIOException(ex);
    42                     }
    43                 };
    44             }
    45 
    46             String charEncoding = headerEncoding;
    47             if (charEncoding == null) {
    48                 charEncoding = ctx.getCharacterEncoding();
    49             }
    50 
    51             boundary = getBoundary(contentType);
    52             if (boundary == null) {
    53                 throw new FileUploadException("the request was rejected because no multipart boundary was found");
    54             }
    55 
    56             notifier = new MultipartStream.ProgressNotifier(listener, requestSize);
    57             try {
    58                 multi = new MultipartStream(input, boundary, notifier);
    59             } catch (IllegalArgumentException iae) {
    60                 throw new InvalidContentTypeException(
    61                         format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae);
    62             }
    63             multi.setHeaderEncoding(charEncoding);
    64 
    65             skipPreamble = true;
    66             findNextItem();
    67         }
      1   private boolean findNextItem() throws IOException {
      2             if (eof) {
      3                 return false;
      4             }
      5             if (currentItem != null) {
      6                 currentItem.close();
      7                 currentItem = null;
      8             }
      9             for (;;) {
     10                 boolean nextPart;
     11                 if (skipPreamble) {
     12                     nextPart = multi.skipPreamble();
     13                 } else {
     14                     nextPart = multi.readBoundary();
     15                 }
     16                 if (!nextPart) {
     17                     if (currentFieldName == null) {
     18                         // Outer multipart terminated -> No more data
     19                         eof = true;
     20                         return false;
     21                     }
     22                     // Inner multipart terminated -> Return to parsing the outer
     23                     multi.setBoundary(boundary);
     24                     currentFieldName = null;
     25                     continue;
     26                 }
     27                 FileItemHeaders headers = getParsedHeaders(multi.readHeaders());
     28                 if (currentFieldName == null) {
     29                     // We're parsing the outer multipart
     30                     String fieldName = getFieldName(headers);
     31                     if (fieldName != null) {
     32                         String subContentType = headers.getHeader(CONTENT_TYPE);
     33                         if (subContentType != null
     34                                 &&  subContentType.toLowerCase(Locale.ENGLISH)
     35                                         .startsWith(MULTIPART_MIXED)) {
     36                             currentFieldName = fieldName;
     37                             // Multiple files associated with this field name
     38                             byte[] subBoundary = getBoundary(subContentType);
     39                             multi.setBoundary(subBoundary);
     40                             skipPreamble = true;
     41                             continue;
     42                         }
     43                         String fileName = getFileName(headers);
     44                         currentItem = new FileItemStreamImpl(fileName,
     45                                 fieldName, headers.getHeader(CONTENT_TYPE),
     46                                 fileName == null, getContentLength(headers));
     47                         currentItem.setHeaders(headers);
     48                         notifier.noteItem();
     49                         itemValid = true;
     50                         return true;
     51                     }
     52                 } else {
     53                     String fileName = getFileName(headers);
     54                     if (fileName != null) {
     55                         currentItem = new FileItemStreamImpl(fileName,
     56                                 currentFieldName,
     57                                 headers.getHeader(CONTENT_TYPE),
     58                                 false, getContentLength(headers));
     59                         currentItem.setHeaders(headers);
     60                         notifier.noteItem();
     61                         itemValid = true;
     62                         return true;
     63                     }
     64                 }
     65                 multi.discardBodyData();
     66             }
     67         }
     68 
     69         private long getContentLength(FileItemHeaders pHeaders) {
     70             try {
     71                 return Long.parseLong(pHeaders.getHeader(CONTENT_LENGTH));
     72             } catch (Exception e) {
     73                 return -1;
     74             }
     75         }
     76 
     77         /**
     78          * Returns, whether another instance of {@link FileItemStream}
     79          * is available.
     80          *
     81          * @throws FileUploadException Parsing or processing the
     82          *   file item failed.
     83          * @throws IOException Reading the file item failed.
     84          * @return True, if one or more additional file items
     85          *   are available, otherwise false.
     86          */
     87         public boolean hasNext() throws FileUploadException, IOException {
     88             if (eof) {
     89                 return false;
     90             }
     91             if (itemValid) {
     92                 return true;
     93             }
     94             try {
     95                 return findNextItem();
     96             } catch (FileUploadIOException e) {
     97                 // unwrap encapsulated SizeException
     98                 throw (FileUploadException) e.getCause();
     99             }
    100         }
    101 
    102         /**
    103          * Returns the next available {@link FileItemStream}.
    104          *
    105          * @throws java.util.NoSuchElementException No more items are
    106          *   available. Use {@link #hasNext()} to prevent this exception.
    107          * @throws FileUploadException Parsing or processing the
    108          *   file item failed.
    109          * @throws IOException Reading the file item failed.
    110          * @return FileItemStream instance, which provides
    111          *   access to the next file item.
    112          */
    113         public FileItemStream next() throws FileUploadException, IOException {
    114             if (eof  ||  (!itemValid && !hasNext())) {
    115                 throw new NoSuchElementException();
    116             }
    117             itemValid = false;
    118             return currentItem;
    119         }
    View Code
  • 相关阅读:
    bzoj 4974 [Lydsy1708月赛]字符串大师 KMP 最小循环元 构造
    4.10 省选模拟赛 约数 数论 转换 三元组个数
    loj #6039 「雅礼集训 2017 Day5」珠宝 分组背包 决策单调性优化
    CF R 632 div2 1333F Kate and imperfection
    CF R 632 div2 1333D Challenges in school №41
    luogu P3703 [SDOI2017]树点涂色
    3.28 省选模拟赛 染色 LCT+线段树
    luogu P3279 [SCOI2013]密码
    4.8 省选模拟赛 相遇 求树上两路径交
    Hyper-V 2016 上安装windows7激活重启后黑屏无法进入系统
  • 原文地址:https://www.cnblogs.com/act262/p/Java.html
Copyright © 2011-2022 走看看