今天下午安排了一个任务:要实现多文件上传,也就是批量上传文件。相信单个文件上传很多人都实现过,批量上传也有不少人实现过,我之前批量上传的做法是利用js或jquery来动态添加删除<input type="file" name="file" />的。感觉在用户体验上也不是很好,于是在网上google一把,发现大家常用的是swfupload.swf这个插件,网上也有类似的例子,但也发现了GooUploader这个插件,它是基于swfupload.swf,也就是底层封装了改插件,同时可以实现无刷新。于是在网上google一把,下了下来。下下来的可以直接放在tomcat运行了,不过它后台是基于servlet实现的。代码如下:
通过反编译工具查看的,它的底层是基于apache的两个有名的常用的组件:commons-fileupload-1.2.1和commons-io-1.4.jar实现的。
package servlet; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.fileupload.util.Streams; public class UploadFileServlet extends HttpServlet implements Servlet { File tmpDir = null; File saveDir = null; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { request.setCharacterEncoding("UTF-8"); if (ServletFileUpload.isMultipartContent(request)) { DiskFileItemFactory dff = new DiskFileItemFactory(); dff.setRepository(this.tmpDir); dff.setSizeThreshold(1024000); ServletFileUpload sfu = new ServletFileUpload(dff); sfu.setFileSizeMax(109999999L); sfu.setSizeMax(999999999L); FileItemIterator fii = sfu.getItemIterator(request); while (fii.hasNext()) { FileItemStream fis = fii.next(); if ((!fis.isFormField()) && (fis.getName().length() > 0)) { System.out.println(fis.getName()); String fileName = fis.getName(); BufferedInputStream in = new BufferedInputStream(fis.openStream()); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File("f:\\nokia\\" + fileName))); Streams.copy(in, out, true); } } response.getWriter().println("File upload successfully!!!"); } } catch (Exception e) { e.printStackTrace(); } } public void init() throws ServletException { super.init(); String tmpPath = "f:\\nokia\\"; String savePath = "f:\\nokia\\"; this.tmpDir = new File(tmpPath); this.saveDir = new File(savePath); if (!this.tmpDir.isDirectory()) this.tmpDir.mkdir(); if (!this.saveDir.isDirectory()) this.saveDir.mkdir(); System.out.print("UploadFileServlet init"); } }
主要就是这个servlet就实现了。由于我的项目是用ssh2,于是就考虑用struts2来实现,废话少说了,
主要代码如下:
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>文件上传控件GooUploader</title> <link rel="stylesheet" type="text/css" href="codebase/GooUploader.css"/> <script type="text/javascript" src="codebase/jquery-1.3.2.min.js"></script> <script type="text/javascript" src="codebase/GooUploader.js"></script> <script type="text/javascript" src="codebase/swfupload/swfupload.js"></script> <script type="text/javascript"> var demo; var post_params = {session_id:"f1423rwe543t4wrtwerwe"}; var property={ width:300, height:200, multiple:true, //file_post_name : "Filedata", //file_types:"*.jpg;*.gif", // file_types_description: "Web Image Files", // post_params:post_params, btn_add_text:"添加", btn_up_text:"上传", btn_cancel_text:"放弃", btn_clean_text:"清空", op_del_text:"单项删除", op_up_text:"单项上传", op_fail_text:"上传失败", op_ok_text:"上传成功", op_no_text:"取消上传", upload_url:"uploadImage.action", flash_url :"codebase/swfupload.swf" }; $(document).ready(function(){ demo=$.createGooUploader($("#demo"),property) }); </script> </head> <body> <br/> <br/> <div id="demo"></div> </body> </html>
注意: * file_post_name : "Filedata"该参数设置了POST信息中上传文件的name值(类似传统Form中设置了<input type="file" name="uploadImg"/>的name属性)。
* 注意:在Linux下面此参数设置无效,接收的name总为Filedata,因此为了保证最大的兼容性,建议此参数使用默认值。查到这个信息我花了3个小时搜索,最后在文档中找到了,这是用struts2实现的关键。
UploadAction.java
package com.test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.FileUtils; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * @author fish */ public class UploadAction extends ActionSupport { private List<File> Filedata; // 默认的客户端文件对象,命名不符合java规范fileData private List<String> FiledataFileName; // 客户端文件名 private List<String> imageContentType; // 客户端文件名类型 public List<File> getFiledata() { return Filedata; } public void setFiledata(List<File> filedata) { Filedata = filedata; } public List<String> getFiledataFileName() { return FiledataFileName; } public void setFiledataFileName(List<String> filedataFileName) { FiledataFileName = filedataFileName; } public List<String> getImageContentType() { return imageContentType; } public void setImageContentType(List<String> imageContentType) { this.imageContentType = imageContentType; } @Override public String execute() throws Exception { if (Filedata == null || Filedata.size() == 0) { return null; } for (int i = 0; i < Filedata.size(); ++i) { String fileName = FiledataFileName.get(i); // 文件真名 long length = Filedata.get(i).length(); // 文件的真实大小 long time = System.currentTimeMillis(); // 将上传的文件保存到服务器的硬盘上 InputStream is = new BufferedInputStream(new FileInputStream(Filedata.get(i))); HttpServletRequest request = ServletActionContext.getRequest(); // 获得ServletRequest对象 //request.getRealPath("/")已不建议使用,改为this.getServletContext().getRealPath("/") System.out.println("path:"+ServletActionContext.getServletContext().getRealPath("/")); File tempFile = new File(ServletActionContext.getServletContext().getRealPath("/uploadimages")+File.separator+fileName); FileUtils.forceMkdir(tempFile.getParentFile()); // 创建上传文件所在的父目录 OutputStream os = new BufferedOutputStream( new FileOutputStream(tempFile)); int len = 0; byte[] buffer = new byte[500]; while (-1 != (len = is.read(buffer))) { os.write(buffer, 0, len); } is.close(); os.flush(); os.close(); } return null; } }
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.multipart.maxSize" value="100000000000"></constant> <package name="upload" extends="struts-default"> <action name="uploadImage" class="com.test.UploadAction"></action> </package> </struts>
这样就搞定了,说难也不难,说易也不易,关键是要找到类似传统Form中设置了<input type="file" name="uploadImg"/>的name属性,就可以了。若想用servlet实现,直接用源码的例子就可以了。
动态传参:
post_params={value:value}; demo.$swfUpload.setPostParams(post_params);