上传文件之 common-fileupload(3)

本文详细介绍文件上传过程中的关键步骤及注意事项,包括处理空文件、文件重命名、避免文件覆盖、目录结构优化、监听上传进度等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.csdn.net/yerenyuan_pku/article/details/52540661#t3

由于文件上传需要注意的细节太多了,一篇文章全部容纳这些细节,真是太长了,索性再写一篇文章,紧衔上一篇文章文件上传(二)

处理文件上传需要注意的细节

如何判断空的上传输入项

在处理完文件上传需要注意的第6个细节后,测试时,如果我们像下面这样上传文件:
这里写图片描述
点击上传按钮,会抛如下异常:
这里写图片描述
这时,我们一定要冷静下来,看到异常不要害怕,而是要学会看异常,找出抛异常的原因。根据以上的异常显示,在代码

String ext = fileName.substring(fileName.lastIndexOf(".")); 
  

    处出现错误,即在获取文件的扩展名时嗝屁了,为什么会这样呢?原因是:我们在第二个上传文件输入项中没有选择一个文件进行上传,那么在UploadServlet的代码中这句代码:

    String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1);
      

      获取到的文件名是""字符串,即空字符串,而不是null,这样在获取文件的扩展名时,fileName.lastIndexOf(".")返回的就是-1。fileName.substring(fileName.lastIndexOf("."));就是从索引为-1的位置截取,所以会报这样的异常:

      java.lang.StringIndexOutOfBoundsException: String index out of range: -1
        

        这个时候,我们就要将UploadServlet的代码修改为:

        public class UploadServlet extends HttpServlet {
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
        
                // List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
                List<String> types = Arrays.asList("jpg","gif","avi","txt");
                // request.setCharacterEncoding("UTF-8");
        
                try {
                    DiskFileItemFactory factory = new DiskFileItemFactory();
                    factory.setSizeThreshold(1024*1024);
                    factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
        
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    // 限制上传文件的大小
                    upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
        
                    // 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
                    if (!upload.isMultipartContent(request)) {
                        // 按照传统方式获取表单数据
                        request.getParameter("username");
                        blabla......
                        return;
                    }
                    // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                    upload.setHeaderEncoding("UTF-8");
        
                    List<FileItem> list = upload.parseRequest(request);
                    for (FileItem item : list) {
                        if (item.isFormField()) {
                            // 为普通输入项的数据
                            String inputName = item.getFieldName();
                            String inputValue = item.getString("UTF-8");
                            // inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
                            System.out.println(inputName + "=" + inputValue);
                        } else {
                            // 代表当前处理的item里面封装的是上传文件
        
                            String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
        
                            // 拿到文件的扩展名
                            String ext = fileName.substring(fileName.lastIndexOf(".")+1); 
                            /* 
                            if (!types.contains(ext)) {
                                request.setAttribute("message", "本系统不支持" + ext + "这种类型");
                                request.getRequestDispatcher("/message.jsp").forward(request, response);
                                return;
                            }
                            */
                            InputStream in = item.getInputStream();
                            int len = 0;
                            byte[] buffer = new byte[1024];
                            // FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                            // FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/upload") + "\\" + fileName);
                            FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
                            while ((len=in.read(buffer)) > 0) {
                                out.write(buffer, 0, len);
                            }
                            in.close();
                            out.close();
        
                            /*
                             * 上传文件完了之后,删除临时文件,
                             * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                             * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                             */
                            item.delete();
                        }
                    }
        
                } catch (FileUploadBase.FileSizeLimitExceededException e) { 
                    e.printStackTrace();
                    request.setAttribute("message", "文件大小不能超过5M");
                    request.getRequestDispatcher("/message.jsp").forward(request, response);
                    return;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        
            protected void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        
        }
          

          为了通过测试,我们将代码:

          if (!types.contains(ext)) {
              request.setAttribute("message", "本系统不支持" + ext + "这种类型");
              request.getRequestDispatcher("/message.jsp").forward(request, response);
              return;
          }
            

            注释掉。
            再只上传一个文件进行测试,此时又会出现这样的异常:
            这里写图片描述
            究其原因是下面这句代码有错误:

            FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
              

              由于fileName是一个空字符串,所以这句代码的意思就是往一个目录里面写数据,那是肯定不行的。因此UploadServlet的代码又要修改为:

              public class UploadServlet extends HttpServlet {
              
                  protected void doGet(HttpServletRequest request, HttpServletResponse response)
                          throws ServletException, IOException {
              
                      // List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
                      List<String> types = Arrays.asList("jpg","gif","avi","txt");
                      // request.setCharacterEncoding("UTF-8");
              
                      try {
                          DiskFileItemFactory factory = new DiskFileItemFactory();
                          factory.setSizeThreshold(1024*1024);
                          factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
              
                          ServletFileUpload upload = new ServletFileUpload(factory);
                          // 限制上传文件的大小
                          upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
              
                          // 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
                          if (!upload.isMultipartContent(request)) {
                              // 按照传统方式获取表单数据
                              request.getParameter("username");
                              blabla......
                              return;
                          }
                          // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                          upload.setHeaderEncoding("UTF-8");
              
                          List<FileItem> list = upload.parseRequest(request);
                          for (FileItem item : list) {
                              if (item.isFormField()) {
                                  // 为普通输入项的数据
                                  String inputName = item.getFieldName();
                                  String inputValue = item.getString("UTF-8");
                                  // inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
                                  System.out.println(inputName + "=" + inputValue);
                              } else {
                                  // 代表当前处理的item里面封装的是上传文件
              
                                  String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                                  if (fileName == null || fileName.trim().equals("")) {
                                      continue;
                                  }
              
                                  // 拿到文件的扩展名
                                  String ext = fileName.substring(fileName.lastIndexOf(".")+1);  
                                  if (!types.contains(ext)) {
                                      request.setAttribute("message", "本系统不支持" + ext + "这种类型");
                                      request.getRequestDispatcher("/message.jsp").forward(request, response);
                                      return;
                                  }
              
                                  InputStream in = item.getInputStream();
                                  int len = 0;
                                  byte[] buffer = new byte[1024];
                                  // FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                                  // FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/upload") + "\\" + fileName);
                                  FileOutputStream out = new FileOutputStream(this.getServletContext().getRealPath("/WEB-INF/upload") + "\\" + fileName);
                                  while ((len=in.read(buffer)) > 0) {
                                      out.write(buffer, 0, len);
                                  }
                                  in.close();
                                  out.close();
              
                                  /*
                                   * 上传文件完了之后,删除临时文件,
                                   * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                   * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                   */
                                  item.delete();
                              }
                          }
              
                      } catch (FileUploadBase.FileSizeLimitExceededException e) { 
                          e.printStackTrace();
                          request.setAttribute("message", "文件大小不能超过5M");
                          request.getRequestDispatcher("/message.jsp").forward(request, response);
                          return;
                      } catch (Exception e) {
                          throw new RuntimeException(e);
                      }
                  }
              
                  protected void doPost(HttpServletRequest request, HttpServletResponse response)
                          throws ServletException, IOException {
                      doGet(request, response);
                  }
              
              }
                

                为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名

                我们在上传文件系统的时候,要考虑到多用户上传相同文件名的文件,而导致文件覆盖的情况发生的问题。为了避免上传文件的覆盖,程序在保存上传文件时,要为每一个文件生成一个唯一的文件名。此时UploadServlet的代码又应修改为:

                public class UploadServlet extends HttpServlet {
                
                    protected void doGet(HttpServletRequest request, HttpServletResponse response)
                            throws ServletException, IOException {
                
                        // List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
                        List<String> types = Arrays.asList("jpg","gif","avi","txt");
                        // request.setCharacterEncoding("UTF-8");
                
                        try {
                            DiskFileItemFactory factory = new DiskFileItemFactory();
                            factory.setSizeThreshold(1024*1024);
                            factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
                
                            ServletFileUpload upload = new ServletFileUpload(factory);
                            // 限制上传文件的大小
                            upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
                
                            // 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
                            if (!upload.isMultipartContent(request)) {
                                // 按照传统方式获取表单数据
                                request.getParameter("username");
                                blabla......
                                return;
                            }
                            // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                            upload.setHeaderEncoding("UTF-8");
                
                            List<FileItem> list = upload.parseRequest(request);
                            for (FileItem item : list) {
                                if (item.isFormField()) {
                                    // 为普通输入项的数据
                                    String inputName = item.getFieldName();
                                    String inputValue = item.getString("UTF-8");
                                    // inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
                                    System.out.println(inputName + "=" + inputValue);
                                } else {
                                    // 代表当前处理的item里面封装的是上传文件
                
                                    String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                                    if (fileName == null || fileName.trim().equals("")) {
                                        continue;
                                    }
                
                                    // 拿到文件的扩展名
                                    String ext = fileName.substring(fileName.lastIndexOf(".")+1);  
                                    if (!types.contains(ext)) {
                                        request.setAttribute("message", "本系统不支持" + ext + "这种类型");
                                        request.getRequestDispatcher("/message.jsp").forward(request, response);
                                        return;
                                    }
                
                                    InputStream in = item.getInputStream();
                                    int len = 0;
                                    byte[] buffer = new byte[1024];
                
                                    // 产生文件的保存目录
                                    String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
                                    // 得到保存在服务器中唯一的文件名
                                    String saveFileName = generateFileName(fileName);
                
                                    FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
                                    while ((len=in.read(buffer)) > 0) {
                                        out.write(buffer, 0, len);
                                    }
                                    in.close();
                                    out.close();
                
                                    /*
                                     * 上传文件完了之后,删除临时文件,
                                     * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                     * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                     */
                                    item.delete();
                                }
                            }
                
                        } catch (FileUploadBase.FileSizeLimitExceededException e) { 
                            e.printStackTrace();
                            request.setAttribute("message", "文件大小不能超过5M");
                            request.getRequestDispatcher("/message.jsp").forward(request, response);
                            return;
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                
                    public String generateFileName(String fileName) {
                        // 4de727e8-2579-477f-a4ae-658355f107fe
                        return UUID.randomUUID().toString() + "_" + fileName;
                    }
                
                    protected void doPost(HttpServletRequest request, HttpServletResponse response)
                            throws ServletException, IOException {
                        doGet(request, response);
                    }
                
                }
                  

                  一般来说,这句代码

                  FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
                    

                    我们应该写为:

                    FileOutputStream out = new FileOutputStream(savePath + "\\" + saveFileName);
                      

                      为何我们不这样写了,因为考虑到了平台无关性,我们一般都是在Windows系统上做开发,然后再把项目部署到Linux系统中,为了更通用,所以我们要使用File.separator来代替各个操作系统中的分隔符。
                      我们上传一个文件进行测试,可以发现在诸如F:\Tomcat_8\apache-tomcat-8.0.36\webapps\day18\WEB-INF\upload这样的目录下找到上传的文件,如下:
                      这里写图片描述

                      为防止一个目录下面出现太多文件,要使用hash算法打散存储

                      如果一个windows目录下面文件数量太大,目录的访问速度就会很慢,在windows里面,建议一个目录下面最多不要超过1000个文件。
                      在做这样一个文件上传系统时,我们也要考虑此种情况。为防止单个目录下文件过多,影响文件读写速度,处理上传文件的程序应根据可能的文件上传总量,选择合适的目录结构生成算法,将上传文件分散存储。我们选择的目录结构生成算法是这样的:
                      根据保存在服务器中文件的文件名,比如cac1c5d9-b492-4cd9-a724-ec06eb4a6a5d_上传文件1.txt,利用hashCode()方法算出这样一串字符串的hashCode值,即得到该字符串在内存中的地址,如121221。这样的数在计算机中是如何存储的呢?大概就是这样的形式:0010 0011 0011 0101 1100 0111 0010 0111

                      • 取其低4位(范围:0~15),构建一个目录(一级目录),这样就会有16个目录(0目录~15目录),每个目录保存1000份文件,总共就可保存16000份文件;
                      • 如若嫌弃保存的文件数太小,可再取其4~8位(范围:0~15),构建一个目录(二级目录),这样就会有16²个目录,每个目录保存1000份文件,总共就可保存256000份文件;
                      • ……
                      • 以此类推,最后取其高4位(范围:0~15),构建一个目录(八级目录),这样就会有16ⁿ(n=8)个目录,每个目录保存1000份文件,总共就可保存16ⁿ(n=8)X1000份文件,足以保存够多的文件了。

                      这样,UploadServlet的代码又应修改为:

                      public class UploadServlet extends HttpServlet {
                      
                          protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                  throws ServletException, IOException {
                      
                              // List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
                              List<String> types = Arrays.asList("jpg","gif","avi","txt");
                              // request.setCharacterEncoding("UTF-8");
                      
                              try {
                                  DiskFileItemFactory factory = new DiskFileItemFactory();
                                  factory.setSizeThreshold(1024*1024);
                                  factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
                      
                                  ServletFileUpload upload = new ServletFileUpload(factory);
                                  // 限制上传文件的大小
                                  upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
                      
                                  // 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
                                  if (!upload.isMultipartContent(request)) {
                                      // 按照传统方式获取表单数据
                                      request.getParameter("username");
                                      blabla......
                                      return;
                                  }
                                  // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                                  upload.setHeaderEncoding("UTF-8");
                      
                                  List<FileItem> list = upload.parseRequest(request);
                                  for (FileItem item : list) {
                                      if (item.isFormField()) {
                                          // 为普通输入项的数据
                                          String inputName = item.getFieldName();
                                          String inputValue = item.getString("UTF-8");
                                          // inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
                                          System.out.println(inputName + "=" + inputValue);
                                      } else {
                                          // 代表当前处理的item里面封装的是上传文件
                      
                                          String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                                          if (fileName == null || fileName.trim().equals("")) {
                                              continue;
                                          }
                      
                                          // 拿到文件的扩展名
                                          String ext = fileName.substring(fileName.lastIndexOf(".")+1);  
                                          if (!types.contains(ext)) {
                                              request.setAttribute("message", "本系统不支持" + ext + "这种类型");
                                              request.getRequestDispatcher("/message.jsp").forward(request, response);
                                              return;
                                          }
                      
                                          InputStream in = item.getInputStream();
                                          int len = 0;
                                          byte[] buffer = new byte[1024];
                      
                                          // 得到保存在服务器中唯一的文件名
                                          String saveFileName = generateFileName(fileName);
                                          // 产生文件的保存目录
                                          String savePath = generateSavePath(this.getServletContext().getRealPath("/WEB-INF/upload"), saveFileName);
                                          FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
                                          while ((len=in.read(buffer)) > 0) {
                                              out.write(buffer, 0, len);
                                          }
                                          in.close();
                                          out.close();
                      
                                          /*
                                           * 上传文件完了之后,删除临时文件,
                                           * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                           * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                           */
                                          item.delete();
                                      }
                                  }
                      
                              } catch (FileUploadBase.FileSizeLimitExceededException e) { 
                                  e.printStackTrace();
                                  request.setAttribute("message", "文件大小不能超过5M");
                                  request.getRequestDispatcher("/message.jsp").forward(request, response);
                                  return;
                              } catch (Exception e) {
                                  throw new RuntimeException(e);
                              }
                              request.setAttribute("message", "上传成功!!!");
                              request.getRequestDispatcher("/message.jsp").forward(request, response);
                      
                          }
                      
                          public String generateSavePath(String path, String fileName) {
                              int hashCode = fileName.hashCode(); // 得到字符串在内存中的地址,如121221
                              int dir1 = hashCode & 15; // int dir1 = hashCode & 0xf; 代表一级目录
                              int dir2 = (hashCode >> 4) & 0xf; // 代表二级目录
                      
                              // 用户第一次上传文件,此savePath目录在服务器的硬盘里原本是没有的,所以应将其创建出来
                              String savePath = path + File.separator + dir1 + File.separator + dir2;
                              File file = new File(savePath);
                              if (!file.exists()) {
                                  file.mkdirs(); // 创建多级目录用mkdirs()方法
                              }
                              return savePath;
                          }
                      
                          public String generateFileName(String fileName) {
                              // 4de727e8-2579-477f-a4ae-658355f107fe
                              return UUID.randomUUID().toString() + "_" + fileName;
                          }
                      
                          protected void doPost(HttpServletRequest request, HttpServletResponse response)
                                  throws ServletException, IOException {
                              doGet(request, response);
                          }
                      
                      }
                        

                        测试完了之后,我们会发现上传的文件在服务器中找起来非常不容易,但是这又不是让人去查找,我们是写程序去查找,所以这根本就不算是什么事。

                        监听上传进度

                        我们在做文件上传系统时,用户上传文件时,一般都会有那种进度条。但是要在前台页面做出这样的上传的进度条,没有学过Ajax技术,是无法完成的,所以我们只在Eclipse控制台打印上传的信息。要做到这一点,就要给解析器注册一个监听器,那么UploadServlet的代码应修改为:

                        public class UploadServlet extends HttpServlet {
                        
                            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                    throws ServletException, IOException {
                        
                                // List<String> types = Arrays.asList(".jpg",".gif",".avi",".txt");
                                List<String> types = Arrays.asList("jpg","gif","avi","txt");
                                // request.setCharacterEncoding("UTF-8");
                        
                                try {
                                    DiskFileItemFactory factory = new DiskFileItemFactory();
                                    factory.setSizeThreshold(1024*1024);
                                    factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
                        
                                    ServletFileUpload upload = new ServletFileUpload(factory);
                        
                                    upload.setProgressListener(new ProgressListener() {
                                        // update方法一定要由解析器来调用
                                        @Override
                                        public void update(long pBytesRead, long pContentLength, int pItems) {
                                            System.out.println("当前已解析:" + pBytesRead);
                                        }
                                    });
                        
                                    // 限制上传文件的大小
                                    upload.setFileSizeMax(1024*1024*5); // 只要超出5M,for循环在解析的时候就会抛异常
                        
                                    // 提交的表单类型不是multipart/form-data,没必要用解析器进行解析数据,按照传统方式获取表单数据
                                    if (!upload.isMultipartContent(request)) {
                                        // 按照传统方式获取表单数据
                                        request.getParameter("username");
                                        blabla......
                                        return;
                                    }
                                    // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                                    upload.setHeaderEncoding("UTF-8");
                        
                                    List<FileItem> list = upload.parseRequest(request);
                                    for (FileItem item : list) {
                                        if (item.isFormField()) {
                                            // 为普通输入项的数据
                                            String inputName = item.getFieldName();
                                            String inputValue = item.getString("UTF-8");
                                            // inputValue = new String(inputValue.getBytes("ISO8859-1"), "UTF-8");
                                            System.out.println(inputName + "=" + inputValue);
                                        } else {
                                            // 代表当前处理的item里面封装的是上传文件
                        
                                            String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                                            if (fileName == null || fileName.trim().equals("")) {
                                                continue;
                                            }
                        
                                            // 拿到文件的扩展名
                                            String ext = fileName.substring(fileName.lastIndexOf(".")+1);  
                                            if (!types.contains(ext)) {
                                                request.setAttribute("message", "本系统不支持" + ext + "这种类型");
                                                request.getRequestDispatcher("/message.jsp").forward(request, response);
                                                return;
                                            }
                        
                                            InputStream in = item.getInputStream();
                                            int len = 0;
                                            byte[] buffer = new byte[1024];
                        
                                            // 得到保存在服务器中唯一的文件名
                                            String saveFileName = generateFileName(fileName);
                                            // 产生文件的保存目录
                                            String savePath = generateSavePath(this.getServletContext().getRealPath("/WEB-INF/upload"), saveFileName);
                                            FileOutputStream out = new FileOutputStream(savePath + File.separator + saveFileName);
                                            while ((len=in.read(buffer)) > 0) {
                                                out.write(buffer, 0, len);
                                            }
                                            in.close();
                                            out.close();
                        
                                            /*
                                             * 上传文件完了之后,删除临时文件,
                                             * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                             * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                             */
                                            item.delete();
                                        }
                                    }
                        
                                } catch (FileUploadBase.FileSizeLimitExceededException e) { 
                                    e.printStackTrace();
                                    request.setAttribute("message", "文件大小不能超过5M");
                                    request.getRequestDispatcher("/message.jsp").forward(request, response);
                                    return;
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                                request.setAttribute("message", "上传成功!!!");
                                request.getRequestDispatcher("/message.jsp").forward(request, response);
                        
                            }
                        
                            public String generateSavePath(String path, String fileName) {
                                int hashCode = fileName.hashCode(); // 得到字符串在内存中的地址,如121221
                                int dir1 = hashCode & 15; // int dir1 = hashCode & 0xf; 代表一级目录
                                int dir2 = (hashCode >> 4) & 0xf; // 代表二级目录
                        
                                // 用户第一次上传文件,此savePath目录在服务器的硬盘里原本是没有的,所以应将其创建出来
                                String savePath = path + File.separator + dir1 + File.separator + dir2;
                                File file = new File(savePath);
                                if (!file.exists()) {
                                    file.mkdirs(); // 创建多级目录用mkdirs()方法
                                }
                                return savePath;
                            }
                        
                            public String generateFileName(String fileName) {
                                // 4de727e8-2579-477f-a4ae-658355f107fe
                                return UUID.randomUUID().toString() + "_" + fileName;
                            }
                        
                            protected void doPost(HttpServletRequest request, HttpServletResponse response)
                                    throws ServletException, IOException {
                                doGet(request, response);
                            }
                        
                        }
                          

                          我们上传一个文件,可以看到在Eclipse的控制台中打印如下信息:

                          当前已解析:4096
                          当前已解析:7625
                          当前已解析:11675
                          当前已解析:15725
                          当前已解析:15817
                          当前已解析:19867
                          当前已解析:23917
                          当前已解析:24009
                          当前已解析:28059
                          当前已解析:32109
                          当前已解析:32201
                          当前已解析:36251
                          当前已解析:40301
                          当前已解析:40393
                          当前已解析:44443
                          当前已解析:48493
                          当前已解析:48585
                          当前已解析:52635
                          当前已解析:56685
                          当前已解析:56777
                          当前已解析:60827
                          当前已解析:64877
                          当前已解析:64969
                          当前已解析:69019
                          当前已解析:73069
                          当前已解析:73161
                          当前已解析:77211
                          当前已解析:81261
                          当前已解析:81353
                          当前已解析:85403
                          当前已解析:89453
                          当前已解析:89545
                          当前已解析:93595
                          当前已解析:97645
                          当前已解析:97737
                          当前已解析:101787
                          当前已解析:105837
                          当前已解析:105929
                          当前已解析:109979
                          当前已解析:112109
                            

                            千万要注意,解析器注册监听器的代码不能放在代码

                            List<FileItem> list = upload.parseRequest(request);
                              

                              后面,因为这句代码就是在解析,别人都解析完了,你才去监听,那还有个屁用!所以监听器一定要写在解析之前
                              最后多一嘴,如果我们希望上传进度条能够均匀地增长,即每上传100M的数据,进度条就增长,可以参考Commons-fileupload组件的User guide,在User guide中就有这样的代码:

                              //Create a progress listener
                              ProgressListener progressListener = new ProgressListener(){
                                 private long megaBytes = -1;
                                 public void update(long pBytesRead, long pContentLength, int pItems) {
                                     long mBytes = pBytesRead / 1000000;
                                     if (megaBytes == mBytes) {
                                         return;
                                     }
                                     megaBytes = mBytes;
                                     System.out.println("We are currently reading item " + pItems);
                                     if (pContentLength == -1) {
                                         System.out.println("So far, " + pBytesRead + " bytes have been read.");
                                     } else {
                                         System.out.println("So far, " + pBytesRead + " of " + pContentLength
                                                            + " bytes have been read.");
                                     }
                                 }
                              };
                                

                                在web页面中动态添加上传输入项

                                有些文件上传系统有这样的需求:要在jsp页面中动态地添加文件上传输入项。要实现此需求,我们就要写JavaScript代码了,其核心思想是:每次动态增加一个文件上传输入框,都把它和删除按纽放置在一个单独的div中,并对删除按纽的onclick事件进行响应,使之删除按纽所在的div
                                我们以此编写一个这样的jsp页面。

                                <%@ page language="java" contentType="text/html; charset=UTF-8"
                                    pageEncoding="UTF-8"%>
                                <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
                                <html>
                                <head>
                                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                                <title>Insert title here</title>
                                <script type="text/javascript">
                                    function addfile() {
                                        var files = document.getElementById("files");
                                
                                        var input = document.createElement("input");
                                        input.type="file";
                                        input.name="file1";
                                
                                        var btn = document.createElement("input");
                                        btn.type="button";
                                        btn.value="删除";
                                        btn.onclick = function del() { // 不要写成delete,类似关键字
                                            // this代表button按钮自己
                                            this.parentNode.parentNode.removeChild(this.parentNode);
                                        }
                                
                                        var div = document.createElement("div");
                                        div.appendChild(input);
                                        div.appendChild(btn);
                                
                                        files.appendChild(div);
                                    }
                                </script>
                                </head>
                                <body>
                                    <form action="/day18/UploadServlet2" enctype="multipart/form-data" method="post">
                                        <table>
                                            <tr>
                                                <td>上传用户</td>
                                                <td>
                                                    <input type="text" name="username">
                                                </td>
                                            </tr>
                                
                                            <tr>
                                                <td>上传文件</td>
                                                <td>
                                                    <input type="button" value="添加上传文件" onclick="addfile()">
                                                </td>
                                            </tr>
                                
                                            <tr>
                                                <td></td>
                                                <td>
                                                    <div id="files"></div>
                                                </td>
                                            </tr>
                                
                                            <tr>
                                                <td></td>
                                                <td>
                                                    <input type="submit" value="上传">    
                                                </td>
                                            </tr>
                                        </table>
                                    </form>
                                </body>
                                </html>
                                  

                                  测试以上jsp页面,如下:
                                  这里写图片描述
                                  终于,我们把处理文件上传所需要注意的细节都介绍完了,总算不错了,给自己一个鼓励!

                                  评论
                                  添加红包

                                  请填写红包祝福语或标题

                                  红包个数最小为10个

                                  红包金额最低5元

                                  当前余额3.43前往充值 >
                                  需支付:10.00
                                  成就一亿技术人!
                                  领取后你会自动成为博主和红包主的粉丝 规则
                                  hope_wisdom
                                  发出的红包
                                  实付
                                  使用余额支付
                                  点击重新获取
                                  扫码支付
                                  钱包余额 0

                                  抵扣说明:

                                  1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
                                  2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

                                  余额充值