Java进阶学习第二十二天——上传与下载

Posted 鹿天斐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进阶学习第二十二天——上传与下载相关的知识,希望对你有一定的参考价值。

文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.06.05 lutianfei none

  • Servlet规范中
    • servlet有初始化参数
    • Filter有初始化参数
    • Listener没有初始化参数,要使用,在开发中一般使用<context-param> servletContext的初始化参数.

文件上传

  • 问题:什么是文件上传?为什么使用文件上传?

    • 就是将客户端资源,通过网络传递到服务器端。
    • 就是因为数据比较大,我们必须通过文件上传才可以完成将数据保存到服务器端操作。
  • 文件上传的本质:就是IO流的操作。

  • 实现web开发中的文件上传功能,需完成如下二步操作:

    • 在web页面中添加上传输入项
    • 在servlet中读取上传文件的数据,并保存到服务器硬盘中
  • 如何在web页面中添加上传输入项?

    • <input type=“file”>标签用于在web页面中添加文件上传输入项,设置文件上传输入项时须注意:
      • 1、必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
      • 2、必须把formenctype属值设为multipart/form-data。设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIMIE协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
      • 3、表单的提交方式要是post
  • 如何在Servlet中读取文件上传数据,并保存到本地硬盘中?

    • Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作。
    • 为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
  • 使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileuploadcommons-io

    • commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持。


文件上传步骤

1.导入jar包
  • commons-fileupload-1.2.1.jar : 文件上传
  • commons-io-1.4.jar : 它是提供的io工具.
  • commons-fileupload 它有三个核心
    • 1.DiskFileItemFactory类
    • 2.ServletFileUpload类
    • 3.FileItem
2.快速入门
  • 1.创建upload2.jsp页面
<form action="${pageContext.request.contextPath}/upload2" method="post" encType="multipart/form-data">
    <input type="file" name="f"><br>
    <input type="submit" value="上传">
</form>


  • 2.创建Upload2Servlet
    • 1.创建一个 DiskFileItemFactory,设置缓冲区大小临时文件目录
      • DiskFileItemFactory factory=new DiskFileItemFactory();
    • 2.创建 ServletFileUpload类,设置上传文件的大小限制。
      • ServletFileUpload upload=new ServletFileUpload(factory);
    • 3.解析所有上传数据,调用ServletFileUpload.parseRequest方法解析request对象,得到一个保存了所有上传内容的List对象
      • List<FileItem> items = upload.parseRequest(request);


  • 3.遍历items集合,集合中的每一项,就是一个上传数据

    • 1.isFormField();
      • True普通表单字段,则调用 getFieldNamegetString 方法得到字段名字段值
      • False上传文件,则调用 getInputStream 方法得到* 数据输入流*,从而读取上传数据。
    • 2.getFieldName();
      • 返回值String,得到组件名称 <input name="">
    • 3.getName();
      • 返回值是String,得到的是上传文件的名称.
      • 注意:浏览器不同,它们得到的效果不一样。
        • 1.包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
        • 2.只包含上传文件名称 例如:a.txt
    • 4.getString();
      • 这个方法可以获取非上传组件的内容,相当于getParameter方法作用。 如果是上传组件,上传的文件是文本文件,可以获取到文件文件的内容。但是如果不是文本文件,则无法正确传输。
    • 5.获取上传文件的内容,保存到服务器端.
      • item.getInputStream();它是用于读取上传文件内容的输入流。
      • 使用文件复制操作就可以完成文件上传。
        • IOUtils.copy(item.getInputStream(), fos);
  • fileupload组件工作流程
    技术分享


FileUpload上传操作核心API

技术分享


  • 获取temp目录部署到tomcat后的绝对磁盘路径的技巧

    • File file = new File(this.getServletContext().getRealPath("/temp"));
  • 1.DiskFileItemFactory 磁盘文件项工厂类,是创建 FileItem 对象的工厂:

    • 作用:可以设置缓存大小以及临时文件保存位置
    • 默认缓存大小是 10240(10k).
    • 临时文件默认存储在系统的临时文件目录下.(可以在环境变量中查看)
    • 1.new DiskFileItemFactory();
      • 缓存大小与临时文件存储位置使用默认的
    • 2.DiskFileItemFactory(int sizeThreshold, File repository)
      • sizeThreshold :缓存大小
      • repository:临时文件存储位置
    • 注意,对于无参数构造,也可以设置缓存大小以及临时文件存储位置
      • setSizeThreshold(int sizeThreshold)
      • setRepository(File repository)
    • 内存缓冲区: 上传文件时,上传文件的内容优先保存在内存缓冲区中,当上传文件大小超过缓冲区大小,就会在服务器端产生临时文件
    • 临时文件存放位置: 保存超过了内存缓冲区大小上传文件而产生临时文件
    • 产生临时文件可以通过 FileItem的delete方法删除


  • 2.ServletFileUpload 文件上传核心类 ,负责处理上传的文件数据,并将表单中每个输入项封装成一个 FileItem 对象中。常用方法有:

    • static boolean isMultipartContent(javax.servlet.http.HttpServletRequest request) 判断是否是上传,即判断request的编码方式是否为multipart/form-data
    • java.util.List parseRequest(javax.servlet.http.HttpServletRequest request) 解析request,将请求体每个部分封装 FileItem对象,返回List<FileItem>
    • void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小
    • void setSizeMax(long sizeMax) 设置总文件上传大小
    • void setHeaderEncoding(java.lang.String encoding) 设置编码集 解决上传文件名乱码
    • setProgressListener(ProgressListener pListener)实时监听文件上传状态
    • ServletFileUpload(factory);创建一个上传工具,指定使用缓存区与临时文件存储位置.
  • 3、FileItem 表示文件上传表单中 每个数据部分,用来表示文件上传表单中的一个上传文件对象或者普通表单对象

    • boolean isFormField() 判断该数据项是否为文件上传项,true 不是文件上传 false 是文件上传
      • 如果判断是一个普通表单对象
        • String getFieldName() 获得普通表单对象的name属性<input name="">
        • String getString(String encoding) 获得普通表单对象的value属性,可以用encoding进行编码设置
      • 如果判断是一个文件上传对象
        • String getName() 获得上传文件的文件名(有些浏览器会携带客户端路径)
          • 注意:浏览器不同,它们得到的效果不一样。
            • 1.包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
            • 2.只包含上传文件名称 例如:a.txt
        • InputStream getInputStream() 获得上传文件的输入流
        • delete() 在关闭FileItem输入流后,删除临时文件
  • 总结:关于文件上传时的乱码问题:

    • 1.上传文件名称乱码
      • ServletFileUpload.setHeaderEncoding(“utf-8”);
    • 2.非上传组件内容乱码
      • FileItem.getString(“utf-8”);
    • 3.思考:上传文件信息是否会乱码,需要解决吗?
      • 不需要解决,因为我们在上传时,使用的字节流来进行复制。
if(fileItem.isFormField()){
   // 不是上传项
   java.lang.String getFieldName()  获得普通表单项name属性
   java.lang.String getString() / java.lang.String getString(java.lang.String encoding) 获得普通表单项value属性 传入编码集用来解决输入value乱码 
}else{
   // 是上传项
   java.lang.String getName() 获得上传文件名 (注意IE6存在路径)
   java.io.InputStream     getInputStream() 获得上传文件内容输入流
   // 上传文件
   void delete()  删除临时文件(删除时,必须要管理输入输出流)
}
  • 注意事项:因为文件上传表单采用编码方式multipart/form-data 与传统url编码不同,所有getParameter 方法不能使用 setCharacterEncoding 无法解决输入项乱码问题。


JavaScript的多文件上传表单

  • 技巧:
    • 每次动态增加一个文件上传输入框,都把它和删除按纽放置在一个单独的div中,并对删除按纽的onclick事件进行响应,使之删除删除按纽所在的div。
    • 如:this.parentNode.parentNode.removeChild(this.parentNode);

多文件上传

     <script type="text/javascript">

        function addFile(){
            var div=document.getElementById("content");

            div.innerhtml+="<div><input type=‘file‘ name=‘f‘><input type=‘button‘ value=‘remove file‘ onclick=‘removeFile(this)‘></div>";
        }

        function removeFile(btn){

            document.getElementById("content").removeChild(btn.parentNode);

        }
    </script>



  <body>

    <input type="button" value="add File" onclick="addFile();">
    <br>
    <br>
    <form action="${pageContext.request.contextPath}/upload4" method="post" encType="multipart/form-data">
        <input type="file" name="f"><br>
        <div id="content">
        </div>
        <input type="submit" value="上传">
    </form>
  </body>    
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        // 1.创建 DiskFileItemFactory
        File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径
        DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file); // 使用默认的.

        // 2.创建ServletFileUpload
        ServletFileUpload upload = new ServletFileUpload(factory);
        boolean flag = upload.isMultipartContent(request); // 用于判断是否是上传操作.
        if (flag) {
            // 解决上传文件名称中文乱码
            upload.setHeaderEncoding("utf-8");

            // 设置上传文件大小
            // upload.setSizeMax(1024 * 1024 * 10);// 总大小为10m

            try {
                List<FileItem> items = upload.parseRequest(request);// 解决request,得到所有的上传项FileItem

                // 3.得到所有上传项
                for (FileItem item : items) {
                    if (!item.isFormField()) {
                        // 上传组件

                        String name = item.getName(); // 上传文件名称
                        // 得到上传文件真实名称

                        String filename = FileUploadUtils.getRealName(name);

                        // 得到随机名称
                        String uuidname = FileUploadUtils
                                .getUUIDFileName(filename);

                        // 得到随机目录
                        String randomDirectory = FileUploadUtils
                                .getRandomDirectory(filename);
                        // 注意:随机目录可能不存在,需要创建.
                        String parentPath = this.getServletContext()
                                .getRealPath("/upload");
                        File rd = new File(parentPath, randomDirectory);

                        if (!rd.exists()) {
                            rd.mkdirs();
                        }

                        IOUtils.copy(item.getInputStream(),
                                new FileOutputStream(new File(rd, uuidname)));

                        // 删除临时文件
                        item.delete();
                    }
                }

            } catch (FileUploadException e) {
                // e.printStackTrace();
                response.getWriter().write(e.getMessage());
                return;
            }
        } else {
            response.getWriter().write("不是上传操作");
            return;
        }
    }


上传文件存在的问题

上传文件在服务器端保存位置问题
  • 1.保存在可以被浏览器直接访问的位置

    • 例如:商城的商品图片
    • 保存在工程的WebRoot下的路径(不包含META-INF以及WEB-INF目录及其子目录)
  • 2.保存在不能被浏览器直接访问的位置

    • 例如:付费的视频。
    • 1.工程中 META-INFWEB-INF目录及其子目录
    • 2.不受tomcat服务器管理目录 例如: WebRoot/WEB-INF/upload 、c:\ 、d:\abc
上传文件在同一个目录重名问题
  • 如果文件重名,后上传文件就会覆盖先上传文件,在开发中解决这个问题,可以给上传文件起随机名称。

  • 文件名 UUID

    • filename = UUID.randomUUID().toString() + "_" + filename;
  • 为了防止同一个目录下方上传文件数量过多 —- 必须采用目录分离算法

    • 1) 按照上传时间进行目录分离 (周、月 )
    • 2) 按照上传用户进行目录分离 —– 为每个用户建立单独目录
    • 3) 按照固定数量进行目录分离 —— 假设每个目录只能存放3000个文件 ,每当一个目录存满3000个文件后,创建一个新的目录
    • 4) 按照唯一文件名的hashcode 进行目录分离
    public static String generateRandomDir(String uuidFileName) {
        // 获得唯一文件名的hashcode
        int hashcode = uuidFileName.hashCode();
        // 获得一级目录
        int d1 = hashcode & 0xf;       
        // 获得二级目录
        int d2 = (hashcode >>> 4) & 0xf;

        return "/" + d2 + "/" + d1;// 共有256目录l
    }


乱码问题
  • 普通编写项 value属性乱码: fileItem.getString(编码集);
  • 上传文件项 文件名乱码 : fileupload.setHeaderEncoding(编码集);


文件下载

  • 文件下载的方式:
    • 1.超连接下载
    • 2.服务器端通过流下载(服务器端编程)

超链接直接指向下载资源

  • 如果文件格式浏览器识别,将直接打开文件,显示在浏览器上, 如果文件格式浏览器不识别,将弹出下载窗口
  • 对于浏览器识别格式的文件,通过另存为进行下载

  • 客户端访问服务器静态资源文件时,静态资源文件是通过 缺省Servlet返回的,在tomcat配置文件conf/web.xml 找到 org.apache.catalina.servlets.DefaultServlet

  • eg:超连接下载

    download1.jsp
    <a href=‘${pageContext.request.contextPath}/upload/a.bmp‘>a.bmp</a><br>
    <a href=‘${pageContext.request.contextPath}/upload/a.doc‘>a.doc</a><br>
    <a href=‘${pageContext.request.contextPath}/upload/a.txt‘>a.txt</a><br>
    <a href=‘${pageContext.request.contextPath}/upload/tk.mp3‘>tk.mp3</a><br>


在服务器端编程完成下载

  • 编写服务器程序,读取服务器端文件,完成下载 必须设置两个头信息 ,来自MIME协议
    • Content-Type
    • Content-Disposition
response.setContentType(getServletContext().getMimeType(filename));
response.setHeader("Content-Disposition", "attachment;filename=" + filename); // 以附件形式打开,不管格式浏览器是否识别
  • 处理IE浏览器与Firefox浏览器乱码问题
if (agent.contains("MSIE")) {
                // IE浏览器
                filename = URLEncoder.encode(filename, "utf-8");
                filename = filename.replace("+", " ");
            } else if (agent.contains("Firefox")) {
                // 火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?"
                        + base64Encoder.encode(filename.getBytes("utf-8"))
                        + "?=";
            } else if (agent.contains("Chrome")) {
                // google浏览器
                filename = URLEncoder.encode(filename, "utf-8");
            } else {
                // 其它浏览器
                filename = URLEncoder.encode(filename, "utf-8");
  • 1.创建download2.jsp
        <a href=‘${pageContext.request.contextPath}/download?filename=a.bmp‘>a.bmp</a><br>
        <a href=‘${pageContext.request.contextPath}/download?filename=a.doc‘>a.doc</a><br>
        <a href=‘${pageContext.request.contextPath}/download?filename=a.txt‘>a.txt</a><br>
        <a href=‘${pageContext.request.contextPath}/download?filename=tk.mp3‘>tk.mp3</a><br>


  • 2.创建DownloadServlet
    // 1.得到要下载 的文件名称
    String filename = request.getParameter("filename");

    //2.判断文件是否存在
    File file = new File("d:/upload/" + filename);
    if (file.exists())

    //3.进行下载 
        原理:就是通过response获取一个输出流,将要下载的文件内容写回到浏览器端就可以了.
  • 注意:要想通过编程的方式,实现文件下载

    • 1.要设置mimetype类型
      • resposne.setContextType(String mimeType);
      • 问题:怎样可以得到要下载文件的mimeType类型?
        • ServletContext.getMimeType(String filename);
      • 如果设置了mimeType,浏览器能解析的就直接展示了,不能解析的,直接下载.
    • 2.设置一个响应头,设置后的效果,就是无论返回的是否可以被浏览器解析,就是下载 。
      • response.setHeader(“content-disposition”,”attachment;filename=下载文件名称”);
  • 总结:服务器端编程下载:

    • 1.将下载的文件通过resposne.getOutputStream()流写回到浏览器端。
    • 2.设置mimeType response.setContentType(getServletContext.getMimeType(String filename));
    • 3.设置响应头,目的是永远是下载操作
      • response.setHeader(“content-disposition”,”attachment;filename=下载文件名称”);
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 1.得到要下载 的文件名称
        String filename = request.getParameter("filename");

        filename = new String(filename.getBytes("iso8859-1"), "utf-8");// 解决中文乱码

        // 2.在d:/upload目录下查找这个文件是否存在
        File file = new File("d:/upload/" + filename);
        if (file.exists()) {
            // /文件存在,完成下载

            // 下载注意事项1--设置下载文件的mimeType
            String mimeType = this.getServletContext().getMimeType(filename);
            response.setContentType(mimeType);

            String agent = request.getHeader("user-agent");
            if (agent.contains("MSIE")) {
                // IE浏览器
                filename = URLEncoder.encode(filename, "utf-8");

            } else if (agent.contains("Firefox")) {
                // 火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?"
                        + base64Encoder.encode(filename.getBytes("utf-8"))
                        + "?=";
            } else {
                // 其它浏览器
                filename = URLEncoder.encode(filename, "utf-8");
            }

            // 下载注意事项2--永远是下载
            response.setHeader("content-disposition", "attachment;filename="
                    + filename);

            FileInputStream fis = new FileInputStream(file); // 读取要下载文件的内容
            OutputStream os = response.getOutputStream(); // 将要下载的文件内容通过输出流写回到浏览器端.
            int len = -1;
            byte[] b = new byte[1024 * 100];

            while ((len = fis.read(b)) != -1) {
                os.write(b, 0, len);
                os.flush();
            }
            os.close();
            fis.close();

        } else {
            throw new RuntimeException("下载资源不存在.");
        }
    }


文件下载时的乱码问题

  • 1.关于下载时中文名称资源查找不到

    • 原因:<a href=‘${pageContext.request.contextPath}/download?filename=天空.mp3‘>天空.mp3</a>
      • 这是get请求。
    • 解决:
      • String filename = request.getParameter("filename");
      • filename = new String(filename.getBytes("iso8859-1"),"utf-8");
  • 2.下载文件显示时的中文乱码问题

        response.setHeader("content-disposition", "attachment;filename="+filename);

        IE:要求filename必须是utf-8码 
        firefox:要求filename必须是base64编码.

        问题:怎样判断浏览器?
            String agent=request.getHeader("user-agent");

            if (agent.contains("MSIE")) {
                // IE浏览器
                filename = URLEncoder.encode(filename, "utf-8");

            } else if (agent.contains("Firefox")) {
                // 火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?"
                        + base64Encoder.encode(filename.getBytes("utf-8"))
                        + "?=";
            }else {
                // 其它浏览器
                filename = URLEncoder.encode(filename, "utf-8");
            }


扩展:使用队列来优化递归操作

  • 队列特点:先进先出.
  • 在jdk中有一个接口Queue 它有一个实现类叫LinkedList它其时就是一个队列。
  • 如果要使用队列,插入 offer 获取使用 poll
  • 使用队列来优化递归操作:是可以解决目录层次过多问题。
    • 因为:递归操作可以理解成是纵向的遍历,如果目录层次比较多,在内存中存储的数据也多,会引起溢出。
    • 使用队列,它是横向遍历,一层一层遍历,可以解决目录层次比较多问题。因为使用队列,最多时候在内存中只存储了一层的信息。
  • 最常用的就是树型结构。
<!-- 使用队列操作 -->

    <%
        String path = "D:\\java1110\\workspace\\day22_2\\WebRoot\\upload";
        File uploadDirectory = new File(path);
        //创建一个队列

        Queue<File> queue = new LinkedList<File>();

        queue.offer(uploadDirectory);

        while (!queue.isEmpty()) { //如果队列不为空
            File f = queue.poll(); //从队列中获取一个File

            if(f.isDirectory()){//是目录,将目录下所有文件遍历出来,存储到队列中
                File[] fs = f.listFiles();

                for (int i = 0; i < fs.length; i++) {
                    queue.offer(fs[i]);
                }
            }else{
                String absolutePath=(f.getAbsolutePath());

                String p=absolutePath.substring(absolutePath.lastIndexOf("\\upload"));

                out.println("<a href=‘/day22_2"+p+"‘>"+f.getName()+"</a><br>");
            }

        }
    %>

网盘系统

  • 需求:
    • 1、系统提供一个文件上传功能,在用户上传文件后,文件保存在服务器端指定目录,文件相关信息保存在数据库中
    • 2、系统提供一个文件下载功能,将数据表中所有资源信息,显示在页面上,允许用户进行下载

技术分享

  • 1.创建表
create database day23

    create table resources(
      id int primary key auto_increment,
      uuidname varchar(100) unique not null,
      realname varchar(40) not null,
      savepath varchar(100) not null,
      uploadtime timestamp ,
      description varchar(255)
    );
  • 2.导入jar包和配置文件

    • c3p0 commons-fileupload dbutils mysql驱动 jstl
    • c3p0-config.xml
  • 3.编码实现上传

    • 1.在index.jsp页面添加上传连接
      <a href=‘${pageContext.request.contextPath}/upload.jsp‘>上传</a><br>
    • 2.创建upload.jsp页面,上传操作浏览器端三个注意事项:
      • 1.method=post
      • 2.encType="multipart/form-data"
      • 3.要使用<input type="file" name=‘f‘>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="f"><br>
    描述:<input type="text" name="description"><br>
    <input type="submit" value="提交">
</form>
* 3.创建UploadServlet
    * 1.上传操作
        * commons-fileupload
            * 1.DiskFileItemFactory 
            * 2.ServletFileUpload
            * 3.FileItem
   * 2.将数据封装,存储到数据库.
       * 问题:怎样将数据封装到javaBean?
            * 手动创建一个Map<String,String[]>将数据封装到map集合,通过BeanUtils完成数据封装
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        Map<String, String[]> map = new HashMap<String, String[]>();

        // 1.创建DiskFileItemFactory
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // 2.创建ServletFileUpload
        ServletFileUpload upload = new ServletFileUpload(factory);

        // 设置上传文件中文名称乱码
        upload.setHeaderEncoding("utf-8");
        // upload.isMultipartContent(request)
        // 3.得到所有的FileItem
        try {
            List<FileItem> items = upload.parseRequest(request);

            // 遍历items,得到所有的上传信息
            for (FileItem item : items) {
                if (item.isFormField()) {
                    // 不是上传组件
                    map.put(item.getFieldName(),
                            new String[] { item.getString("utf-8") }); // 封装非上传组件信息
                } else {
                    // 是上传组件
                    // 得到上传文件名称
                    String filename = item.getName();
                    filename = FileUploadUtils.getRealName(filename);
                    map.put("realname", new String[] { filename }); // 封装上传文件真实名称
                    // 得到随机名称
                    String uuidname = FileUploadUtils.getUUIDFileName(filename);

                    map.put("uuidname", new String[] { uuidname });// 封装上传文件随机名称
                    // 得到随机目录
                    String randomDirectory = FileUploadUtils
                            .getRandomDirectory(filename);

                    String uploadPath = this.getServletContext().getRealPath(
                            "/WEB-INF/upload");

                    File parentDirectory = new File(uploadPath, randomDirectory);
                    if (!parentDirectory.exists()) {
                        parentDirectory.mkdirs();
                    }

                    map.put("savepath", new String[] { uploadPath
                            + randomDirectory });// 封装上传文件保存路径

                    IOUtils.copy(item.getInputStream(), new FileOutputStream(
                            new File(parentDirectory, uuidname)));

                    item.delete();
                }
            }

            // /将数据封装到javaBean
            Resource r = new Resource();

            BeanUtils.populate(r, map);

            // 调用service完成保存数据到db。
            ResourceService service = new ResourceService();

            service.save(r);

            response.sendRedirect(request.getContextPath() + "/index.jsp");

        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }


  • 4.下载操作

    • 1.在index.jsp页面,下载连接会访问一个servlet,得到所有可以下载的数据,在页面上展示
      • 1.index.jsp页面代码
        • <a href="${pageContext.request.contextPath}/showDownload">下载</a>
      • 2.创建ShowDownloadServlet
        • 在这个servlet中,查看db,得到所有可以下载的信息
        • List<Resource> rs = service.findAll();
      • 3.创建一个download.jsp页面,展示所有可以下载的信息.
    • 2.在download.jsp,点击下载时,传递的是要下载文件的id。
      <a href=‘${pageContext.request.contextPath}/download?id=${r.id}‘>下载</a>

    • 3.创建一个DownloadServlet

      • 1.查询数据库,得到要下载的文件的相关信息
      • 2.下载操作
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 1.得到id
        String id = request.getParameter("id");

        // 2.调用service,得到Resource对象.
        ResourceService service = new ResourceService();
        try {
            Resource r = service.findById(id);

            File file = new File(r.getSavepath(), r.getUuidname());

            if (file.exists()) {
                // 资源存在
                String filename = r.getRealname();
                // 下载注意事项1--设置下载文件的mimeType
                String mimeType = this.getServletContext()
                        .getMimeType(filename);
                response.setContentType(mimeType);

                String agent = request.getHeader("user-agent");
                if (agent.contains("MSIE")) {
                    // IE浏览器
                    filename = URLEncoder.encode(filename, "utf-8");

                } else if (agent.contains("Firefox")) {
                    // 火狐浏览器
                    BASE64Encoder base64Encoder = new BASE64Encoder();
                    filename = "=?utf-8?B?"
                            + base64Encoder.encode(filename.getBytes("utf-8"))
                            + "?=";
                } else {
                    // 其它浏览器
                    filename = URLEncoder.encode(filename, "utf-8");
                }

                // 下载注意事项2--永远是下载
                response.setHeader("content-disposition",
                        "attachment;filename=" + filename);

                byte[] b = FileUtils.readFileToByteArray(file); // 将指定文件读取到byte[]数组中.

                response.getOutputStream().write(b);

            } else {
                throw new RuntimeException("资源不存在");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }

    }


























































以上是关于Java进阶学习第二十二天——上传与下载的主要内容,如果未能解决你的问题,请参考以下文章

JavaWeb学习 (二十八)————文件上传和下载

python学习第二十二天文件byte类型

(二十四)ATP应用测试平台——springboot集成fastdfs上传与下载功能

第二十三节,迁移学习和数据扩充

Python学习第二十二天

Python学习第二十二天