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. 多部件表单体

  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:\files\a.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 之文件上传的更多相关文章

  1. JavaWeb:实现文件上传

    JavaWeb:实现文件上传 理解文件上传: 1.上传文件就是把客户端的文件发送给服务器端. 2.HTTP响应的正文部分最常见的是HTML文档,但是也可以是其他任意格式的数据,如图片和声音文件中的数据 ...

  2. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  3. JavaWeb:实现文件上传与下载

    JavaWeb:实现文件上传与下载 文件上传前端处理 本模块使用到的前端Ajax库为Axio,其地址为GitHub官网. 关于文件上传 上传文件就是把客户端的文件发送给服务器端. 在常见情况(不包含文 ...

  4. JavaWeb实现文件上传下载功能实例解析 (好用)

    转: JavaWeb实现文件上传下载功能实例解析 转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web ...

  5. 使用传统javaweb进行文件上传

    使用传统文件上传方式 1.配置依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sou ...

  6. JavaWeb多文件上传及zip打包下载

    项目中经常会使用到文件上传及下载的功能.本篇文章总结场景在JavaWeb环境下,多文件上传及批量打包下载功能,包括前台及后台部分.  首先明确一点:  无法通过页面的无刷新ajax请求,直接发下载.上 ...

  7. 深入分析JavaWeb Item40 -- 文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是很经常使用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传.浏览器在上传的过程中是将文件以流的形式提交到server端的.假设 ...

  8. javaweb大文件上传

    本文主要关于利用html表单上传文件的后台代码实现. 需要用到两个工具类Apache commons-fileupload和commons-io. 注意要校验是否选择文件上传,最开始写的时候没有加上校 ...

  9. javaWeb实现文件上传与下载 (转)

    文件上传概述 实现web开发中的文件上传功能,需完成如下二步操作: 在web页面中添加上传输入项 在servlet中读取上传文件的数据,并保存到本地硬盘中. 如何在web页面中添加上传输入项? < ...

随机推荐

  1. 【MyBatis学习09】高级映射之一对多查询

    上一篇博文总结了一下一对一的映射,本文主要总结一下一对多的映射,从上一篇文章中的映射关系图中可知,订单项和订单明细是一对多的关系,所以本文主要来查询订单表,然后关联订单明细表,这样就有一对多的问题出来 ...

  2. Mac OS X中配置Apache后提示You don't have permission to access / on this server

    根据这篇博客http://www.cnblogs.com/snandy/archive/2012/11/13/2765381.html,在mac系统中,配置的apache,配置完成后,提示 You d ...

  3. 04-1下载Win系统(装机助理)

    下载Win系统(装机助理): http://www.zhuangjizhuli.com/upan.html http://www.krlxx.com/64win7.html 选择你需要安装的系统: 以 ...

  4. C++语言基础(1)-命名空间

    一个中大型软件往往由多名程序员共同开发,会使用大量的变量和函数,当有两个人都同时定义了一个名字相同的全局变量或函数的时候,若是把他们的代码整合在一块编译,此时编译器就会提示变量或函数重复定义,C++为 ...

  5. Redis提供商配置ASP.NET会话状态

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Co ...

  6. match函数

    match(s, r [, a]) Return the position in s where the regular expression r occurs, or 0 if r is not p ...

  7. vm中安装ubuntu16

    安装完成后,开机出现 smbus host controller not enabled 上网照着网友的建议: 在grub界面选择高级选项 root shell 进入到shell之后 mount -o ...

  8. CS项目总结

    最近做了近一年的CS项目终于接近完工了,有一种脱离苦海,跳出泥潭的感觉.虽然此项目做的很不理想,但它却给了我颇多感受,许多经验教训值得总结. 1.总的技术解决方案大方向上选择的不合适,导致后期对新的需 ...

  9. IRQ与FIQ的区别

    1.对FIQ你必须进快处理中断请求,并离开这个模式. 2.IRQ可以被FIQ所中断,但FIQ不能被IRQ所中断,在处理FIQ时必须要关闭中断. 3.FIQ的优先级比IRQ高. 4.FIQ模式下,比IR ...

  10. 大数据(6) - MapReduce简易介绍入门

    一 MapReduce入门 MapReduce定义(简单来说就是hadoop的数据分析核心,理解其中的原理,则可以分析聚合一切需求) Mapreduce是一个分布式运算程序的编程框架,是用户开发“基于 ...