SWFUpload技术文档

lihuistorm 贡献于2011-07-05

作者 胡佳  创建于2010-12-19 13:36:00   修改者hoojo  修改于2010-12-22 03:31:00字数20004

文档摘要:SWF多文件无刷新上传,利用flash完成多文件上传操作。服务器端可以用Struts、Servlet、JSP完成,这里用Struts1.x完成上传。
关键词:

SWFUpload SWF多文件无刷新上传,利用flash完成多文件上传操作。服务器端可以用Struts、Servlet、JSP完成,这里用Struts1.x完成上传 1、 首先看下目录结构 SWFUpload这个文件夹是核心文件,里面的文件一个都不能少。 css文件夹是样式文件,所有的样式可以在此文件中修改完成 images是图片 jslib是js库文件,需要的上传的js文件和flash文件 其中handlers.js是上传中一系列的事件,可以在此文件中修改自己的上传所需要的事件。如开始上传、取消、停止上传等 swfupload.queue.js这个文件主要是完成将客户端选择的多一个文件一个个的排成一个队列,然后依次向服务器上传。 swfupload.swf是flash文件,就那个添加或上传的按钮 sample.html是完成后的上传实例 2、 首先看看客户端的sample.html中的js和html内容 SWFUpload 多文件上传示例

上传文件列表
A.先介绍导入的js文件 这些文件是必须的,且在导入的时候注意你的路径和顺序。还有就文件编码,文件保存的不同编码可以会影响文件显示的乱码问题,charset就是文件保存的编码。 B.然后在其中是script脚本的参数详细讲解 设置flash文件 flash_url : "jslib/swfupload.swf", 设置服务器的上传地址 upload_url: "../upload.do", 提交到服务器的参数信息,这样就添加了一个param参数,值是uploadParams在服务器端用request.getParameter(“param”)就可以拿到值 post_params: {"param" : "uploadParams"}, 上传文件的最大空间 file_size_limit : "200MB", 允许上传文件的类型,*.*是所有,*.txt只能上传文本 file_types : "*.*", 这个就服务器端要获得的文件的属性,相当于file的name file_post_name: "uploadFile", 所有文件夹 file_types_description : "All Files", 上传文件选取的最大队列数 file_upload_limit : 50, file_queue_limit : 0, 下面是上传按钮的设置 button_image_url: "images/TestImageNoText_65x29.png", button_width: "65", button_height: "29", button_placeholder_id: "spanButtonPlaceHolder", button_text: '浏 览', button_text_style: ".theFont { font-size: 12; }", button_text_left_padding: 12, button_text_top_padding: 3, 下面是上传事件和函数: 选择完文件后就触发 file_queued_handler : fileQueued, 上传文件错误时触发 file_queue_error_handler : fileQueueError, 上传文件弹出窗口,窗口关闭触发 file_dialog_complete_handler : fileDialogComplete, 开始上传触发 upload_start_handler : uploadStart, upload_progress_handler : uploadProgress, 上传错误触发 upload_error_handler : uploadError, 上传成功 upload_success_handler : uploadSuccess, 完成 upload_complete_handler : uploadComplete, 队列中上传完成 queue_complete_handler : queueComplete 下面看看html代码:

上传文件列表
值得介绍的是 这个span就会被flsah的浏览多代替,注意这里的id和上面js button_placeholder_id是对应的 这个是上传按钮,点击上传就会执行upload这个js方法 这个是停止上传的,可以取消当前正在上传的文件,运行stop方法 取消所有的队列文件 3、 官方的handlers被修改的几个方法 选择文件后显示文件的大小 function fileQueued(file) { try { var progress = new FileProgress(file, this.customSettings.progressTarget); var size = file.size; var unit = "B"; if (size > (1024 * 1024 * 1024)) { unit = "GB"; size /= (1024 * 1024 * 1024); } else if (size > (1024 * 1021)) { unit = "MB"; size /= (1024 * 1024); } else if (size > 1024) { unit = "KB"; size /= 1024; } progress.setStatus("" + size.toFixed(2) + " " + unit + " 等待上传......"); progress.toggleCancel(true, this); } catch (ex) { this.debug(ex); } } 显示当前文件上传进度的百分比 function uploadProgress(file, bytesLoaded, bytesTotal) { try { var percent = Math.ceil((bytesLoaded / bytesTotal) * 100); var progress = new FileProgress(file, this.customSettings.progressTarget); progress.setProgress(percent); progress.setStatus("已上传 " + percent+ "% ......"); } catch (ex) { this.debug(ex); } } 获取服务器端上传后返回的信息 function uploadSuccess(file, serverData) { try { var progress = new FileProgress(file, this.customSettings.progressTarget); progress.setComplete(); var data = eval("(" + serverData + ")"); if (data.success == 0 || data.success == "0") { progress.setStatus("上传完成!"); } else { progress.setError(); progress.setStatus("上传失败!" + data.message); } progress.toggleCancel(false); } catch (ex) { this.debug(ex); } } 4、 下面看看服务器端的上传代码 //上传文件保存路径 public static String path = "/upload/"; //定义可以上传文件的后缀数组,默认"*",代表所有 public static String[] filePostfixs = { "*" }; public static String[] typeImages = { "gif", "jpeg", "png", "jpg", "tif", "bmp" }; public static String[] typeOthers = { "html", "htm", "doc", "xls", "txt", "zip", "rar", "pdf", "cll" }; //上传文件的最大长度 public static long maxFileSize = 1024 * 1024 * 2;//2M //一次读取多少字节 public static int bufferSize = 1024 * 8; private final static void init() { if (bufferSize > Integer.MAX_VALUE) { bufferSize = 1024 * 8; } else if (bufferSize < 8) { bufferSize = 8; } if (maxFileSize < 1) { maxFileSize = 1024 * 1024 * 1024 * 2L; } else if (maxFileSize > Long.MAX_VALUE) { maxFileSize = 1024 * 1024 * 1024 * 2L; } } /** * function:根据传递InputStream,上传文件 * @createDate Dec 19, 2010 8:53:12 PM * @param is InputStream * @param fileName 文件名 * @param path 保存路径 * @return 上传状态 * @throws Exception */ public static UploadState upload4Stream(InputStream is, String fileName, String path) throws Exception { init(); UploadState state = UploadState.UPLOAD_FAILURE; if (fileName == null && "".equals(fileName)) { fileName = getRandomName(fileName); } OutputStream os = null; try { path = getDoPath(path); mkDir(path); fileName = getBracketFileName(fileName, path); os = new FileOutputStream(path + fileName); int read = 0; byte[] buffer = new byte[bufferSize]; while ((read = is.read(buffer)) != -1) { os.write(buffer, 0, read); } state = UploadState.UPLOAD_SUCCSSS; } catch(FileNotFoundException e) { state = UploadState.UPLOAD_NOTFOUND; throw e; } catch (Exception e) { state = UploadState.UPLOAD_FAILURE; throw e; } finally { if (is != null) { is.close(); } if (os != null) { os.flush(); os.close(); } } return state; } /** * function: 主要针对struts的FormFile进行文件上传 * @createDate Oct 9, 2010 11:22:14 PM * @param file FormFile * @param path 路径 * @return UploadState 是否上传成功 * @throws Exception */ public static UploadState upload(FormFile file, String fileName, String path) throws Exception { init(); UploadState state = UploadState.UPLOAD_FAILURE; if (fileName == null && "".equals(fileName)) { fileName = file.getFileName(); } InputStream is = null; try { long fileSize = file.getFileSize(); if (fileSize <= 0) { state = UploadState.UPLOAD_ZEROSIZE; } else { if (fileSize <= maxFileSize) { is = file.getInputStream(); state = upload4Stream(is, fileName, path); } else { state = UploadState.UPLOAD_OVERSIZE; } } } catch(FileNotFoundException e) { state = UploadState.UPLOAD_NOTFOUND; throw e; } catch (Exception e) { state = UploadState.UPLOAD_FAILURE; throw e; } finally { if (is != null) { is.close(); } } return state; } /** * function:struts上传文件,并根据传递的文件类型数组验证上传的文件是否合法 * @createDate Oct 10, 2010 3:53:59 PM * @param file FormFile * @param path 路径 * @param allowTypes 文件类型数组 * @return UploadState 是否上传成功 * @throws Exception */ public static UploadState upload(FormFile file, String fileName, String path, String[] allowTypes) throws Exception { UploadState state = UploadState.UPLOAD_FAILURE; if (validTypeByName(file.getFileName(), allowTypes)) { state = upload(file, fileName, path); } return state; } upload4Stream是通过传递InputStream完成上传,这个方法不管是是FormFile、File还是其他的文件对象都可以完成上传。你也可以根据自己的需求进行二次封装完成上传。 上面的上传还用到了其他的验证、命名、路径等辅助方法,详细请看源代码。 验证文件名、类型 /** * function: 根据文件名和类型数组验证文件类型是否合法,flag是否忽略大小写 * @createDate Oct 10, 2010 11:54:54 AM * @param fileName 文件名 * @param allowTypes 类型数组 * @param flag 是否获得大小写 * @return 是否验证通过 */ public static boolean validTypeByName(String fileName, String[] allowTypes, boolean flag) { String suffix = getType(fileName); boolean valid = false; if (allowTypes.length > 0 && "*".equals(allowTypes[0])) { valid = true; } else { for (String type : allowTypes) { if (flag) {//不区分大小写后缀 if (suffix != null && suffix.equalsIgnoreCase(type)) { valid = true; break; } } else {//严格区分大小写 if (suffix != null && suffix.equals(type)) { valid = true; break; } } } } return valid; } /** * function:根据文件名称和类型数组验证文件类型是否合法 * @createDate Oct 10, 2010 10:27:17 AM * @param fileName 文件名 * @param allowTypes 文件类型数组 * @return 是否合法 */ public static boolean validTypeByName(String fileName, String[] allowTypes) { return validTypeByName(fileName, allowTypes, true); } /** * function: 根据后缀和类型数组验证文件类型是否合法,flag是否区分后缀大小写,true严格大小写 * @createDate Oct 10, 2010 12:00:10 PM * @param suffix 后缀名 * @param allowTypes 文件类型数组 * @param flag 是否区分大小写 * @return 是否合法 */ public static boolean validTypeByPostfix(String suffix, String[] allowTypes, boolean flag) { boolean valid = false; if (allowTypes.length > 0 && "*".equals(allowTypes[0])) { valid = true; } else { for (String type : allowTypes) { if (flag) {//不区分大小写后缀 if (suffix != null && suffix.equalsIgnoreCase(type)) { valid = true; break; } } else {//严格区分大小写 if (suffix != null && suffix.equals(type)) { valid = true; break; } } } } return valid; } /** * function:根据文件后缀名和类型数组,验证文件类型是否合法 * @createDate Oct 10, 2010 10:25:32 AM * @param suffix 后缀名 * @param allowTypes 类型数组 * @return 是否合法 */ public static boolean validTypeByPostfix(String suffix, String[] allowTypes) { return validTypeByPostfix(suffix, allowTypes, true); } /** * function:验证当前后缀、文件类型是否是图片类型 * typeImages 可以设置图片类型 * @createDate Oct 10, 2010 12:17:18 PM * @param suffix 验证文件的后缀 * @return 是否合法 */ public static boolean validTypeByPostfix4Images(String suffix) { return validTypeByPostfix(suffix, typeImages); } /** * function:验证当前后缀、文件类型是否是非图片类型(常用办公文件类型) * typeOthers 可以设置文件类型 * @createDate Oct 10, 2010 12:18:18 PM * @param suffix 验证文件的后缀 * @return 是否合法 */ public static boolean validTypeByPostfix4Others(String suffix) { return validTypeByPostfix(suffix, typeOthers); } /** * function:验证当前文件名、文件类型是否是图片类型 * typeImages 可以设置图片类型 * @createDate Oct 10, 2010 12:19:18 PM * @param fileName 验证文件的名称 * @return 是否合法 */ public static boolean validTypeByName4Images(String fileName) { return validTypeByName(fileName, typeImages); } /** * function:验证当前文件名称、文件类型是否是非图片类型(常用办公文件类型) * typeOthers 可以设置文件类型 * @createDate Oct 10, 2010 12:21:22 PM * @param fileName 验证文件的名称 * @return 是否合法 */ public static boolean validTypeByName4Others(String fileName) { return validTypeByName(fileName, typeOthers); } 文件删除操作,对重名的文件可以删除或是替换 /** * function:传递一个路径和文件名称,删除该文件 * @createDate Oct 10, 2010 10:47:57 AM * @param fileName 文件名称 * @param path 路径 * @return 是否删除成功 */ public static boolean removeFile(String fileName, String path) { boolean flag = false; if (isFileExist(fileName, path)) { File file = new File(getDoPath(path) + fileName); flag = file.delete(); } return flag; } /** * function:删除文件 * @createDate Oct 10, 2010 10:49:54 AM * @param file 要删除的文件 * @return 是否删除成功 */ public static boolean removeFile(File file) { boolean flag = false; if (file != null && file.exists()) { flag = file.delete(); } return flag; } 获得文件类型、后缀、名称等操作 /** * function: 传入一个文件名,得到这个文件名称的后缀 * @createDate Oct 9, 2010 11:30:46 PM * @param fileName 文件名 * @return 后缀名 */ public static String getSuffix(String fileName) { int index = fileName.lastIndexOf("."); if (index != -1) { String suffix = fileName.substring(index);//后缀 return suffix; } else { return null; } } /** * function:和文件后缀一样,不同的是没有“.” * @createDate Oct 10, 2010 2:42:43 PM * @param fileName 文件名称 * @return */ public static String getType(String fileName) { int index = fileName.lastIndexOf("."); if (index != -1) { String suffix = fileName.substring(index + 1);//后缀 return suffix; } else { return null; } } /** * function: 传递一个文件名称和一个新名称,组合成一个新的带后缀文件名 * 当传递的文件名没有后缀,会添加默认的后缀 * @createDate Oct 9, 2010 10:53:06 PM * @param fileName 文件名称 * @param newName 新文件名称 * @param nullSuffix 为没有后缀的文件所添加的后缀;eg:txt * @return String 文件名称 */ public static String getNewFileName(String fileName, String newName, String nullSuffix) { String suffix = getSuffix(fileName); if (suffix != null) { newName += suffix; } else { newName = newName.concat(".").concat(nullSuffix); } return newName; } /** * function: 利用uuid产生一个随机的name * @createDate Oct 9, 2010 10:45:27 PM * @param fileName 带后缀的文件名称 * @return String 随机生成的name */ public static String getRandomName(String fileName) { String randomName = UUID.randomUUID().toString(); return getNewFileName(fileName, randomName, "txt"); } /** * function: 用当前日期、时间和1000以内的随机数组合成的文件名称 * @createDate Oct 9, 2010 11:01:47 PM * @param fileName 文件名称 * @return 新文件名称 */ public static String getNumberName(String fileName) { SimpleDateFormat format = new SimpleDateFormat("yyMMddhhmmss"); int rand = new Random().nextInt(1000); String numberName = format.format(new Date()) + rand; return getNewFileName(fileName, numberName, "txt"); } /** * function:判断该文件是否存在 * @createDate Oct 10, 2010 12:00:44 AM * @param fileName 文件名称 * @param path 目录 * @return 是否存在 */ public static boolean isFileExist(String fileName, String path) { File file = new File(getDoPath(path) + fileName); return file.exists(); } /** * function:返回可用的文件名 * @createDate Oct 10, 2010 1:02:45 AM * @param fileName 文件名 * @param path 路径 * @return 可用文件名 */ public static String getBracketFileName(String fileName, String path) { return getBracketFileName(fileName, fileName, path, 1); } /** * function:递归处理文件名称,直到名称不重复(对文件名、目录文件夹都可用) * eg: a.txt --> a(1).txt
* 文件夹upload--> 文件夹upload(1) * @createDate Oct 10, 2010 12:56:27 AM * @param fileName 文件名称 * @param path 文件路径 * @param num 累加数字,种子 * @return 返回没有重复的名称 */ public static String getBracketFileName(String fileName, String bracketName, String path, int num) { boolean exist = isFileExist(bracketName, path); if (exist) { int index = fileName.lastIndexOf("."); String suffix = ""; bracketName = fileName; if (index != -1) { suffix = fileName.substring(index); bracketName = fileName.substring(0, index); } bracketName += "(" + num + ")" + suffix; num++; bracketName = getBracketFileName(fileName, bracketName, path, num); } return bracketName; } /** * function:处理后的系统文件路径 * @createDate Oct 10, 2010 12:49:31 AM * @param path 文件路径 * @return 返回处理后的路径 */ public static String getDoPath(String path) { path = path.replace("\\", "/"); String lastChar = path.substring(path.length() - 1); if (!"/".equals(lastChar)) { path += "/"; } return path; } /** * function: 创建指定的path路径目录 * @createDate Oct 9, 2010 11:03:49 PM * @param path 目录、路径 * @return 是否创建成功 * @throws Exception */ public static boolean mkDir(String path) throws Exception { File file = null; try { file = new File(path); if (!file.exists()) { //file.mkdir();创建子目录,如果父目录不存在则不创建 return file.mkdirs(); } } catch (RuntimeException e) { throw e; } finally { file = null; } return false; } 上面的上传还需要一个上传状态的枚举对象,代码如下: package com.hoo.enums; /** * function: 文件上传状态 * @fileName UploadState.java * @createDate 2010-10-11 下午12:18:14 */ public enum UploadState { UPLOAD_SUCCSSS(0, "上传文件成功!"), UPLOAD_FAILURE(1, "上传文件失败!"), UPLOAD_TYPE_ERROR(2, "上传文件类型错误!"), UPLOAD_OVERSIZE(3, "上传文件过大!"), UPLOAD_ZEROSIZE(4, "上传文件为空!"), UPLOAD_NOTFOUND(5, "上传文件路径错误!"); private String state; private int flag; public String getState() { return this.state; } public int getFlag() { return this.flag; } UploadState(int flag, String state) { this.state = state; this.flag = flag; } } 5、 下面看看Struts的ActionForm代码。 package com.hoo.form; import org.apache.struts.action.ActionForm; import org.apache.struts.upload.FormFile; @SuppressWarnings("serial") public class UploadFileForm extends ActionForm { private FormFile uploadFile; public FormFile getUploadFile() { return uploadFile; } public void setUploadFile(FormFile uploadFile) { this.uploadFile = uploadFile; } private String param; public String getParam() { return param; } public void setParam(String param) { this.param = param; } } uploadFile这个属性是和客户端js中的file_post_name: "uploadFile"属性对应,这个一定要注意,param属性是和客户端的post_params: {"param" : "uploadParams"} 中的param对应,如果你还有其他参数都会在这里列举。如果你是上传的时候,文件名出现乱码,那么你最好在这里把文件名用encodeURI转码2次。通过post_params传递到服务器端,然后服务器端用URLDecoder转码即可。 6、 服务器端上传代码,很简单直接调用UploadFormFileUtils工具类完成上传 package com.hoo.action; import static com.hoo.util.UploadFormFileUtils.maxFileSize; import static com.hoo.util.UploadFormFileUtils.upload; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.upload.FormFile; import com.hoo.enums.UploadState; import com.hoo.form.UploadFileForm; import com.hoo.util.UploadFormFileUtils; /** * function:struts多文件上传 * @createDate Oct 10, 2010 5:14:43 PM * @file UploadAction.java * @package com.hoo.action * @project StrutsUpload * @version 1.0 */ public class UploadAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { UploadFileForm uForm = (UploadFileForm)form; String path = request.getSession().getServletContext().getRealPath(UploadFormFileUtils.path); maxFileSize = 1024 * 1024 * 20L; FormFile file = uForm.getUploadFile(); UploadState state = upload(file, file.getFileName(), path); System.out.println(uForm.getParam()); response.getWriter().print("{success: " + state.getFlag() + ", message: '" + state.getState() + "'}"); return null; } } 注意:这里上传就是一个方法,很普通的方法。也就是上传一个文件,其实SWFupload的上传是利用queue队列,将队列中的文件依次通过flash向服务器端完成上传。而并不是一次上传或是批量上传。 response.getWriter().print("{success: " + state.getFlag() + ", message: '" + state.getState() + "'}"); 和客户端的handlers.js函数中的uploadSuccess中的serverData中的内容对应的 var data = eval("(" + serverData + ")"); if (data.success == 0 || data.success == "0") { progress.setStatus("上传完成!"); } else { progress.setError(); progress.setStatus("上传失败!" + data.message); } 这里是将服务器端传递过来的json字符用eval转换成js对象,data就是一个js对象 data.success这里的success就是服务器端字符串中success的值,同样message也是服务器端字符串后面的值。 Strtus-config.xml配置 支持struts1.x的SWFUpload多文件无刷新上传就到此结束。其中对主要的几个文件和js文件中要注意到的地方都指出过。且提供源代码参考,这里提供方法的基本上够用,能完成上传、提示、验证等。 下次有时间会提供ExtJS+SWFUpload+Struts2.x的多文件上传,这个界面更加友好、人性化、功能将更加丰富。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ] 2 人已下载

下载文档