Cooky - study blog

Java, Grails, OpenSolaris, Linux, programming, skateboarding...

用commons-fileupload-1.2 实现文件上传

    前几天搞文件上传, Google到了Apache 的 commons-fileupload-1.2.jar 上传组件, 研究了API然后结合Hibernate实现了上传图片
并保存到MySQL数据库. 今天重新写了一遍, 由于不需要保存到数据库了, 就实现了保存成文件格式.

    我的这个FileUpload web工程源文件下载如下 :
FileUpload.rar . 解压到当前文件夹后直接剪切到 Tomcat 主目录下的 webapps 
目录下, 启动 Tomcat 后在浏览器输入 
http://localhost:8080/FileUpload/upload.html 查看演示.

    我是用Eclipse 开发. 首先, 下载两个开发包: commons-fileupload 和 commons-io(这个在应用commons-fileupload时会用到).
这两个开发包(jar文件) 在我前面提供的FileUpload 工程下的WEB-INF/lib下可以找到, 你也可以到官方下载:
http://commons.apache.org/downloads/download_fileupload.cgi 下载 commons-fileupload-1.2.jar
组件包 (直接下载地址:
http://apache.mirror.phpchina.com/commons/fileupload/binaries/commons-fileupload-1.2-bin.zip),
http://commons.apache.org/downloads/download_io.cgi 下载 commons-io-1.3.2 组件包(直接下载地址:
 
http://apache.mirror.phpchina.com/commons/io/binaries/commons-io-1.3.2-bin.zip). 

    启动Eclipse, 新建Web Project, 取名 FileUpload. 然后在WebRoot文件夹(Web根文件夹)下新建两个文件夹(New->Folder) :
ImagesUploaded 和 ImagesUploadTemp, 分别用来存放上传文件和上传时的临时文件,稍后代码里会用到.

     在WebRoot 文件夹下新建文件upload.html, 用来提供上传用的form. 源代码如下: 
     右击src, 新建一个Servlet: FileUploadServlet, 路径设为src/FileUploadServlet . 保存后WebRoot/WEB-INF/web.xml 更新为:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>FileUploadServlet</servlet-name>
    <servlet-class>FileUploadServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>FileUploadServlet</servlet-name>
    <url-pattern>/FileUploadServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>upload.html</welcome-file>
  </welcome-file-list>
</web-app>


   
    其中,我把<welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list> 的欢迎文件设为了upload.html,
这样等完成后可能直接用
http://localhost:8080/FileUpload/ 来访问upload.html. 不改的话, 可以在http://localhost:8080/FileUpload/upload.html
页面上传文件.    在写FileUploadServlet 之前, 先将之前下载的commons-fileupload 和commons-io 组件包压缩文件解压出来, 把里面的
commons-fileupload-1.2.jar (lib文件夹下) 和 commons-io-1.3.2.jar 拷到WebRoot/WEB-INF/lib 文件夹下, 以便使用它们的功能.

    FileUploadServlet.java 的源代码如下, 附有详细注解:
FileUploadServlet.java

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class FileUploadServlet extends HttpServlet {

 public FileUploadServlet() {
  super();
 }

 public void destroy() {
  super.destroy(); // Just puts "destroy" string in log
  // Put your code here
 }

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  doPost(request, response);
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  final long MAX_SIZE = 3 * 1024 * 1024;// 设置上传文件最大为 3M
  // 允许上传的文件格式的列表
  final String[] allowedExt = new String[] { "jpg", "jpeg", "gif", "txt",
    "doc", "docx", "mp3", "wma", "m4a" };
  response.setContentType("text/html");
  // 设置字符编码为UTF-8, 这样支持汉字显示
  response.setCharacterEncoding("UTF-8");

  // 实例化一个硬盘文件工厂,用来配置上传组件ServletFileUpload
  DiskFileItemFactory dfif = new DiskFileItemFactory();
  dfif.setSizeThreshold(4096);// 设置上传文件时用于临时存放文件的内存大小,这里是4K.多于的部分将临时存在硬盘
  dfif.setRepository(new File(request.getRealPath("/")
    + "ImagesUploadTemp"));// 设置存放临时文件的目录,web根目录下的ImagesUploadTemp目录

  // 用以上工厂实例化上传组件
  ServletFileUpload sfu = new ServletFileUpload(dfif);
  // 设置最大上传尺寸
  sfu.setSizeMax(MAX_SIZE);

  PrintWriter out = response.getWriter();
  // 从request得到 所有 上传域的列表
  List fileList = null;
  try {
   fileList = sfu.parseRequest(request);
  } catch (FileUploadException e) {// 处理文件尺寸过大异常
   if (e instanceof SizeLimitExceededException) {
    out.println("文件尺寸超过规定大小:" + MAX_SIZE + "字节<p />");
    out.println("<a href=\"upload.html\" target=\"_top\">返回</a>");
    return;
   }
   e.printStackTrace();
  }
  // 没有文件上传
  if (fileList == null || fileList.size() == 0) {
   out.println("请选择上传文件<p />");
   out.println("<a href=\"upload.html\" target=\"_top\">返回</a>");
   return;
  }
  // 得到所有上传的文件
  Iterator fileItr = fileList.iterator();
  // 循环处理所有文件
  while (fileItr.hasNext()) {
   FileItem fileItem = null;
   String path = null;
   long size = 0;
   // 得到当前文件
   fileItem = (FileItem) fileItr.next();
   // 忽略简单form字段而不是上传域的文件域(<input type="text" />等)
   if (fileItem == null || fileItem.isFormField()) {
    continue;
   }
   // 得到文件的完整路径
   path = fileItem.getName();
   // 得到文件的大小
   size = fileItem.getSize();
   if ("".equals(path) || size == 0) {
    out.println("请选择上传文件<p />");
    out.println("<a href=\"upload.html\" target=\"_top\">返回</a>");
    return;
   }

   // 得到去除路径的文件名
   String t_name = path.substring(path.lastIndexOf("\\") + 1);
   // 得到文件的扩展名(无扩展名时将得到全名)
   String t_ext = t_name.substring(t_name.lastIndexOf(".") + 1);
   // 拒绝接受规定文件格式之外的文件类型
   int allowFlag = 0;
   int allowedExtCount = allowedExt.length;
   for (; allowFlag < allowedExtCount; allowFlag++) {
    if (allowedExt[allowFlag].equals(t_ext))
     break;
   }
   if (allowFlag == allowedExtCount) {
    out.println("请上传以下类型的文件<p />");
    for (allowFlag = 0; allowFlag < allowedExtCount; allowFlag++)
     out.println("*." + allowedExt[allowFlag]
       + "&nbsp;&nbsp;&nbsp;");
    out.println("<p /><a href=\"upload.html\" target=\"_top\">返回</a>");
    return;
   }

   long now = System.currentTimeMillis();
   // 根据系统时间生成上传后保存的文件名
   String prefix = String.valueOf(now);
   // 保存的最终文件完整路径,保存在web根目录下的ImagesUploaded目录下
   String u_name = request.getRealPath("/") + "ImagesUploaded/"
     + prefix + "." + t_ext;
   try {
    // 保存文件
    fileItem.write(new File(u_name));
    out.println("文件上传成功. 已保存为: " + prefix + "." + t_ext
      + " &nbsp;&nbsp;文件大小: " + size + "字节<p />");
    out.println("<a href=\"upload.html\" target=\"_top\">继续上传</a>");
   } catch (Exception e) {
    e.printStackTrace();
   }
 }

 }

 public void init() throws ServletException {
  // Put your code here
 }

}

  

    保存后部署项目(MyEclipse下直接点击Deploy J2EE...按钮, 然后选择Tomcat服务器). 没有MyEclipse的话, 把WebRoot 拷到
Tomcat 主目录下的webapps 目录下, 并重命名为 FileUpload 然后启动Tomcat. (或直接下载我在文章开始提供的工程打包rar文件).
最后打开浏览器, 输入url:
 
http://localhost:8080/FileUpload/upload.html .

    关于开发工具的基本配置( Eclipse 等), 请参加我的另一篇文章.


Keep It Simple, Stupid

posted on 2007-10-02 19:55 Cooky 阅读(25377) 评论(51)  编辑  收藏 所属分类: Java

评论

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-12 22:16 xpg

好文章,先试用一下,谢谢!!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-13 01:02 cooky

@xpg
3Q!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-18 22:08 lion

不错 谢谢分享  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-19 00:37 cooky

@lion
:)  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-20 13:24 cooky

用Firefox看排版有点小问题...不好意思  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-22 19:23 nike

just test  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-22 19:24 nike

确实很强  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-22 19:28 nike

你很厉害哦  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-10-22 22:45 cooky

@nike
.....  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-11-05 23:23 WRF

谢谢!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-11-18 14:15 上帝也犯困

顶一下,非常的感谢你.  回复  更多评论   

# re: 用commons-fileupload-1.2 实上传 2007-12-13 15:30 现文件

upload.html  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2007-12-27 15:49 hehe

ww  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2007-12-28 17:31 常常

写得不错很有开源精神,不像有些人代码开源还用软件整理得乱七八糟。  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-01-03 21:23 cynthia

谢谢,正着急呢。  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-01-04 11:09 lyle

good good!!!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-01-05 00:39 cc

我把FileUpload.rar解压到当前文件夹后直接剪切到 Tomcat 主目录下的 webapps 目录下, 启动 Tomcat 后在浏览器输入 http://localhost:8080/FileUpload/upload.html
出现错误如下:
javax.servlet.ServletException: Error allocating a servlet instance
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:685)
java.lang.Thread.run(Unknown Source)


root cause

java.lang.UnsupportedClassVersionError: Bad version number in .class file
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(Unknown Source)
java.security.SecureClassLoader.defineClass(Unknown Source)
org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1847)
org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:873)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1326)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1205)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:685)
java.lang.Thread.run(Unknown Source)

这是什么原因?

麻烦大家帮忙分析一下  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-01-05 12:34 cooky

java.lang.UnsupportedClassVersionError: Bad version number in .class file . 这个应该是由于JDK版本不一致. 我原来的好像是用JDK1.6做的. 你需要重新编译一下. 版本一致有三个地方需要设置:
1.安装JDK(如1.5或1.6), 设置JAVA_HOME变量. 在Eclipse的菜单:
Window->Preferences->Java->Installed JREs: (Add...)jdk1.5.x(或1.6.x)
2.设置编译版本:Window->Preferences->Java->Compiler:Compiler compliance level: 5.0(或6.0, 跟第1步中的一致)
3.设置Tomcat运行环境:只要在第1步中设置了JAVA_HOME环境变量后,Tomcat会使用设置的JDK版本. 在MyEclipse需要另外进行设置:
Window->Preferences->MyEclipse->Application Servers->Tomcat->Tomcat 6.x(或5.x)->JDK:jdk1.5.x(或1.6.x)
[先把你要的Tomcat版本Enable一下]

1,2,3中的选择的JDK版本要一致.
  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-01-05 12:35 cooky

@cc
如上  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-04-01 09:55 temper

上传大文件,比如为几百m时,开始的时候会在fileList = sfu.parseRequest(request);抛出尺寸过大的异常,但是好像程序会继续上传,或者进行别的操作,几分钟以后才会跳到异常页(时间可能根据个人的机器配置不同)。
请问有没有一个可以遇到异常,马上到错误页的方法?  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-04-01 10:05 Cooky

@temper 好像是这样的,我还没找到好的方法。。。  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-04-08 20:26 初树雷

我的  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-04-10 14:11 paulQuei

我靠,我摆渡过来的  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-04-10 14:19 Cooky

@paulQuei 呵呵  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-04-16 21:37 蓝色自由

不错,谢谢~~~  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-05-11 20:46 lc

传递输入地址的Form一定要multipart/Form-data编码吗?
我还想Form中输入一些别的内容,用request.getParameter就找不到啊。  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-05-13 20:39 WEIQ

你写的很好啊,非常感谢,我在网上找了很多个,没有一个像你写的那么明了的  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-05-13 21:23 WEIQ

为什么一定要过滤掉表单里的文本字段啊,想加点文字描述都不行  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-05-13 22:09 Cooky

@WEIQ
那个好像是ServletFileUpload的parseRequest方法的问题,它会重新解析request. 至于commons-fileupload可不可以一起处理multipart/form-data和文本,我不清楚,应该可以的吧. 你再查下资料好了, 这个我好久没搞了.
;)  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-05-18 08:11 王林

哪位高人可以提供上传文件到数据库的代码?显现身手吧  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-05-20 14:27 beenylee

非常感谢您的无私奉献  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-05-20 14:31 beenylee

挺佩服你的,我下载到了common fileuplod包以后,看了API还是不会用,看完您这篇文章才学会使用,我想请教的是,对于一个陌生的东西(比如common fileupload),想要正确使用它,有没有普遍的方法?  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-05-21 14:50 dudu

那我表单传过来的其他数据怎么获得?用request.getParameter就找不到啊  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2008-06-25 13:08 huang

写的太好了!谢谢了!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-11-05 12:32 123

xiexie  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2008-11-05 19:59 cooky

好久以前写的了, 多谢大家的支持.
那时是在学校里, 自由时间比较多, 现在工作半年了, 大多接触的是 GWT 和 Ruby on Rails. 不过最近跟几个朋友用 Lightweight JavaEE 搞个 Blog 网站, 到时会把源码公开 (在 Google Code 上), 消息我会更新在我的 blogpost 里 (见此网站左边的链接), 也尽量记得把项目地址发在这 :)

祝大家的程序员生涯一帆风顺 ;-)  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2009-01-07 10:42 java

实用,谢了  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2009-03-04 00:47 三棵

不错
  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2009-04-06 22:12

谢谢楼主  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2009-04-06 22:12

谢谢楼主 很好用  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2009-06-02 23:31 江哥

ImagesUploaded 和 ImagesUploadTemp没有看到上传的内容,进行测式的时候,页面显示成功了,也把上传的文件大小,时间打印出来的,就是在ImagesUploaded 和 ImagesUploadTemp没有看到上传的内容?这是怎么回事?
dfif.setRepository(new File(request.getRealPath("/")
+ "ImagesUploadTemp"));
中的request.getRealPath(有下划线)是不推荐使作的方法,和这个有关吗?  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2009-06-03 09:39 cooky

@江哥
可能是文件路径的问题. 可以使用以下方法来获得保存文件的路径:
假设这个Servlet的.class文件最终被放在 FileUpload/WEB-INF/classes/文件夹中 (Windows 下的文件路径分隔符好像应该使用反斜杠 \), 而要保存文件的文件夹位于 FileUpload/WEB-INF/ImagesUploaded/, 则用以下代码修改后替换原来的保存文件的部分 (fileItem.wirte(new File(u_name)) 那儿):
String fileName = "a.jpg";// TODO replace with your file name
/* file path separator: "/" for Unix/Linux, "\\" for Windows */
final String PATH_SEPARATOR = "/";
File currFolder = null;
try {
currFolder = new File(Main.class.getResource("/").toURI());
} catch (URISyntaxException e) {
e.printStackTrace();// TODO log the exception
}
if (currFolder != null) {
String pathToSave = currFolder.getParent() + PATH_SEPARATOR + "ImagesUploaded" + PATH_SEPARATOR;
pathToSave += fileName;
// System.out.println(pathToSave);
fileItem.write(new File(pathToSave));
} else {
System.out.println("Can not locate the folder to save file");// TODO
}  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2009-07-15 11:52 小强

各种方法非常好,谢谢  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2010-01-30 10:15 hao

很不错,顶!!!!!  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2010-07-06 09:22 wh

ding ~~~  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2012-03-26 20:34 jiaoxuekun

求源码  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传[未登录] 2012-09-26 14:31 s

谢谢~~  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2012-10-19 18:54 ly

多谢啊 看了这个学习了  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2012-11-26 13:52 tw

3Q  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2012-12-19 19:20 清泉..

谢谢,写得很详细  回复  更多评论   

# re: 用commons-fileupload-1.2 实现文件上传 2014-08-30 21:30 213213

非常感谢。已经掌握了  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: