使用COS组件实现文件上传

来源:互联网 发布:nsurlsessiond mac 编辑:程序博客网 时间:2024/05/21 17:42

这是一个Servlet应用。。

首先是web.xml

[xhtml] view plaincopyprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  5.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  6.     <servlet>  
  7.         <servlet-name>UploadServelt</servlet-name>  
  8.         <servlet-class>com.jadyer.servlet.UploadServelt</servlet-class>  
  9.         <!-- 指定所上传的文件,在上传成功后,保存在硬盘中的位置 -->  
  10.         <init-param>  
  11.             <param-name>savePath</param-name>  
  12.             <param-value>D://mydata//upload</param-value>  
  13.         </init-param>  
  14.     </servlet>  
  15.     <servlet-mapping>  
  16.         <servlet-name>UploadServelt</servlet-name>  
  17.         <url-pattern>/servlet/UploadServelt</url-pattern>  
  18.     </servlet-mapping>  
  19.   
  20.     <welcome-file-list>  
  21.         <welcome-file>upload.jsp</welcome-file>  
  22.     </welcome-file-list>  
  23. </web-app>  
  24. <!--  
  25. 曾有网友拿COS跟commons-fileupload和jspSmartUpload进行试验对比,试验过程如下  
  26. 分别上传2MB、20MB、45MB、200MB的文件,并测试三种组件的花费时间,测试结果如下  
  27. 文件小于2MB时,COS和FileUpload的上传速度差不多,但jspSmartUpload已显出弱势  
  28. 随着文件的增大,FileUpload和SmartUpload的上传速度明显不如COS  
  29. 当文件200MB时,SmartUpload已经不堪重负而崩溃  
  30. 而此时COS所花费的时间比FileUpload要少了20多秒  
  31. 毫无疑问,试验结果,COS的性能,当之无愧位居第一  
  32. -->  

然后是用于收集所上传的文件信息的upload.jsp页面

[xhtml] view plaincopyprint?
  1. <%@ page language="java" pageEncoding="UTF-8"%>  
  2.   
  3. <form action="<%=request.getContextPath()%>/servlet/UploadServelt" enctype="multipart/form-data" method="POST">  
  4.     用户:<input type="text" name="username"><br/>  
  5.     密码:<input type="password" name="password"><br/>  
  6.     性别:<input type="radio" name="sex" value="woman" checked>女    
  7.          <input type="radio" name="sex" value="man"><br/>  
  8.     喜好:<input type="checkbox" name="like" value="sleep">睡觉    
  9.          <input type="checkbox" name="like" value="coding" checked>写代码    
  10.          <input type="checkbox" name="like" value="eat">吃饭<br/>  
  11.     附件:<input type="file" name="file11"><br/>  
  12.     附件:<input type="file" name="file22"><br/>  
  13.     附件:<input type="file" name="file33"><br/>  
  14.          <input type="submit" value="我要上传">  
  15. </form>  

接着是自定义的用于解决上传的文件名冲突的命名策略类

[java] view plaincopyprint?
  1. package com.jadyer.util;  
  2.   
  3. import java.io.File;  
  4. import java.util.Date;  
  5.   
  6. import com.oreilly.servlet.multipart.FileRenamePolicy;  
  7.   
  8. /** 
  9.  * 自定义的命名策略文件 
  10.  * @see 用于解决上传文件的同名冲突问题 
  11.  * @see 解决方法:文件名 + 时间戳 + 文件后缀 
  12.  */  
  13. public class RandomFileNamePolicy implements FileRenamePolicy {  
  14.     public File rename(File file) {  
  15.         /* 
  16.          * 假设,我们上传了一个同名文件,文件名为【abcd.ccc】 
  17.          */  
  18.         int index = file.getName().lastIndexOf("."); //获取文件名中【.】的下标  
  19.         String body = file.getName().substring(0, index); //表示文件名的主题,即【abcd】  
  20.         String postfix = ""//表示文件名的后缀,即【.ccc】  
  21.         String timer = ""//代表当前系统时间的数字  
  22.           
  23.         //如果该文件的名字中,没有【.】的话,那么lastIndexOf(".")将返回-1  
  24.         if (index != -1) {  
  25.             timer = new Date().getTime() + ""//在文件的名字前面,添加的表示当前系统时间的数字  
  26.             postfix = file.getName().substring(index); //获取到文件名当中的【.ccc】  
  27.         } else {  
  28.             timer = new Date().getTime() + "";  
  29.             postfix = ""//如果lastIndexOf(".")返回-1,说明该文件名中没有【.】即没有后缀  
  30.         }  
  31.           
  32.         String newName = body + timer + postfix; //构造新的文件名  
  33.         return new File(file.getParent(), newName); //返回重命名后的文件  
  34.     }  
  35. }  

最后是用来处理文件上传的核心操作的Servlet

[java] view plaincopyprint?
  1. package com.jadyer.servlet;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.util.Enumeration;  
  6.   
  7. import javax.servlet.ServletConfig;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.http.HttpServlet;  
  10. import javax.servlet.http.HttpServletRequest;  
  11. import javax.servlet.http.HttpServletResponse;  
  12.   
  13. import com.jadyer.util.RandomFileNamePolicy;  
  14. import com.oreilly.servlet.MultipartRequest;  
  15.   
  16. /** 
  17.  * 此时需要在该Web项目中引入cos.jar 
  18.  * 可通过http://www.servlets.com/cos/cos-26Dec2008.zip下载 
  19.  */  
  20. public class UploadServelt extends HttpServlet {  
  21.     private static final long serialVersionUID = -7946856825034537432L;  
  22.       
  23.     private String savePath;  
  24.   
  25.     public void init(ServletConfig config) {  
  26.         //取得web.xml中配置的savePath参数的值  
  27.         savePath = config.getInitParameter("savePath");  
  28.     }  
  29.   
  30.     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  31.         //指定所上传的文件,上传成功后,在硬盘上的保存位置  
  32.         String saveDirectory = this.savePath;  
  33.           
  34.         //如果所指定的文件夹,在硬盘上不存在的话,则创建该文件夹  
  35.         File fileDirectory = new File(saveDirectory);  
  36.         if(fileDirectory.exists()){  
  37.             System.out.println("提示:" + saveDirectory + "目录已存在");  
  38.         }else{  
  39.             //fileDirectory.mkdir();//此时如果使用mkdir()方法,文件夹将创建失败  
  40.             //因为我们在web.xml中指定的<init-param-value>的值,包含父目录  
  41.             fileDirectory.mkdirs();  
  42.             System.out.println("成功创建" + saveDirectory + "文件夹");  
  43.         }  
  44.   
  45.         //限定所上传文件的合计大小,默认为1MB。这里设置的不是单个文件,而是上传的所有文件的总大小  
  46.         int maxPostSize = 8 * 1024 * 1024;  
  47.           
  48.         //可能会出现不同用户,上传同名文件的现象,所以我们应该采取某种手段,以解决文件名称冲突的问题  
  49.         //在COS中有一个默认的命名策略DefaultFileRenamePolicy,只要存在重名现象,它就会在文件名后面加上1.2.3..等以示区分  
  50.         //DefaultFileRenamePolicy dfrp = new DefaultFileRenamePolicy();  
  51.         //MultipartRequest multi = new MultipartRequest(request, saveDirectory, maxPostSize, "UTF-8", dfrp);  
  52.           
  53.         //本人测试的结果却是:若未显式new DefaultFileRenamePolicy(),此时若上传同名文件,则先前的文件会被后面上传的文件覆盖掉  
  54.         //MultipartRequest multi = new MultipartRequest(request, saveDirectory, maxPostSize, "UTF-8");  
  55.           
  56.         //我们也可以自定义命名策略文件。。我这里的解决办法是:文件名 + 时间戳 + 文件后缀  
  57.         //在COS中自定义命名策略文件时,只需要实现FileRenamePolicy接口,并重写其rename(File file)方法即可  
  58.         RandomFileNamePolicy rfnp = new RandomFileNamePolicy();  
  59.           
  60.         //完成文件上传  
  61.         MultipartRequest multi = new MultipartRequest(request, saveDirectory, maxPostSize, "UTF-8", rfnp);  
  62.           
  63.         //输出所上传的文件的信息  
  64.         Enumeration fileNames = multi.getFileNames();  
  65.         while(fileNames.hasMoreElements()){  
  66.             String fileName = (String)fileNames.nextElement();  
  67.             if(null != multi.getFile(fileName)){  
  68.                 String lastFileName = multi.getFilesystemName(fileName);  
  69.                 System.out.println("上传的文件: " + saveDirectory + "//" + lastFileName);  
  70.             }  
  71.         }  
  72.           
  73.         //输出所提交的表单中其它文本输入域的值  
  74.         Enumeration formValue = multi.getParameterNames();  
  75.         while(formValue.hasMoreElements()){  
  76.             String param = (String)formValue.nextElement();  
  77.             String value = multi.getParameter(param);  
  78.             System.out.println(value);  
  79.         }  
  80.         //若知道前台表单输入域的name值,便可使用下面代码,更省事  
  81.         System.out.println("用户:" + multi.getParameter("username"));  
  82.         System.out.println("密码:" + multi.getParameter("password"));  
  83.         System.out.println("性别:" + multi.getParameter("sex"));  
  84.         for(String like : multi.getParameterValues("like")){  
  85.             System.out.println("喜好:" + like);  
  86.         }  
  87.     }  
  88.   
  89. }  
  90. /*************【MultipartRequest类中的几个实用方法】**************************************************/  
  91. //public Enumeration getFileNames()  
  92. //返回包含了所有上传的文件名称的一个Enumeration对象  
  93. //在Enumeration对象里面储存的是前台表单中<input type="file" name="">里面的name值  
  94.   
  95. //public File getFile(String name)  
  96. //返回存储在服务器上的指定name的File对象。该name是<input type="file" name="">的name值  
  97. //若服务器上不存在该文件或者未上传该文件到服务器上,则返回null  
  98.   
  99. //public String getFilesystemName(String name)  
  100. //返回所上传的文件,在服务器上的真正文件名。该name是<input type="file" name="">的name值  
  101. //如果在上传文件时,未指定FileRenamePolicy命名策略文件,则返回的是该文件上传之前的原始名称  
  102. //若服务器上不存在该文件或者未上传该文件到服务器上,则返回null  
  103.   
  104. //public String getOriginalFileName(String name)  
  105. //返回所上传的文件,在命名策略文件生效前的文件名。该name是<input type="file" name="">的name值  
  106. //说白了,就是你上传的文件的本地的原始名字,而不是在上传到服务器之后,为解决同名现象而被重命名后的名字  
  107.   
  108. //public Enumeration getParameterNames()  
  109. //返回前台表单中,除文件输入域外的,其它文本输入域的所有参数值  
  110. //在Enumeration对象里面,储存的是前台表单中的<input type="除file外" name="">里面的name值  
  111.   
  112. //public String getParameter(String name)  
  113. //返回前台表单中,文本输入域的值。该name是表单中<input type="除file外" name="">里的name值  
  114. //如果前台表单中的name参数,对应有多个值,比如<input type="checkbox">  
  115. //那么此时,该方法将只会输出这多个值中的最后一个值  
  116. //所以,对于类似<input type="checkbox">而言,更推荐getParameterValues(String name)方法  
  117. /***************************************************************************************************/  
  118.   
  119.   
  120. /*************【略析COS组件中MultipartRequest构造方法】***********************************************/  
  121. //com.oreilly.servlet.MultipartRequest.MultipartRequest主要负责文件上传的处理  
  122. //MultipartRequest类共有8个构造函数,可参考官方文档,以下是对构造函数中参数的简要说明  
  123. //saveDirectory--指定所上传文件,在服务器端的存储目录  
  124. //maxPostSize----限制上传文件的合计大小。默认为1MB  
  125. //encoding-------解决上传文件名称的乱码问题  
  126. //policy---------解决上传文件名称的重名问题  
  127. /***************************************************************************************************/  
  128.   
  129.   
  130. /*************【关于maxPostSize参数的感言】**********************************************************/  
  131. //这里必须声明一点:MultipartRequest构造方法中的maxPostSize参数,网上存在一定的误解  
  132. //接触COS,是很偶然的:周三,QQ上,突然想要写一段代码,实现的是在两个JSP中上传一个图片  
  133. //要求:代码尽量少。原本我对IO流就没那么熟练,于是条件反射的就想用commons-fileupload组件  
  134. //结果,还是觉得不行,要求代码要尽量少啊。我一寻思,既如此,jspSmartUpload就也不行了  
  135. //可是要我自己去写IO的那些东西,又有些不情愿,于是就琢磨着到网上找找其它的文件上传组件  
  136. //很快就在oschina.net发现了COS组件,当时看到那个Demo,不禁眼前一亮,这组件太给力了  
  137. //于是决定好好研究研究它,随之就去CSDN搜索COS的相关文章,竟然少得可怜,让我大吃一惊  
  138. //反倒是commons-fileupload如日中天,莫非COS宣传不力??于是赶紧探索COS的前世今生  
  139. //没想到COS竟然是大名鼎鼎的O'Rrilly公司开发的一款用于HTTP上传文件的OpenSource组件  
  140. //太赞了!!大家都知道:O'Reilly公司的书是非常闻名的  
  141. //没想到O'Reilly竟然也开发了一个上传组件,还是开源的,也是为开源事业做出了贡献啊,赞!!  
  142. //于是在COS主页:http://www.servlets.com/cos将其发行包下载下来  
  143. //COS下载地址为:http://www.servlets.com/cos/cos-26Dec2008.zip  
  144. //发现COS的最后一次更新,是2008年12月26日  
  145. //真巧了,这一天正是毛主席的生日啊,而且我也是在2010年12月26日那天开始自学Java的。。  
  146. //好了,不扯了,言归正传  
  147. //网上所有我看到的COS使用的例子,都对maxPostSize参数存在一定的误解,说的都不够严密  
  148. //int maxPostSize = 5 * 4 * 1024 * 1024;  
  149. //网上部分人对这行代码的解释是:限定所上传文件的单个大小最大为4MB,且最多只能上传5个文件  
  150. //当时第一反应:这COS也忒棒了吧,这么注重细节,连这个都封装好了??  
  151. //紧接着又一想:貌似不对呀,为何不单独定义一个变量,来限定上传文件的个数呢?  
  152. //像这样都封装到maxPostSize中,貌似不太便于升级和维护啊,这样也未免太懒些了吧  
  153. //伴随着这个疑问,我也就开始步步测试,结果发现:此乃误解!!  
  154. //通过查看COS的源码,在MultipartRequest.java的第70行,发现是这样定义的  
  155. //private static final int DEFAULT_MAX_POST_SIZE = 1024 * 1024;  // 1 Meg  
  156. //这说明了:COS组件的本意,是要用该参数来限定所上传文件的合计大小!!  
  157. //而且在COS主页中,已经对其进行了说明,请参见http://www.servlets.com/cos/faq.html  
  158. //在该页面中,有这样一段话:The default maximum is 1 Meg。。这不就是很好的说明嘛  
  159. //今天,我曾试图翻译http://www.servlets.com/cos/faq.html里的文档  
  160. //因为,这份FAQ写的并不是太难,结果翻译到了一半,发现:这么做,意义不大。于是停止了翻译  
  161. //好了,关于maxPostSize参数的说明,就到这里吧  
  162. //我想说的是:人,要对自己负责,最直接的体现,就是对自己写的代码负责  
  163. //我想说的是:在网上获得到的代码,自己一定要重新运行测试一遍  
  164. //我想说的是:毕竟,人家把代码写到了网上,说明此人不那么吝啬,这是值得肯定和赞许的  
  165. //我想说的是:但作为普通老百姓的咱们,人家没有义务对你负责,这你要知道  
  166. //我想说的是:不要觉得凡是网上的代码,就全部都是正确的,所以毛主席说的好:没有实践就没有发言权  
  167. //我想说的是:同样,我博客的所有代码,虽已经过我的亲自测试,但未免会由于某些JDK环境等因素导致失效  
  168. //我想说的是:所以,如果哪位网友发现,我的某些代码不合时宜,还望不吝指出:jadyer@yeah.net  
  169. /***************************************************************************************************/  

0 0