JavaWeb 之文件上传

摘要:
FileUploadBase.FileSizeLimitExceedeException.整个请求所有数据大小限制sfu.setSizeMax:表示限制整个表单大小为1M;必须在parseRequest()方法之前调用;如果上传的文件超出限制,在parseRequest()方法执行时,会抛出异常!!FileUploadBase.SizeLimitExceededException.5.5缓存大小与临时目录缓存大小:上传文件超出多大时,才向硬盘保存!=-1){filename=filename.substring;}//给文件名添加uuid前缀,处理文件同名问题Stringsavename=Comm

1. 文件上传的要求

1.1 上传对表单的限制

  • method="post";
  • enctype="multipart/form-data";
  • 表单中需要添加文件表单项: <input type="file" name="xxx"/>.

1.2 上传对 Servlet 的限制

  • request.getParameter("xxx") 方法返回的是字符串类型, 所以在表单中有
    enctype="multipart/form-data"时, 该方法作废了, 因为它永远都返回 null.
  • 应该使用 ServletInputStream request.getInputStream(), 返回结果中包含整个请求体.
  • 上传不能使用 BaseServlet,因为BaseServlet 内部调用了 getParameter() 方法.

2. 多部件表单体

JavaWeb 之文件上传第1张

  1. 一个表单被分割出多个部件,即一个表单项一个部件;
  2. 一个部件中自己包含请求头和空行, 以及请求体;
  3. 普通表单项
    • 包含一个请求头: Content-Disposition:xxx; name="表单项名称";
    • 请求体就是表单项的值.
  4. 文件表单项
    • 包含两个请求头:
    • Content-Disposition:xxx; name="表单项名称"; filename="上传文件的名称";
    • Content-Type: 上传文件的 MIME 类型;
    • 请求体就是上传文件的内容.

3. 相关 jar 包

  • commons-fileupload.jar
  • commons-io.jar
  • 这个组件会解析 request 中的上传数据, 解析后的结果是,一个表单项数据封装到一个 FileItem 对象中.
    我们只需要调用 FileItem 的方法即可.

4. 上传三步

4.1 上传涉及的相关类

  • 工厂类: DiskFileItemFactory;
  • 解析器类: ServletFileUpload;
  • 表单项类: FileItem;

4.2 具体步骤

  • 创建工厂: DiskFileItemFactory factory = new DiskFileItemFactory();
  • 创建解析器: ServletFileUpload sfu = new ServletFileUpload(factory);
  • 使用解析器来解析 request, 得到FileItem集合: List<FileItem> fileItemList = sfu.parseRequest(request);

4.3 FileItem 对象中的方法 (commons-fileupload API)

  • boolean isFormField(): 是否为普通表单项. true,表示为普通表单项; false,表示为文件表单项;
  • String getFieldName(): 返回当前表单项的名称;
  • String getString(String charset): 返回表单项的值, charset 默认值为 "utf-8";
  • String getName(): 返回上传文件的名称;
  • long getSize(): 返回上传文件的字节数;
  • InputStream getInputStream(): 返回上传文件对应的输入流;
  • void write(File destFile): 把上传文件的内容保存到指定的文件中;
  • String getContentType(): 获取上传文件的 MIME 类型;

5. 上传的细节

5.1 文件必须保存到 WEB-INF 下!

  • 目的是不让浏览器直接访问到.

5.2 文件名称相关问题

  1. IE6 浏览器上传的文件名称是绝对路径(包含磁盘的路径),需要将磁盘部分切割, 例如: "c:filesa.jpg";
  2. 文件名乱码或普通表单项乱码:
    • request.setCharacterEncoding("utf-8"), fileupload 内部会调用 request.getCharacterEncoding()方法;
    • servletFileUpload.setHeaderEncoding("utf-8"), 这种方式的优先级高于前一种.
  3. 文件同名问题: 需要为每个文件添加名称前缀, 为了保证不重复, 可以使用 uuid
    • filename = CommonUtils.uuid()+"_"+filename;

5.3 目录打散

  1. 不能在一个目录下存放过多文件
    • 首字母打散: 使用文件的首字母作为目录名称; 不方便操作中文的文件名
    • 时间打散: 使用当前日期作为目录;
    • 哈希打散:
      • 通过文件名称获得 int 值, 即调用 hashCode();
      • 把 int 值转换成十六进制 "0~9 和 A ~ F";
      • 获取十六进制的前两位用来生成目录, 目录为两层! 例如: "1B2C3D4E5F", /1/B 保存文件.

5.4 上传文件的大小限制

  1. 单个文件的大小限制

    • sfu.setFileSizeMax(100 * 1024): 表示限制单个文件大小为 100K;
    • 必须在 parseRequest() 方法之前调用;
    • 如果上传的文件超出限制, 在 parseRequest() 方法执行时, 会抛出异常!!
      FileUploadBase.FileSizeLimitExceedeException.
  2. 整个请求所有数据大小限制

    • sfu.setSizeMax(1024 * 1024): 表示限制整个表单大小为 1M;
    • 必须在 parseRequest() 方法之前调用;
    • 如果上传的文件超出限制, 在 parseRequest() 方法执行时, 会抛出异常!!
      FileUploadBase.SizeLimitExceededException.

5.5 缓存大小与临时目录

  • 缓存大小: 上传文件超出多大时, 才向硬盘保存! 默认 10KB;
  • 临时目录: 向硬盘的什么目录保存;
  • 设置缓存大小和临时目录: new DiskFileItemFactory(20 * 1024, new File("F:/temp"))
// 目录打散
    public void UploadServlet extends HttpServlet{

        public void doPost(HttpServletRequest request, HttpServletResponse resp)
                throws ServletException, IOException{

            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;utf-8");

            // 文件上传三步
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload sfu = new ServletFileUpload(factory);

            try{
                List<FileItem> fileItemList = sfu.parseRequest(request);

                // 获取照片文件表单项
                FileItem fi = fileItemList.get(1);

                // 得到保存上传文件的根路径
                String root = this.getServletContext().getRealPath("/WEB-INF/files/");

                // 得到文件名
                String filename = fi.getName();

                //处理文件名的绝对路径问题
                int index = filename.lastIndexOf("\");
                if(index != -1){
                    filename = filename.substring(index+1);
                }

                // 给文件名添加 uuid 前缀, 处理文件同名问题
                String savename = CommonUtils.uuid()+"_"+filename;

                // 得到文件名的 hashCode, 生成两层目录
                int hCode = filename.hashCode();
                String hex = Integer.toHexString(hCode);

                File dirFile = new File(root,hex.charAt(0)+"/"+hex.charAt(1));

                // 如果目录不存在, 创建目录链
                dirFile.mkdirs();

                // 创建目标文件
                File destFile = new File(dirFile,savename);

                // 保存
                fi.save(destFile);

            }catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    }

参考资料:

免责声明:文章转载自《JavaWeb 之文件上传》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇在chrome中的source找不到自己写的js时处理方法Python打开文件报错SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated UXXXXXXXX escape下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Qt 之 pro 配置详解

原文地址:https://blog.csdn.net/liang19890820/article/details/51774724 简述 使用Qt的时候,我们经常会对pro进行一系列繁琐的配置,为方便大家理解、查找,现将常用的配置进行整理。 |版权声明:一去、二三里,未经博主允许不得转载。 配置 注释 以“#”开始,到这一行结束。快捷键:Ctrl +...

高可用的Spring FTP上传下载工具类(已解决上传过程常见问题)

前言 最近在项目中需要和ftp服务器进行交互,在网上找了一下关于ftp上传下载的工具类,大致有两种。 第一种是单例模式的类。 第二种是另外定义一个Service,直接通过Service来实现ftp的上传下载删除。 这两种感觉都有利弊。 第一种实现了代码复用,但是配置信息全需要写在类中,维护比较复杂。 第二种如果是spring框架,可以通过propertis...

Mac上zip,rar,tar文件命令解压和压缩

经常遇到在windowns上的压缩文件,在mac上解压出现问题,特意总结了下在Terminal里常用命令的方式解压和压缩文件 1、zip压缩文件 zip命令的参数很多,可以利用"zip --help"查看,在这里就不在一一说明了,下面只说几个常用的 zip -q -r -e -m -o 'yourName.zip' "zipfile list''-q :不...

《马哥出品高薪linux运维教程》wingkeung学习笔记-linux基础入门课程

计算机原理概念: 1、CPU和内存中的存储单元通信线路称为总线(BUS),总线是被指令和数据复用的,所以也称为前端总线。 2、计算机中计算频率的时间标准即晶体振荡器原理,精确计算时间长度,根据相同的时间统计变化的次数,即保持时钟同步。 3、每一个芯片在厂家生产时都有一个以微码(汇编语言)形式存在内置接口,完成一定意义上的智能操作。 4、CPU中控制器在未从...

获取任何小程序源码

只需两步获取任何小程序源码  这种方法,并不能反编译出所有的小程序源码,请自知! 具体的局限请看:qwerty472123大神的md文件https://github.com/qwerty472123/wxappUnpacker 下面是原文:   最近在学习微信小程序开发,半个月学习下来,很想实战一下踩踩坑,于是就仿写了一个滴滴他们家的青桔单车小程序的...

CentOS 6.3下Samba服务器的安装与配置方法(图文详解)

这篇文章主要介绍了CentOS 6.3下Samba服务器的安装与配置方法(图文详解),需要的朋友可以参考下 一、简介Samba是一个能让Linux系统应用Microsoft网络通讯协议的软件,而SMB是Server Message Block的缩写,即为服务器消息块 ,SMB主要是作为Microsoft的网络通讯协议,后来Samba将SMB通信协议应用到...