最近的网站项目中需要实现上传pdf的功能,期间找了很多jquery的插件,都不能满足要求,最后找到GooUploader.js,由于自己是第一次接触上传文件的功能,虽然看了很多写地详细的博客,还是花了很长时间才应用到项目中,所以在这里自己总结一下。
GooUploader.js插件是在swfupload.js基础上进行扩展的,有些比较好的特点:
1. 支持批量文件上传;
2. 上传文件时,选择文件后,可以选择单个文件上传,也可以选择批量文件上传;
3. 开始上传文件后,可以取消单个文件上传,也可以取消批量文件上传;
4. 可以利用flash插件进行进度监视,不需要编写后台代码进行进度检测;
5. UI界面美观,可以自己定义每个按钮的显示文字;
6. 实现了异步刷新效果;
我的项目中使用插件的效果如下(图中“返回”按钮是我修改js文件后的效果,最后会介绍):
下面开始介绍插件的具体使用方法:
1. 首先要引入插件所用的js文件,GooUploader.js、swfupload.js、jquery.min.js,jquery版本为1.5.2,版本过高可能会出现问题,这也是这个插件我觉得不太好用的部分,不能使用高版本的juery,也有可能是我自己没有调试好,这一部分没有做过多研究。css样式文件为GooUploader.css
2. 接着是定义一些插件的参数,代码如下:
var post_params = { folder : $($(t).next()).attr("id"), username : userInfo.userName }; var upload_property = { width : 300,//宽度 height : 300,//长度 multiple : true,//是否批量上传 file_types : "*.pdf",//文件过滤 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 : "upload", flash_url : "/CloudPaper/swfupload.swf" };
一些属性的含义在注释中已经注明,很容易理解,需要着重说明的是调用后台函数的部分,我的项目中使用的是struts2框架,所以这里只介绍在struts2中的使用方法。代码中红色字体 "upload_url"处,为action的名字;"post_params"处,为需要传参的部分,而参数需要提前定义在变量中,格式在代码开始处,传参使用的是requset方式,所以后台参数获取为应使用对应方法。以下为我的项目中获取参数的方法。
String userName = request.getParameter("username");
String folderPath = request.getParameter("folder");
属性中还有一点需要注意,最后一个属性flash_url应填写一个swfupload.swf文件的路径,这是为了检测进度显示所用,但是因为GooUploader.js插件中定义了缺省值,所以这里建议写上自己的绝对路径,否则可能会出现路径找不到的问题,我在这里耗费不少时间。
3. 在页面中定义一个空的div,在调用生成函数即可,create_ret是返回结果,可以通过它获取一些属性,但我没用太多应用,这里不好做太多介绍,以免误导。函数的第一个参数为页面中的div对象,这里是通过取id的方式获取,后一个为上面定义过的属性。
var create_ret = $.createGooUploader($("#upload"),upload_property);
4. 接下来写后台文件,以下代码是我找到的大牛博客中的一段代码,做了一小部分修改,给重名文件在原名后加一个数字。
参考地址:http://blog.csdn.net/ocean_30/article/details/6747643
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; 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 UploadFile 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) { HttpServletRequest request = ServletActionContext.getRequest(); // 获得ServletRequest对象 String userName = request.getParameter("username"); // 文件真名 String fileName = FiledataFileName.get(i); int fileOrderNum=0;//用来计数重名文件 long length = Filedata.get(i).length(); // 文件的真实大小 long time = System.currentTimeMillis(); // 将上传的文件保存到服务器的硬盘上 InputStream is = new BufferedInputStream(new FileInputStream(Filedata.get(i))); System.out.println("path:"+ServletActionContext.getServletContext().getRealPath("/")); String tmpSaveFileName = ServletActionContext.getServletContext().getRealPath("/userFiles/" + userName + "/pdf" ) + File.separator + fileName; File tmpFile = new File(tmpSaveFileName); while(tmpFile.exists()) { fileOrderNum++; tmpSaveFileName = ServletActionContext.getServletContext().getRealPath("/userFiles/" + userName + "/pdf" ) + File.separator + fileName+"("+fileOrderNum+")"; tmpFile = new File(tmpSaveFileName); } FileUtils.forceMkdir(tmpFile.getParentFile()); // 创建上传文件所在的父目录 OutputStream os = new BufferedOutputStream( new FileOutputStream(tmpFile)); 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 "success"; } }
5. 最后配置struts2,前面已经说过,插件实现的是异步刷新,所以这里的返回只需要随便写一个真实存在的jsp即可,不会对返回有影响。
<action name="upload" class="com.UploadFile"> <result name="success">/jsp/index.jsp</result> </action>
因为原插件中没有返回按钮,所以自己修改了GooUploader.js中的一小部分代码,加入了返回功能,在源码中找到this.$multiple,加入红色代码,可以在页面上加入返回按钮,如果想要修改显示图片,可以修改<b>标签的class。
if(this.$multiple){ this.$btn_upload=$("<div class='upload_btn'><div class='left'></div><div><b class='upload'>"+(property.btn_up_text||"Upload")+"</b></div><div class='right'></div></div>"); this.$btn_cancel=$("<div class='upload_btn' style='display:none'><div class='left'></div><div><b class='cancel'>"+(property.btn_cancel_text||"Cancel")+"</b></div><div class='right'></div></div>"); this.$btn_clean=$("<div class='upload_btn' style='float:right'><div class='left'></div><div><b class='clean'>"+(property.btn_clean_text||"Clean")+"</b></div><div class='right'></div></div>"); this.$btn_back=$("<div class='upload_btn' style='float:right'><div class='left'></div><div><b class='clean'>"+"返回"+"</b></div><div class='right'></div></div>"); this.$div_btn.append(this.$btn_upload).append(this.$btn_cancel).append(this.$btn_clean).append(this.$btn_back); }
在源码中找到以下代码,加入红色代码,为上面添加的按钮绑定调用函数即可。
if(this.$multiple){ this.$btn_upload.bind("click",{content:this.$content,fileList:this.$fileList,cancel:this.$btn_cancel},function(e){ for(var key in e.data.fileList){ var li=e.data.content.children("#"+key); if(li.children(".op_up").css("display")=="block"){ inthis.$goon=li.attr("id"); li.children(".op_up").click(); this.style.display="none"; e.data.cancel.css({display:"block"}); break; } } }); this.$btn_cancel.bind("click",{content:this.$content,fileList:this.$fileList},function(e){ for(var key in e.data.fileList){ var li=e.data.content.children("#"+key); if(li.children(".op_up").css("display")=="block"){ li.children(".op_up").css("display","none"); li.children(".op_del").css("display","none"); li.children(".op_no").click(); } else if(li.children(".op_no").css("display")=="block"){ li.children(".op_no").click(); } } }); this.$btn_clean.bind("click",{swfUpload:this.$swfUpload,content:this.$content,fileList:this.$fileList},function(e){ if(e.data.swfUpload.getStats().in_progress==0){ for(var key in e.data.fileList){ e.data.content.children("#"+key).remove(); e.data.fileList[key]=null; } } }); this.$btn_back.bind("click",function(e){
....... }); }