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();
        }

    }
时间: 2024-08-04 03:56:02

Java进阶学习第二十二天——上传与下载的相关文章

Struts2学习总结——文件上传与下载

Struts2文件上传与下载 1.1.1新建一个Maven项目(demo02) 在此添加Web构面以及 struts2 构面 1.2.1配置Maven依赖(pom.xml 文件) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20

java实现ftp文件的上传与下载

最近在做ftp文件的上传与下载,基于此,整理了一下资料.本来想采用java自带的方法,可是看了一下jdk1.6与1.7的实现方法有点区别,于是采用了Apache下的框架实现的... 1.首先引用3个包 2.然后是相关类的代码 /** * ftp链接常量 * */ public class Ftp { private String ipAddr;//ip地址 private Integer port;//端口号 private String userName;//用户名 private Strin

java对excel表格的上传和下载处理

Excel表格文件的上传和下载,java中涉及到文件肯定会有io流的知识. 而excel文件就要涉及到poi技术,而excel的版本包括:2003-2007和2010两个版本, 即excel的后缀名为:xls和xlsx. 这里我是按照正规的项目流程做的案例,所以可能会比网上的一些Demo复杂一些.不过文件的上传和下载基本都是一套固定的流程,只是每个人的实现方式不太相同. 数据库我用的是MySql. 下面是我的项目目录: 按照正常的项目做了分层处理,文件上传的业务我放到了service处理,而文件

JavaWeb学习总结——文件上传和下载

在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件.这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,stru

Java web开发——文件的上传和下载

一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输.关闭浏览器后保留进度信息. 支持文件夹批量上传下载,服务器端保留文件夹层级结构,服务器端文件夹层级结构与本地相同. 支持大文件批量上传(20G)和下载,同时需要保证上传期间用户电脑不出现卡死等体验:支持文件夹上传,文件夹中的文件数量达到1万个以上,且包含层级结构. 支持断点续传,关闭浏览器或刷新浏览

Java进阶学习第二十三天——国际化与AJAX、JSON

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.06.10 lutianfei none 国际化 软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的.符合来访者阅读习惯的页面或数据. 国际化又称为 i18n:internationalization 软件实现国际化,需具备哪些特征: 对于程序中固定使用的文本元素,例如菜单栏.导航条等中使用的文本元素.或错误提示信息,状态信息等,需要根据来访者的地区和国家,选择不

Java进阶学习第十二天——JSP JavaBean EL

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.05.04 lutianfei none session(拓展) session的追踪(了解) session的创建和销毁 创建session : 第一次访问资源,调用request.getSession() session销毁的三种方法: 非正常关闭服务器 session的过期,默认是30分钟.(tomcat/conf/web.xml) <session-config> <session-timeout>

java实现文件上传和下载

写在前面 [文件上传和下载]是很多系统必备功能, 比如PM\OA\ERP等:系统中常见的开发模式有B/S和C/S,而前者主要是通过浏览器来访问web服务器,一般采用七层协议中的[应用层http]进行数据传输,后者主要通过编程语言开发的app作为客户端来访问服务端,一般采用七层协议中的[传输层tcp]进行数据传输. 文章主要完成简单java web涉及的文件上传和下载功能. 正文 1. java原生servlet实现: pom.xml配置: <dependency> <groupId>

Javaweb学习笔记10—文件上传与下载

 今天来讲javaweb的第10阶段学习.文件的上传与下载,今天主要说的是这个功能的实现,不用说了,听名字就是外行人也知道肯定很重要啦. 老规矩,首先先用一张思维导图来展现今天的博客内容. ps:我的思维是用的xMind画的,如果你对我的思维导图感兴趣并且想看到你们跟详细的备注信息,请点击下载 另外:如果图看不清的话请右击---在新窗口中打开会清楚很多 一*, 文件的上传:      1 *分析实现步骤: 1.1* 客户端浏览器通过文件域选择本地要上传的文件. * 点击"上传"按钮