• Apache Commons FileUpload实现文件上传


    一、Apache Commons-FileUpload简介

    Apache Commons是一个专注于可重用Java组件的所有方面的 Apache 项目。
    Apache Commons项目由三个部分组成:

    • Commons Proper - 可重用Java组件的存储库。
    • The Commons Sandbox - 用于Java组件开发的工作区。
    • The Commons Dormant - 当前不活动的组件存储库。

    Commons-FileUpload是Commons Proper中的一个组件,该组件依赖于Commons-IO ,Commons-IO也是 Commons Proper中的一个组件。
    Commons FileUpload的JAR包下载
    Commons IO的JAR包下载

    二.maven依赖

    <!-- upload file -->
            <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.4</version>
            </dependency>

    三.前端界面

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
        <% String path = request.getContextPath(); %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>upload</title>
    </head>
    <br>
    <br>
    
    <form action="<%=path%>/device/uploadFile" method ="post" enctype="multipart/form-data">
        <input type ="file" name ="doc1"><br><br>
        <input type ="file" name ="doc2"><br><br>
        <input type ="text" name = info><br><br>
        <input type ="password" name ="password"><br><br>
        
        <input type="submit" value="提交">
    </form>
    
    <body>
    
    </body>
    </html>

    四.后台代码

    @RequestMapping(value="/uploadFile")
        public String uploadFile(final HttpServletRequest request, final HttpServletResponse response){         
        
            request.setAttribute("msg", "Not first time!");        
             //创建一个“硬盘文件条目工厂”对象
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //设置阈值,设置JVM一次能够处理的文件大小(默认吞吐量是10KB)
            factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
            //设置临时文件的存储位置(文件大小大于吞吐量的话就必须设置这个值,比如文件大小:1GB ,一次吞吐量:1MB)
             factory.setRepository(new File("d:\test"));
            //创建核心对象
             ServletFileUpload fileUpload = new ServletFileUpload(factory);
            //设置最大可支持的文件大小(10MB)
             fileUpload.setFileSizeMax(1024*1024*10);
            //设置转换时使用的字符集
             fileUpload.setHeaderEncoding("UTF-8");
             if(ServletFileUpload.isMultipartContent(request)){
                 try {
                    List<FileItem> fileItems = fileUpload.parseRequest(request);
                    for ( FileItem fileItem : fileItems) {
                        if(fileItem.isFormField()){//判断该FileItem为一个普通的form元素
                            //获取字段名
                            String fieldName = fileItem.getFieldName();
                            //获取字段值,并解决乱码
                            String fieldValue = fileItem.getString("UTF-8");
                            System.out.println(fieldName +" : " + fieldValue);
                            
                        }else{//判断该FileItem为一个文件
                            
                            System.out.println("Start to uplaod file!");
                            //获取文件名
                            String fileName = fileItem.getName();
                            System.out.println("fileName : " + fileName);
                            //获取文件大小
                            long fileSize = fileItem.getSize();
                            System.out.println("fileSize : " + fileSize);
                            
                            fileItem.write(new File("D://test//upload"+File.separator +fileName));
                        }
                    }
                } catch (FileUploadException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (UnsupportedEncodingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
             }
            
        return "device/uploadFile";
        }

     五。异常

    catch(FileUploadBase.SizeLimitExceededException ex){
                    out.print("上传失败,文件太大,单个文件的最大限制是:"+upload.getSizeMax()+"bytes!");    
    }

    1.其中需要注意的是流的操作,和File类的操作,mkdirs()和mkdir()的区别是什么?它们都是用来创建文件夹的,区别在mkdirs能创建多级目录,而mkdir()只能创建当前的文件夹,如果发现上一层目录并还没有创建时,它也会无动于衷,什么也不干,也就不能创建当前文件夹,必须先要创建了上一级文件夹才可以。

    2.上面还有很多的问题需要解决,比如上传文件名的乱码问题,比如单表内容的乱码问题,比如上传文件同名问题,如果上传的文件很大,该如何进行处理,比如,放在同一级目录下的文件过多如何处理。每次都自己手动写输出流,将内容存到指定位置,太过麻烦,等等问题,现在写一个加强版,在解决上面所有的问题。

    3.上传文件名乱码问题:使用servletFileUpload.setHeaderEncoding("UTF-8");或者request.setCharacterEncoding("UTF-8")都可以

    4.表单内容乱码问题:使用getString("utf-8")即可,也就是在获取内容时,就可以设置码表。

    5.上传文件同名问题:使用UUID.randomUUID().toString().replace("-", "").获得一个独一无二的32位数字

    6.使用FileUtils.copyInputStreamToFile(is, file);来将内容输出到指定路径文件中去,mkdirs() 自动创建目录

    7.同一级目录下的文件过多问题:创建多级目录,通过文件名的hashcode的值,hashCode为int型,占4个字节,一个字节占8位,也就是占32位,将其分组,4位4位一组,就能分8组,每一次代表一层目录,也就能够分8层目录,每一层中,有可以创建16种不同的文件夹。这样算下来,就能有很多很多个文件夹了,每个文件夹下面都可以存很多文件,看我们的业务需求,来决定要创建几层目录,就从hashcode中拿几组数据出来。原理图如下

                

     生成两级目录
    public class StringUtils {
    
        /**
         * 生成二级目录
         * @param fileName  abc.txt
         * @return  /4/5
         */
        public static String getDir(String fileName) {
            //1 hashCode值
            int hashCode = fileName.hashCode();
            System.out.println(hashCode);
            //2 第一层 0xf表示15的16进制数。
            int dir1 = hashCode & 0xf;
            //3 第二层目录
            int dir2 = hashCode >>> 4 & 0xf;
            
            //4 拼写
            return "/" + dir1 + "/" + dir2;
        }
        
        public static void main(String[] args) {
            System.out.println(getDir("abc.txt"));
        }
    
    }

    总结上传:

            其实理解了也不是很难,就是上传文件后的处理比较麻烦,各种小问题,存储过程最为麻烦。

            1、创建工厂类

            2、使用核心类,

            3、解析request请求,

            4、遍历请求体的内容,将上传内容和普通表单内容都获取出来

            5、获取到上传内容时,对其存储位置进行设置

            其中很多细节问题都在上面已经说清楚了,代码中也有很多注释。

  • 相关阅读:
    kaggle CTR预估
    基于大规模语料的新词发现算法【转自matix67】
    vim E437: terminal capability "cm" required
    makefile 中的符号替换($@、$^、$<、$?)
    【转】Makefile 中:= ?= += =的区别
    python urljoin问题
    python 写文件刷新缓存
    python Popen卡死问题
    nohup 日志切割
    换行和回车野史
  • 原文地址:https://www.cnblogs.com/lukelook/p/11066059.html
Copyright © 2020-2023  润新知