JavaEE组件commons-fileupload实现文件上传、下载_java

一、文件上传概述

实现Web开发中的文件上传功能,需要两步操作:

1、在Web页面中添加上传输入项

    <form action="#" method="post" enctype="multipart/form-data">
      <input type="file" name="filename1"/><br>
      <input type="file" name="filename2"/><br>
      <input type="submit" value="上传"/>
    <form>
    <!-- 1、表单方式必须是post
      2、必须设置encType属性为 multipart/form-data.设置该值后,浏览器在上传文件时,将会把文件数据附带在http请求消息体中,
        并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
      3、必须要设置input的name属性,否则浏览器将不会发送上传文件的数据。
    -->

2、在Servlet中读取文件上传数据,并保存到服务器硬盘

Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在Servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作。

比如下面是截取的浏览器上传文件时发送的请求的HTTP协议中的部分内容:        

Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
Content-Type: multipart/form-data; boundary=---------------------------7dfa01d1908a4
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
Content-Length: 653
Host: localhost:8080
Connection: Keep-Alive
Pragma: no-cache
Cookie: JSESSIONID=11CEFF8E271AB62CE676B5A87B746B5F
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="username"
zhangsan
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="userpass"
1234
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="filename1"; filename="C:\Users\ASUS\Desktop\upload.txt"
Content-Type: text/plain
this is first file content!
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="filename1"; filename="C:\Users\ASUS\Desktop\upload2.txt"
Content-Type: text/plain
this is Second file content!
hello
-----------------------------7dfa01d1908a4--

 从上面的数据中也可以看出,如果自己手工的去分割读取数据很难写出健壮稳定的程序。所以,为方便用户处理上传数据,Apache开源组织提供了一个用来处理表单文件上传的一个开源组件(Commons-fileupload),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。

 需要导入两个jar包:Commons-fileupload、commons-io

response.setContentType("text/html;charset=utf-8");//设置响应编码
    request.setCharacterEncoding("utf-8");
    PrintWriter writer = response.getWriter();//获取响应输出流

    ServletInputStream inputStream = request.getInputStream();//获取请求输入流

    /*
     * 1、创建DiskFileItemFactory对象,设置缓冲区大小和临时文件目录
     *  该类有两个构造方法一个是无参的构造方法,
     *  另一个是带两个参数的构造方法
     * @param int sizeThreshold,该参数设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时,fileupload组件将使用临时文件缓存上传文件
     * @param java.io.File repository,该参数指定临时文件目录,默认值为System.getProperty("java.io.tmpdir");
     *
     *  如果使用了无参的构造方法,则使用setSizeThreshold(int sizeThreshold),setRepository(java.io.File repository)
     *  方法手动进行设置
     */
    DiskFileItemFactory factory = new DiskFileItemFactory();

    int sizeThreshold=1024*1024;
    factory.setSizeThreshold(sizeThreshold);

    File repository = new File(request.getSession().getServletContext().getRealPath("temp"));
//    System.out.println(request.getSession().getServletContext().getRealPath("temp"));
//    System.out.println(request.getRealPath("temp"));
    factory.setRepository(repository);

    /*
     * 2、使用DiskFileItemFactory对象创建ServletFileUpload对象,并设置上传文件的大小
     *
     *  ServletFileUpload对象负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem
     *  该对象的常用方法有:
     *      boolean isMultipartContent(request);判断上传表单是否为multipart/form-data类型
     *      List parseRequest(request);解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合
     *      void setFileSizeMax(long filesizeMax);设置单个上传文件的最大值
     *      void setSizeMax(long sizeMax);设置上传温江总量的最大值
     *      void setHeaderEncoding();设置编码格式,解决上传文件名乱码问题
     */
    ServletFileUpload upload = new ServletFileUpload(factory);

    upload.setHeaderEncoding("utf-8");//设置编码格式,解决上传文件名乱码问题
    /*
     * 3、调用ServletFileUpload.parseRequest方法解析request对象,得到一个保存了所有上传内容的List对象
     */
    List<FileItem> parseRequest=null;
    try {
       parseRequest = upload.parseRequest(request);
    } catch (FileUploadException e) {
      e.printStackTrace();
    }
    /*
     * 4、对list进行迭代,每迭代一个FileItem对象,调用其isFormField方法判断是否是文件上传
     *  true表示是普通表单字段,则调用getFieldName、getString方法得到字段名和字段值
     *  false为上传文件,则调用getInputStream方法得到数据输入流,从而读取上传数据
     *
     *  FileItem用来表示文件上传表单中的一个上传文件对象或者普通的表单对象
     *  该对象常用方法有:
     *     boolean isFormField();判断FileItem是一个文件上传对象还是普通表单对象
     *     true表示是普通表单字段,
     *         则调用getFieldName、getString方法得到字段名和字段值
     *     false为上传文件,
     *         则调用getName()获得上传文件的文件名,注意:有些浏览器会携带客户端路径,需要自己减除
     *         调用getInputStream()方法得到数据输入流,从而读取上传数据
     *         delete(); 表示在关闭FileItem输入流后,删除临时文件。
     */

    for (FileItem fileItem : parseRequest) {
      if (fileItem.isFormField()) {//表示普通字段
        if ("username".equals(fileItem.getFieldName())) {
          String username = fileItem.getString();
          writer.write("您的用户名:"+username+"<br>");
        }
        if ("userpass".equals(fileItem.getFieldName())) {
          String userpass = fileItem.getString();
          writer.write("您的密码:"+userpass+"<br>");
        }

      }else {//表示是上传的文件
        //不同浏览器上传的文件可能带有路径名,需要自己切割
        String clientName = fileItem.getName();
        String filename = "";
        if (clientName.contains("\\")) {//如果包含"\"表示是一个带路径的名字,则截取最后的文件名
          filename = clientName.substring(clientName.lastIndexOf("\\")).substring(1);
        }else {
          filename = clientName;
        }

        UUID randomUUID = UUID.randomUUID();//生成一个128位长的全球唯一标识

        filename = randomUUID.toString()+filename;

        /*
         * 设计一个目录生成算法,如果所用用户上传的文件总数是亿数量级的或更多,放在同一个目录下回导致文件索引非常慢,
         * 所以,设计一个目录结构来分散存放文件是非常有必要,且合理的
         * 将UUID取哈希算法,散列到更小的范围,
         * 将UUID的hashcode转换为一个8位的8进制字符串,
         * 从这个字符串的第一位开始,每一个字符代表一级目录,这样就构建了一个八级目录,每一级目录中最多有16个子目录
         * 这无论对于服务器还是操作系统都是非常高效的目录结构
         */
        int hashUUID =randomUUID.hashCode();
        String hexUUID = Integer.toHexString(hashUUID);
        //System.out.println(hexUUID);
        //获取将上传的文件存存储在哪个文件夹下的绝对路径
        String filepath=request.getSession().getServletContext().getRealPath("upload");
        for (char c : hexUUID.toCharArray()) {
          filepath = filepath+"/"+c;
        }
        //如果目录不存在就生成八级目录
        File filepathFile = new File(filepath);
        if (!filepathFile.exists()) {
          filepathFile.mkdirs();
        }
        //从Request输入流中读取文件,并写入到服务器
        InputStream inputStream2 = fileItem.getInputStream();
        //在服务器端创建文件
        File file = new File(filepath+"/"+filename);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));

        byte[] buffer = new byte[10*1024];
        int len = 0;
        while ((len= inputStream2.read(buffer, 0, 10*1024))!=-1) {
          bos.write(buffer, 0, len);
        }
        writer.write("您上传文件"+clientName+"成功<br>");
        //关闭资源
        bos.close();
        inputStream2.close();
      }
    }
  //注意Eclipse的上传的文件是保存在项目的运行目录,而不是workspace中的工程目录里。

 二、文件上传需要特别注意的问题: (这些问题在上面的代码中都提供了简单的解决)

1、文件存放的位置

为保证服务器的安全,上传文件应保存在应用程序的WEB-INF目录下,或者不受WEB服务器管理的目录,如果用户上传一个带有可执行代码的文件,如jsp文件,根据拼接访问路径去访问的话,可以在服务器端做任何事情。

2、为防止多用户上传形同文件名的文件,而导致文件覆盖的情况发生,文件上传程序应保证上传文件具有唯一文件名

使用UUID + 用户上传文件名的方式重命名

关于UUID:
UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。

是一个128位长的数字,一般用16进制表示。算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID。从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)3240年不重复。

从JDK1.5开始,生成UUID变成了一件简单的事,以为JDK实现了UUID:

java.util.UUID,直接调用即可.
UUID uuid  =  UUID.randomUUID();
String s = UUID.randomUUID().toString();//用来生成数据库的主键id非常不错。。 
 
UUID是由一个十六位的数字组成,表现出来的形式例如
550E8400-E29B-11D4-A716-446655440000 

3、为防止单个目录下文件过多,影响文件读写速度,处理上传文件的程序应该应根据可能的上传总量,选择合适的目录结构生成算法,将上传文件分散存储。如使用hashcode方法构建多级目录。

4、如果不同用户都上传了相同的文件,那么在服务器端没有必要存储同一个文件的很多分拷贝,这样很浪费资源,应该设计算法解决这种重复文件的问题。

5、JSP技术原理自动实现了多线程。所以开发者不需要考虑上传文件的多线程操作 

三、文件下载 

<%
    ArrayList<String> fileNames = new ArrayList<String>();
    fileNames.add("file/aa.txt");
    fileNames.add("file/bb.jpg");
    for(String fileName : fileNames) {
   %>

    <form action="DownloadServlet" method="get">
      <input type="hidden" name="fileName" value="<%=fileName %>" />
      <input type="submit" value="下载:<%=fileName %>" />
    </form>
   <%
    }
   %>

    request.setCharacterEncoding("utf-8");

    String filename = request.getParameter("fileName");

    String urlname = URLEncoder.encode(filename, "utf-8");//防止文件名中有中文乱码
    response.setHeader("Content-Disposition","attachment;filename="+urlname);

    FileInputStream fis = new FileInputStream(new File(request.getSession().getServletContext().getRealPath(filename)));
    BufferedInputStream bis = new BufferedInputStream(fis);
    ServletOutputStream sos = response.getOutputStream();

    byte[] buffer = new byte[1024];
    int len=0;
    while((len=bis.read(buffer, 0, 1024))!=-1){
      sos.write(buffer, 0, len);
    }
    bis.close();
    fis.close();

四、在SSH中使用smartUpload组件简化文件上传下载

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javaee
, 文件上传
, 文件下载
, fileupload
commons
commons fileupload、commons fileupload包、commons—fileupload、commonsfileupload、fileupload组件,以便于您获取更多的相关知识。

时间: 2024-10-31 20:33:15

JavaEE组件commons-fileupload实现文件上传、下载_java的相关文章

Java组件commons fileupload实现文件上传功能_java

Apache提供的commons-fileupload jar包实现文件上传确实很简单,最近要用Servlet/JSP做一个图片上传功能,在网上找了很多资料,大多是基于struts框架介绍的,还有些虽然也介绍common-fileupload的上传,但是那些例子比较老,有些类现在都废弃了. 通过研究学习总结,终于完成了这个上传功能,下面与大家分享一下. 案例场景 一个图书馆后台管理界面,需要提供上传图书图片的功能并且最终显示在页面中. 实现效果 进入添加书籍页面,默认显示一个图片"暂无突破&qu

Apache Commons fileUpload实现文件上传之一_java

废话不多说了,直奔主题了. 需要两个jar包: commons-fileupload.jar Commons IO的jar包(本文使用commons-io-2.4.jar) 利用Servlet来实现文件上传. package web.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.

commons fileupload实现文件上传的实例代码_java

一.文件上传的原理分析 1.文件上传的必要前提 a.表单的method必须是post b.表单的enctype属性必须是multipart/form-data类型的. enctype默认值:application/x-www-form-urlencoded 作用:告知服务器,请求正文的MIME类型 application/x-www-form-urlencoded : username=abc&password=123 ServletRequest.getParameter(String nam

利用ssh实现服务器文件上传下载_java

通过ssh实现服务器文件上传下载 写在前面的话 之前记录过一篇使用apache的FTP开源组件实现服务器文件上传下载的方法,但是后来发现在删除的时候会有些权限问题,导致无法删除服务器上的文件.虽然在Windows上使用FileZilla Server设置读写权限后没问题,但是在服务器端还是有些不好用. 因为自己需要实现资源管理功能,除了单文件的FastDFS存储之外,一些特定资源的存储还是打算暂时存放服务器上,项目组同事说后面不会专门在服务器上开FTP服务,于是改成了sftp方式进行操作. 这个

Java FTPClient实现文件上传下载_java

在JAVA程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件,本文简单介绍如何利用jakarta commons中的FTPClient(在commons-net包中)实现上传下载文件.所用到的jar包有:  commons-net-1.4.1.jar  jakarta-oro.jar  一.上传文件 文件上传源代码 /** * Description: 向FTP服务器上传文件 * @Version1.0 * @param url FTP服务器hostname * @param

Apache Commons fileUpload实现文件上传

将Apache的commons-fileupload.jar放在应用程序的WEB-INF\lib下,即可使用.下面举例介绍如何使用它的文件上传功能. 所使用的fileUpload版本为1.2,环境为Eclipse3.3+MyEclipse6.0.FileUpload 是基于 Commons IO的,所以在进入项目前先确定Commons IO的jar包(本文使用commons-io-1.3.2.jar)在WEB-INF\lib下. 此文作示例工程可在文章最后的附件中下载. 示例1 最简单的例子,通

用fileupload组件实现的大文件上传简单实例_JSP编程

1.FileUploadServlet.java文件,实现上传处理 import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servl

JavaEE中struts2实现文件上传下载功能实例解析_java

本文实例为大家分享了struts2实现文件上传下载的具体实现代码,供大家参考,具体内容如下 一.文件上传 struts提交的文件组件上传, 前台: 1).提交方式POST 2).表单类型 multipart/form-data 3).input type=file 后台: Apache提供的FileUpload组件 核心类: FileItemFactory FileItem的工厂 ServletFileUpload servlet 中的文件上传的核心类 FileItem 封装了上传的表单文件项的

AJAX+JSF组件 实现高性能的文件上传

一. 引言 基于浏览器的文件上传,特别是对于通过<input type="file">标签包含到Web页面来实现上传的情况,还存在较严重的性能问题.我们知道,超过10MB的上传文件经常导致一种非常痛苦的用户体验.一旦用户提交了文件,在浏览器把文件上传到服务器的过程中,界面看上去似乎处于静止状态.由于这一切发生在后台,所以许多没有耐心的用户开始认为服务器"挂"了,因而再次提交文件,这当然使得情况变得更糟糕. 为了尽可能使得文件上传感觉更友好些,一旦用户提交

JavaWeb中struts2实现文件上传下载功能实例解析_java

在做B/S系统时,通常会涉及到上传文件和下载文件,在没接struts2框架之前,我们都是使用apache下面的commons子项目的FileUpload组件来进行文件的上传,但是那样做的话,代码看起来比较繁琐,而且不灵活,在学习了struts2后,struts2为文件上传下载提供了更好的实现机制,在这里我分别就单文件上传和多文件上传的源代码进行一下讲解,这里需要导入文件下载上传的两个jar文件,一个是commons-fileupload-1.2.2.jar,另一个是commons-io-2.0.