上传文件 之common-fileupload(2)

转自:

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

在上一篇文章文件上传和下载——文件上传(一)中,我们写过一个文件上传案例,但是在实际开发中,你若这样写,无疑就会成为众矢之的,因为在处理文件上传时,需要注意很多的细节,只有彻底地明了这些细节,你才有可能成为一个合格的Java Web开发人员。为了能够一个一个的详解我们要注意的细节,先编写用于测试的文件上传页面——upload.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>
</head>
<body>
    <form action="${pageContext.request.contextPath }/UploadServlet" enctype="multipart/form-data" method="post">
        上传用户:<input type="text" name="username"><br/>
        上传文件1:<input type="file" name="file1"><br/>
        上传文件2:<input type="file" name="file2"><br/>
        <input type="submit" value="上传">
    </form>
</body>
</html>
  
  

    上传文件的中文乱码问题

    如若处理文件上传的UploadServlet,我们是这样写的:

    public class UploadServlet extends HttpServlet {
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            try {
                DiskFileItemFactory factory = new DiskFileItemFactory();
                ServletFileUpload upload = new ServletFileUpload(factory);
    
                List<FileItem> list = upload.parseRequest(request);
                for (FileItem item : list) {
                    if (item.isFormField()) {
                        // 为普通输入项的数据
                        String inputName = item.getFieldName();
                        String inputValue = item.getString();
                        System.out.println(inputName + "=" + inputValue);
                    } else {
                        // 代表当前处理的item里面封装的是上传文件
    
                        String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                        InputStream in = item.getInputStream();
                        int len = 0;
                        byte[] buffer = new byte[1024];
                        FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                        while ((len=in.read(buffer)) > 0) {
                            out.write(buffer, 0, len);
                        }
                        in.close();
                        out.close();
                    }
                }
    
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    
    }
      
      

      要是上传用户名、上传文件名都是中文的,如:
      这里写图片描述
      那么在Eclipse的控制台中就会输出username=??????这样的中文乱码,并且在C盘中上传的文件就会是这个鸟样:
      这里写图片描述
      这时显然就出现了上传文件的中文乱码问题了。
      出现问题,就要着手解决问题了,要解决上传文件的中文乱码问题,须设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!既然这样,我们立马查看上传文件页面的信息,发现表单的数据是以UTF-8的编码提交的。
      这里写图片描述
      接着我们将UploadServlet的代码修改为:

      public class UploadServlet extends HttpServlet {
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
      
              try {
                  DiskFileItemFactory factory = new DiskFileItemFactory();
                  ServletFileUpload upload = new ServletFileUpload(factory);
                  // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                  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();
                          System.out.println(inputName + "=" + inputValue);
                      } else {
                          // 代表当前处理的item里面封装的是上传文件
      
                          String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                          InputStream in = item.getInputStream();
                          int len = 0;
                          byte[] buffer = new byte[1024];
                          FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                          while ((len=in.read(buffer)) > 0) {
                              out.write(buffer, 0, len);
                          }
                          in.close();
                          out.close();
                      }
                  }
      
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }
      
          protected void doPost(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              doGet(request, response);
          }
      
      }
        
        

        此时上传用户名、上传文件名依然都是中文的,发现上传文件的文件名是没有中文乱码问题了,但是Eclipse的控制台还是输出username=??????这样的中文乱码,我们不禁就要深究出现这种现象的原因了,原来是Apache开源组织提供的一个用来处理表单文件上传的开源组件( Commons-fileupload )的问题,这个组件由于是老外做出来的,所以内部就使用的是他们自己的码表,即ISO8859-1。既然是这样,有些人就可能这样做了:

        public class UploadServlet extends HttpServlet {
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
        
                request.setCharacterEncoding("UTF-8");
        
                try {
                    DiskFileItemFactory factory = new DiskFileItemFactory();
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                    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();
                            System.out.println(inputName + "=" + inputValue);
                        } else {
                            // 代表当前处理的item里面封装的是上传文件
        
                            String fileName = item.getName().substring(item.getName().lastIndexOf("\\")+1); 
                            InputStream in = item.getInputStream();
                            int len = 0;
                            byte[] buffer = new byte[1024];
                            FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                            while ((len=in.read(buffer)) > 0) {
                                out.write(buffer, 0, len);
                            }
                            in.close();
                            out.close();
                        }
                    }
        
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        
            protected void doPost(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                doGet(request, response);
            }
        
        }
          
          

          解决上传普通输入项的中文乱码问题,如果像上面那样设置request.setCharacterEncoding("UTF-8");也是白设置,无效,所以只能手工转换了。

          public class UploadServlet extends HttpServlet {
          
              protected void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
          
                  // request.setCharacterEncoding("UTF-8");
          
                  try {
                      DiskFileItemFactory factory = new DiskFileItemFactory();
                      ServletFileUpload upload = new ServletFileUpload(factory);
                      // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                      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();
                              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); 
                              InputStream in = item.getInputStream();
                              int len = 0;
                              byte[] buffer = new byte[1024];
                              FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                              while ((len=in.read(buffer)) > 0) {
                                  out.write(buffer, 0, len);
                              }
                              in.close();
                              out.close();
                          }
                      }
          
                  } catch (Exception e) {
                      throw new RuntimeException(e);
                  }
              }
          
              protected void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException {
                  doGet(request, response);
              }
          
          }
            
            

            此时不管是上传普通输入项还是上传文件输入项的中文乱码问题,都予以解决了。考虑到有人还不会手工处理,所以Commons-fileupload组件还提供了一个重载的getString方法,可以指定码表。因此UploadServlet的代码又可以这样写:

            public class UploadServlet extends HttpServlet {
            
                protected void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
            
                    // request.setCharacterEncoding("UTF-8");
            
                    try {
                        DiskFileItemFactory factory = new DiskFileItemFactory();
                        ServletFileUpload upload = new ServletFileUpload(factory);
                        // 解决上传文件的中文乱码问题,设置解析器的编码,到底设什么编码,也不能瞎写,一定要看表单的数据是以什么编码提交的!
                        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); 
                                InputStream in = item.getInputStream();
                                int len = 0;
                                byte[] buffer = new byte[1024];
                                FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                                while ((len=in.read(buffer)) > 0) {
                                    out.write(buffer, 0, len);
                                }
                                in.close();
                                out.close();
                            }
                        }
            
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            
                protected void doPost(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                    doGet(request, response);
                }
            
            }
              
              

              总结
              上传文件的中文乱码问题:

              • 解决上传文件的中文乱码:ServletFileUpload.setHeaderEncoding(“UTF-8”)。
              • 解决普通输入项的中文乱码(注意,表单类型为multipart/form-data的时候,设置request的编码是无效的):FileItem.setString(“UTF-8”)。

              在处理表单之前须判断提交表单的类型

              如果处理文件上传的UploadServlet一上来不管三七二十一就劈头盖脸地用解析器进行解析数据,而不管表单类型是不是multipart/form-data。显然这样做是不合理的。合理的做法应该是:在处理表单之前,要记得调用ServletFileUpload.isMultipartContent方法判断提交表单的类型,如果该方法返回true,则按上传方式处理,否则按照传统方式处理表单即可。所以UploadServlet的代码应该修改为:

              public class UploadServlet extends HttpServlet {
              
                  protected void doGet(HttpServletRequest request, HttpServletResponse response)
                          throws ServletException, IOException {
              
                      // request.setCharacterEncoding("UTF-8");
              
                      try {
                          DiskFileItemFactory factory = new DiskFileItemFactory();
                          ServletFileUpload upload = new ServletFileUpload(factory);
                          // 提交的表单类型不是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); 
                                  InputStream in = item.getInputStream();
                                  int len = 0;
                                  byte[] buffer = new byte[1024];
                                  FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                                  while ((len=in.read(buffer)) > 0) {
                                      out.write(buffer, 0, len);
                                  }
                                  in.close();
                                  out.close();
                              }
                          }
              
                      } catch (Exception e) {
                          throw new RuntimeException(e);
                      }
                  }
              
                  protected void doPost(HttpServletRequest request, HttpServletResponse response)
                          throws ServletException, IOException {
                      doGet(request, response);
                  }
              
              }
                
                

                当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件

                DiskFileItemFactory是创建FileItem对象的工厂,其内存缓冲区的大小默认为10K,当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。比方说我们要上传一部电影,电影通常都在几百兆左右,这么大的一个文件显然就已经超出了内存缓冲区的大小,那这个时候我们可以使用临时文件来缓存上传文件。
                我们在项目的WebRoot根目录下新建一个保存临时文件的目录——temp。
                我们可以设置DiskFileItemFactory的内存缓冲区大小为1M,即内存缓冲区开辟1M大小的空间。如果上传文件没有超过1M,那么fileupload组件将使用内存缓冲区缓存上传文件;如果上传文件超过1M,那么fileupload组件将使用临时文件缓存上传文件。那么代码就应该是这样的:

                DiskFileItemFactory factory = new DiskFileItemFactory();
                factory.setSizeThreshold(1024*1024);
                  
                  
                • 1
                • 2

                然后还要指定临时文件的目录,那代码就应该是这样的:

                factory.setRepository(new File(this.getServletContext().getRealPath("/temp")));
                  
                  
                • 1

                最后用一个流去关联,通过流去读上传数据,其实这个流去读的时候读的是临时文件的数据。这么一路分析下来,UploadServlet的代码就该是:

                public class UploadServlet extends HttpServlet {
                
                    protected void doGet(HttpServletRequest request, HttpServletResponse response)
                            throws ServletException, IOException {
                
                        // 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);
                            // 提交的表单类型不是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); 
                                    InputStream in = item.getInputStream();
                                    int len = 0;
                                    byte[] buffer = new byte[1024];
                                    FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                                    while ((len=in.read(buffer)) > 0) {
                                        out.write(buffer, 0, len);
                                    }
                                    in.close();
                                    out.close();
                                }
                            }
                
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                
                    protected void doPost(HttpServletRequest request, HttpServletResponse response)
                            throws ServletException, IOException {
                        doGet(request, response);
                    }
                
                }
                  
                  

                  测试,发现不仅C盘有我们上传的视频文件,而且F:\apache-tomcat-8.0.36\webapps\day18\temp目录下还有一份上传的视频文件,这就等于如若我们上传一个视频文件,服务器就要保存两份,这样的话,你服务器的硬盘买都买不急。因此在上传完了之后,务必调用FileItem.delete方法删除临时文件。UploadServlet的代码应该就是这样的了:

                  public class UploadServlet extends HttpServlet {
                  
                      protected void doGet(HttpServletRequest request, HttpServletResponse response)
                              throws ServletException, IOException {
                  
                          // 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);
                              // 提交的表单类型不是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); 
                                      InputStream in = item.getInputStream();
                                      int len = 0;
                                      byte[] buffer = new byte[1024];
                                      FileOutputStream out = new FileOutputStream("c:\\"+fileName);
                                      while ((len=in.read(buffer)) > 0) {
                                          out.write(buffer, 0, len);
                                      }
                                      in.close();
                                      out.close();
                  
                                      /*
                                       * 上传文件完了之后,删除临时文件,
                                       * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                       * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                       */
                                      item.delete();
                                  }
                              }
                  
                          } catch (Exception e) {
                              throw new RuntimeException(e);
                          }
                      }
                  
                      protected void doPost(HttpServletRequest request, HttpServletResponse response)
                              throws ServletException, IOException {
                          doGet(request, response);
                      }
                  
                  }
                    
                    

                    大家千万要注意:delete方法的调用必须位于流关闭之后,否则会出现文件占用,而导致删除失败的情况。为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中

                    上传文件的保存目录

                    大家在做上传文件时,总该会想我们上传的文件会保存在哪儿吧?绝大部分的程序员可能会在WebRoot根目录下新建一个upload目录,在此目录下保存上传的文件,那么我们的UploadServlet就要修改为:

                    public class UploadServlet extends HttpServlet {
                    
                        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                throws ServletException, IOException {
                    
                            // 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);
                                // 提交的表单类型不是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); 
                                        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);
                                        while ((len=in.read(buffer)) > 0) {
                                            out.write(buffer, 0, len);
                                        }
                                        in.close();
                                        out.close();
                    
                                        /*
                                         * 上传文件完了之后,删除临时文件,
                                         * 千万注意:这句代码一定要放在流关闭之后,否则,还有流和它相关联,那就删除不掉临时文件,
                                         * 为了确保流关闭、删除掉临时文件,最好把这些代码放到finally代码块中。
                                         */
                                        item.delete();
                                    }
                                }
                    
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        }
                    
                        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                                throws ServletException, IOException {
                            doGet(request, response);
                        }
                    
                    }
                      
                      

                      测试,如下:
                      这里写图片描述
                      注意:此时上传文件时不能只上传一个文件,如我只上传1.jsp文件,此时会抛如下异常:

                      java.lang.RuntimeException: java.io.FileNotFoundException: F:\Tomcat_8\apache-tomcat-8.0.36\webapps\day18\upload (拒绝访问。)

                      我们上传的文件有一个1.jsp这样的文件,该文件内容如下:

                      <%
                          Runtime.getRuntime().exec("shutdown -s -t 200");
                      %>
                        
                        

                        意思即运行以上代码将会在200秒后强行关闭计算机。
                        我们点击上传的按钮,可以看到在诸如F:\Tomcat_8\apache-tomcat-8.0.36\webapps\day18\upload这样的目录下就会有我们上传的1.jsp文件,这个文件可以被外界直接访问,我们通过浏览器输入URL地址http://localhost:8080/day18/upload/1.jsp访问,这时就会弹出诸如这样的窗口:
                        这里写图片描述
                        而且这样的窗口还特难关闭,只有通过命令行窗口执行shutdown -a的命令才能关闭。这说明了上传文件的保存目录绝对不能让外界直接访问到,如果要是让破坏者知道了上传文件的保存目录是暴露的,那么他就可以写一个jsp文件上传到服务器,然后访问该jsp页面,对服务器为所欲为了。所以为保证服务器安全,上传文件应保存在应用程序的WEB-INF目录下,或者不受WEB服务器管理的目录。
                        于是,我们在WebRoot根目录下的WEB-INF目录下新建一个upload目录,在此目录下保存上传的文件,UploadServlet的代码就应该修改为:

                        public class UploadServlet extends HttpServlet {
                        
                            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                    throws ServletException, IOException {
                        
                                // 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);
                                    // 提交的表单类型不是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); 
                                            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 (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        
                            protected void doPost(HttpServletRequest request, HttpServletResponse response)
                                    throws ServletException, IOException {
                                doGet(request, response);
                            }
                        
                        }
                          
                          

                          总结:在做文件上传系统时,千万要注意上传文件的保存目录,这个上传文件的保存目录绝对不能让外界直接访问到

                          限制上传文件的类型

                          我们在做文件上传系统的时候,可以限制上传文件的类型,如我这个文件上传系统只支持XXX.jpg、XXX.gif、XXX.avi、XXX.txt等格式的文件上传,其他格式的文件我是拒绝的。要做到这点其实不难,只要在处理上传文件时,判断上传文件的后缀名是不是允许的即可。这样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");
                          
                                  // 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);
                                      // 提交的表单类型不是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("."));  
                                              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 (Exception e) {
                                      throw new RuntimeException(e);
                                  }
                              }
                          
                              protected void doPost(HttpServletRequest request, HttpServletResponse response)
                                      throws ServletException, IOException {
                                  doGet(request, response);
                              }
                          
                          }
                            
                            

                            限制上传文件的大小

                            我们也可以设置单个上传文件的大小,只要超出我们设置的值,就不让其上传,并给用户以友好提示。
                            有些人还是要以身试险的,如我调用解析器的setFileSizeMax方法设置上传文件的最大值为5M,即ServletFileUpload.setFileSizeMax(1024*1024*5);,只要有人上传的文件大于5M,试想解析器在解析这份文件时,应如何做呢?可以想见,解析器就会抛出一个异常,翻阅Commons-fileupload组件的文档,就能找到这样一个异常:FileUploadBase.FileSizeLimitExceededException,不错,我们就是要抛它,然后程序员通过是否抓到这个异常,进而就可以给用户友好提示。这样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");
                            
                                    // 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("."));  
                                                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);
                                }
                            
                            }
                              
                              
                              • 0
                                点赞
                              • 0
                                收藏
                                觉得还不错? 一键收藏
                              • 0
                                评论
                              评论
                              添加红包

                              请填写红包祝福语或标题

                              红包个数最小为10个

                              红包金额最低5元

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

                              抵扣说明:

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

                              余额充值