Java学习之文件上传的注意细节

来源:互联网 发布:论文相似性检测软件 编辑:程序博客网 时间:2024/06/09 17:06

上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的

  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

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

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

  4、要限制上传文件的最大值。

  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

  针对上述提出的5点细节问题,我们来改进一下UploadHandleServlet,改进后的代码如下:

 1 package me.gacl.web.controller;  2   3 import java.io.File;  4 import java.io.FileOutputStream;  5 import java.io.IOException;  6 import java.io.InputStream;  7 import java.util.List;  8 import java.util.UUID;  9  10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 import org.apache.commons.fileupload.FileItem; 15 import org.apache.commons.fileupload.FileUploadBase; 16 import org.apache.commons.fileupload.ProgressListener; 17 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 18 import org.apache.commons.fileupload.servlet.ServletFileUpload; 19  20 /** 21 * @ClassName: UploadHandleServlet 22 * @Description: TODO(这里用一句话描述这个类的作用) 23 *  24 *  25 * 26 */  27 public class UploadHandleServlet extends HttpServlet { 28  29     public void doGet(HttpServletRequest request, HttpServletResponse response) 30             throws ServletException, IOException { 31                 //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 32                 String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); 33                 //上传时生成的临时文件保存目录 34                 String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp"); 35                 File tmpFile = new File(tempPath); 36                 if (!tmpFile.exists()) { 37                     //创建临时目录 38                     tmpFile.mkdir(); 39                 } 40                  41                 //消息提示 42                 String message = ""; 43                 try{ 44                     //使用Apache文件上传组件处理文件上传步骤: 45                     //1、创建一个DiskFileItemFactory工厂 46                     DiskFileItemFactory factory = new DiskFileItemFactory(); 47                     //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。 48                     factory.setSizeThreshold(1024*100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB 49                     //设置上传时生成的临时文件的保存目录 50                     factory.setRepository(tmpFile); 51                     //2、创建一个文件上传解析器 52                     ServletFileUpload upload = new ServletFileUpload(factory); 53                     //监听文件上传进度 54                     upload.setProgressListener(new ProgressListener(){ 55                         public void update(long pBytesRead, long pContentLength, int arg2) { 56                             System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead); 57                             /** 58                              * 文件大小为:14608,当前已处理:4096 59                                 文件大小为:14608,当前已处理:7367 60                                 文件大小为:14608,当前已处理:11419 61                                 文件大小为:14608,当前已处理:14608 62                              */ 63                         } 64                     }); 65                      //解决上传文件名的中文乱码 66                     upload.setHeaderEncoding("UTF-8");  67                     //3、判断提交上来的数据是否是上传表单的数据 68                     if(!ServletFileUpload.isMultipartContent(request)){ 69                         //按照传统方式获取数据 70                         return; 71                     } 72                      73                     //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB 74                     upload.setFileSizeMax(1024*1024); 75                     //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB 76                     upload.setSizeMax(1024*1024*10); 77                     //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项 78                     List<FileItem> list = upload.parseRequest(request); 79                     for(FileItem item : list){ 80                         //如果fileitem中封装的是普通输入项的数据 81                         if(item.isFormField()){ 82                             String name = item.getFieldName(); 83                             //解决普通输入项的数据的中文乱码问题 84                             String value = item.getString("UTF-8"); 85                             //value = new String(value.getBytes("iso8859-1"),"UTF-8"); 86                             System.out.println(name + "=" + value); 87                         }else{//如果fileitem中封装的是上传文件 88                             //得到上传的文件名称, 89                             String filename = item.getName(); 90                             System.out.println(filename); 91                             if(filename==null || filename.trim().equals("")){ 92                                 continue; 93                             } 94                             //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt 95                             //处理获取到的上传文件的文件名的路径部分,只保留文件名部分 96                             filename = filename.substring(filename.lastIndexOf("\\")+1); 97                             //得到上传文件的扩展名 98                             String fileExtName = filename.substring(filename.lastIndexOf(".")+1); 99                             //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法100                             System.out.println("上传的文件的扩展名是:"+fileExtName);101                             //获取item中的上传文件的输入流102                             InputStream in = item.getInputStream();103                             //得到文件保存的名称104                             String saveFilename = makeFileName(filename);105                             //得到文件的保存目录106                             String realSavePath = makePath(saveFilename, savePath);107                             //创建一个文件输出流108                             FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);109                             //创建一个缓冲区110                             byte buffer[] = new byte[1024];111                             //判断输入流中的数据是否已经读完的标识112                             int len = 0;113                             //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据114                             while((len=in.read(buffer))>0){115                                 //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中116                                 out.write(buffer, 0, len);117                             }118                             //关闭输入流119                             in.close();120                             //关闭输出流121                             out.close();122                             //删除处理文件上传时生成的临时文件123                             //item.delete();124                             message = "文件上传成功!";125                         }126                     }127                 }catch (FileUploadBase.FileSizeLimitExceededException e) {128                     e.printStackTrace();129                     request.setAttribute("message", "单个文件超出最大值!!!");130                     request.getRequestDispatcher("/message.jsp").forward(request, response);131                     return;132                 }catch (FileUploadBase.SizeLimitExceededException e) {133                     e.printStackTrace();134                     request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");135                     request.getRequestDispatcher("/message.jsp").forward(request, response);136                     return;137                 }catch (Exception e) {138                     message= "文件上传失败!";139                     e.printStackTrace();140                 }141                 request.setAttribute("message",message);142                 request.getRequestDispatcher("/message.jsp").forward(request, response);143     }144     145     /**146     * @Method: makeFileName147     * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称148     * @Anthor:孤傲苍狼149     * @param filename 文件的原始名称150     * @return uuid+"_"+文件的原始名称151     */ 152     private String makeFileName(String filename){  //2.jpg153         //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名154         return UUID.randomUUID().toString() + "_" + filename;155     }156     157     /**158      * 为防止一个目录下面出现太多文件,要使用hash算法打散存储159     * @Method: makePath160     * @Description: 161     162     *163     * @param filename 文件名,要根据文件名生成存储目录164     * @param savePath 文件存储路径165     * @return 新的存储目录166     */ 167     private String makePath(String filename,String savePath){168         //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址169         int hashcode = filename.hashCode();170         int dir1 = hashcode&0xf;  //0--15171         int dir2 = (hashcode&0xf0)>>4;  //0-15172         //构造新的保存目录173         String dir = savePath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5174         //File既可以代表文件也可以代表目录175         File file = new File(dir);176         //如果目录不存在177         if(!file.exists()){178             //创建目录179             file.mkdirs();180         }181         return dir;182     }183 184     public void doPost(HttpServletRequest request, HttpServletResponse response)185             throws ServletException, IOException {186 187         doGet(request, response);188     }189 }

针对上述提出的5点小细节问题进行改进之后,我们的文件上传功能就算是做得比较完善了。

0 0
原创粉丝点击