ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

zyUpload多文件上传组件:老项目里的Flash上传救星

zyUpload多文件上传组件:老项目里的Flash上传救星 简介这是一个关于zyUpload图片上传插件的完整资源包专为需要兼容低版本浏览器的Web开发场景打造。插件核心解决了老旧浏览器环境下多图上传、截图直接提交等功能的兼容问题开发者只需对接上传接口即可快速集成。资源共16个文件压缩包仅156KB包含3个JavaScript核心脚本、1个CSS样式文件、1个HTML示例页面以及9张预览效果图和2个数据库文件前后端配套结构清晰。这种轻量化设计尤其适合个人站长或中小企业快速搭建图片上传方案。目前已有562人学习下载说明该插件在兼容性处理上有一定参考价值从示例页面到核心源码均提供可运行版本对希望定制上传按钮样式、调整图片预览逻辑或了解Flash/ActiveX兼容策略的开发者可以直接对照源码修改使用无需从零编写底层协议节省开发调试时间。1. zyUpload.rar 是什么老项目里的多文件上传救星如果你维护的是 2015 年前后落地的 Java Web 系统很可能在某个旧目录里见过 zyUpload.rar。zyUpload 是一个基于 jQuery 的多文件上传组件用 JS 做界面、用 Flash 做文件传输解压后就是一套可以直接拷进 Web 项目的静态资源和配套示例。它能解决的问题很具体在不改造后端框架的前提下给传统 Servlet/JSP 项目加上多选、进度条、拖拽上传。适合正在给老系统补功能、又不想为了一个上传框引入全家桶框架的一线开发也适合接手遗留系统时快速判断这个压缩包到底能不能用。2. 拆解 zyUpload.rar先搞清包里有什么再决定怎么接我第一次见到 zyUpload.rar是在一个物流后台的第三方文件目录里。当时的反应是怎么还在用 Flash 上传可真正接完才发现这套组件在当年的设计里相当成熟能一次多选、能拖拽、能显示真实进度后端只需要一个普通 multipart 接口。下面按我处理这类压缩包的顺序讲。2.1 核心组成JS 管流程Flash 干上传的活zyUpload 不是单一文件而是一组文件配合工作。常见构成是一个 CSS 负责列表和进度条外观两个 JS 文件负责界面逻辑和 JS-Flash 桥接一个 upload.swf 是真正的文件选择与传输执行体。有些版本还会带 demo 页面和简短说明。这套架构把 Flash 当成了一个可编程的传输引擎。用户点击选择文件时JS 让 Flash 弹出系统文件框选完后Flash 直接向后端接口提交 multipart 数据并把进度通过回调传给 JSJS 再去更新页面上的进度条、触发成功或失败回调。换句话说Flash 在这里不是炫技是承担当时浏览器做不了的多选和真实进度上报。这也决定了它的边界页面必须能加载 swf浏览器必须还支持 Flash。今天你用新版 Chrome 自测大概率直接卡在选择文件那一步这不是组件坏了是运行环境变了。我接 zyUpload 时第一台测试机永远准备着一个 IE 11 或同等环境。提示zyUpload 的 swf 是运行必需件不是可有可无的装饰。缺了它一切 JS 配置都不会有效果。2.2 解压后先做体检这 3 个文件没到齐就别往下走拿到压缩包后别急着复制我先做三件事每件都用不了两分钟。第一检查 upload.swf 是否存在。这个文件是整个上传动作的实际执行者没有它后面全部配置都是白搭。很多从同事手里转手得到的压缩包swf 被杀毒软件或下载工具清掉了外面看不出异常等接完才发现选文件没反应。第二跑一遍 demo。压缩包里一般都带例子先按 demo 的目录结构原样放到 Web 容器里用浏览器打开。如果 demo 能上传说明包是完整的问题只在于你没配好路径如果 demo 都不动优先怀疑 swf 损坏或浏览器不支持 Flash。第三确认静态资源最终会不会被打进部署包。我用 Maven 时会把 upload.swf、zyUpload.js、zyFile.js 和 css 放进 src/main/webapp 对应目录而不是放在类路径里。如果你是直接部署 Tomcat就要检查 webapps 下目标文件夹是否能用 URL 直接访问到 swf。这组文件必须被浏览器当静态资源加载不能藏在后端资源目录里。2.3 初始化参数先把 6 个核心参数对齐接着看初始化代码。zyUpload 有很多版本参数名存在出入但核心逻辑一致。我在老项目里最常用的就是这 6 个参数常见值作用url/upload/receive后端接收地址相对绝对都行multipletrue是否允许多选dragtrue是否开启拖拽上传sizeLimit1010241024单个文件前端限制maxCount10队列最大文件数onSuccess / onFailurefunction单文件上传结果回调url 要写能直接访问到的后端接口别拼错项目上下文根。sizeLimit 只是前端体验后端必须再限一次不能相信任何前端校验。onSuccess 里的 data 是后端返回的字符串很多版本不会自动解析 JSON需要自己 JSON.parse。这个细节卡住过不少人后面避坑部分会细说。3. 把 zyUpload 接入页面前端三步走跑通最小流程下面以前端接入为例。假设项目是传统 Web 结构没有前端工程化直接把文件放到静态目录。三步走是我实践下来最省事的路径。3.1 页面引入CSS 和 JS 的次序决定第一印象引入顺序是先 jQuery再 zyFile.js再 zyUpload.js。CSS 放前面。用下面的结构放在页面底部能避免大部分作用域和初始化顺序问题。link relstylesheet href/static/upload/zyUpload.css div iduploaderBox classupload-box/div script src/static/jquery/jquery-3.5.1.min.js/script script src/static/upload/zyFile.js/script script src/static/upload/zyUpload.js/scriptclass 选择器“upload-box”只是一种习惯叫法插件内部会在这个容器里生成选择按钮、文件列表和进度条。如果你用的 jQuery 是 1.x老插件兼容性更好用 jQuery 3.x 一般也能跑但个别版本在事件绑定上有冲突这时优先换成 demo 自带的 jQuery。3.2 初始化最小可运行脚本容器结构到位后在另一个 script 标签里初始化$(#uploaderBox).zyUpload({ url: /upload/receive, multiple: true, drag: true, maxCount: 10, sizeLimit: 10 * 1024 * 1024, onSelect: function (file) { console.log(selected:, file.name); }, onSuccess: function (file, data) { var result JSON.parse(data); console.log(ok:, result.url); }, onFailure: function (file, data) { console.log(fail:, file.name, data); } });url 是后端接收 multipart 的地址带不带项目上下文都可以但必须前后端一致。multiple 决定能否一次选多个drag 决定是否支持拖拽。onSelect 会在每个文件进入队列时触发onSuccess 的第一个参数是当前文件对象第二个参数是后端返回的文本。这里我直接 JSON.parse因为后面后端回的就是 JSON。3.3 swf 路径最容易踩的静态资源坑如果页面加载完成后点选择文件没有任何反应九成是 upload.swf 没被浏览器加载到。这个组件的 JS 会按自己的规则推导 swf 路径而你把文件拷贝到不同目录后推导结果很容易失效。我习惯的做法是先看 demo 页里 swf 是怎么引的再让它等于项目里的实际静态路径。// 有的版本会读取这个全局变量来定位 swf var uploadSwfUrl /static/upload/upload.swf;你拿到的包如果认这个变量设置一次就好如果不认就去找初始化参数里的 swf 相关配置。还有一个稳妥的办法让 swf 和 zyUpload.js 放在同一个目录然后用浏览器开发者工具确认这个 swf 请求返回 200 而不是 404。看到 200 再点按钮后端没接好也不至于完全没反应。4. 后端对接Java Servlet 收文件、存磁盘、回 JSON前端能弹出文件框、进度条能走就说明通信链路对了。接下来后端必须做三件事读取 multipart 里的二进制流、把文件保存到磁盘、给前端回一个能被 onSuccess 识别的 JSON。我以 Java Servlet 为例这也是 zyUpload 最常见的搭配。4.1 用 Servlet 接收 multipart 请求Servlet 3.0 之后可以用 getPart 读取但很多老项目还在用 commons-fileupload。下面这段是我在项目里常用的写法依赖 commons-fileupload 和 commons-io。protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding(UTF-8); response.setContentType(application/json; charsetUTF-8); String saveDir /data/uploads; Files.createDirectories(Paths.get(saveDir)); if (!ServletFileUpload.isMultipartContent(request)) { response.getWriter().write({\code\:1,\msg\:\not multipart\}); return; } DiskFileItemFactory factory new DiskFileItemFactory(); factory.setSizeThreshold(1024 * 1024); ServletFileUpload upload new ServletFileUpload(factory); upload.setFileSizeMax(10L * 1024 * 1024); upload.setSizeMax(100L * 1024 * 1024); String savedName ; try { ListFileItem items upload.parseRequest(request); for (FileItem item : items) { if (item.isFormField()) { continue; } String originalName item.getName(); String ext FilenameUtils.getExtension(originalName); savedName UUID.randomUUID().toString().replace(-, ) . ext; File target new File(saveDir, savedName); item.write(target); } response.getWriter().write( {\code\:0,\url\:\/uploads/ savedName \,\msg\:\ok\} ); } catch (Exception e) { response.getWriter().write({\code\:1,\msg\:\upload error\}); } }第一件事是设置请求和响应的编码否则后面文件名和 JSON 都会花。Files.createDirectories 保证目录存在。DiskFileItemFactory 的 sizeThreshold 是内存阈值超过这个大小写入临时文件不影响业务逻辑但能避免大文件吃满内存。setFileSizeMax 限制单个文件setSizeMax 限制整个请求这些才是后端真正的防线。保存文件名我用 UUID 再加扩展名而不是前端传的原始文件名。原因很简单前端文件名不可信而且极可能带中文和非法字符直接落盘会造成路径或编码问题。原始文件名如果想要可以在 JSON 里另外返回 originalName。4.2 回给前端的数据JSON 约定前端 onSuccess 拿到的 data 就是这个响应体。务必保证响应头是 application/json并且文本是合法 JSON。zyUpload 很多版本不会自动解析得在回调里 JSON.parse所以你不能往 JSON 前面塞 HTML 或异常堆栈。{code:0,url:/uploads/a1b2c3.jpg,msg:ok}我把 code 约定为 0 成功非 0 失败url 是访问文件的相对路径。onFailure 不一定只由网络错误触发后端如果返回 HTTP 500Flash 也会把它当失败。所以后端接口要稳至少要能把异常打到日志里。4.3 临时目录与大小上限要前后端一起限常见做法是给工厂单独指定临时目录避免系统盘被大文件写满factory.setRepository(new File(/data/temp));这句话经常被忽略。默认临时目录可能在 /tmp 上上传峰值一来磁盘占用和清理策略都可能出问题。另外Tomcat 的 maxPostSize 如果还是默认值超过 2MB 的请求会被提前拒绝接口根本没进来。我一般会在 server.xml 的 Connector 上显式调大并在 nginx 层同步调整 client_max_body_size否则后端的 setFileSizeMax 只是白设。5. zyUpload 避坑指南5 个翻车现场与对症处理这一节我直接列最常见的 5 个坑每个都按现象、原因、解决写。很多问题不是逻辑难而是组件自带的口子多。5.1 点击“选择文件”没反应换台机器还复现现象选择按钮点了没反应也没有报错控制台干干净净。原因swf 没加载成功或当前浏览器已经没有 Flash 运行环境。zyUpload 对运行环境非常敏感新版 Chrome 从 2020 年起不再支持 Flash在这类机器上无论如何选不了文件。解决先用开发者工具看 swf 请求是否 200。如果 404把 upload.swf 放到能用 URL 直接访问的静态目录如果状态正常换一台装了旧版 Flash 的 IE 或老浏览器再测。不要在一个不支持 Flash 的环境里调试配置问题那会把路径问题和新环境问题混在一起。5.2 进度条到 100% 后不触发 onSuccess现象文件确实传到了后端磁盘上也有文件但前端进度条不走完列表一直显示上传中。原因后端返回的内容不是合法 JSON或者 Content-Type 不是 application/json。Flash 在接收响应时按文本解析读到异常堆栈或空响应后会判定失败onSuccess 永远等不到。解决后端写好 JSON 字符串后把 setContentType 放在调用 getWriter 之前。另外检查前端回调里是否需要 JSON.parse不要把一个字符串直接当对象用。还是不行就在 onFailure 里把 data 打出来看。5.3 后端拿到的原始文件名乱码现象保存到磁盘的文件名没问题因为用了 UUID但传给业务系统的 originalName 成了 ??_??.jpg 这类字符。原因编码链断了。Flash 默认按 UTF-8 传文件名但页面的编码、Servlet 的 request 解码、数据库连接串的编码任何一环不一致都会乱。解决从三处统一页面 meta 声明 UTF-8Servlet 开头执行 request.setCharacterEncoding(UTF-8)Tomcat server.xml 的 Connector 配置 URIEncodingUTF-8。如果还乱检查项目 filter 是否在 Servlet 之前把编码覆盖了。这里不要多做一次转码通常统一成 UTF-8 就是终点。5.4 文件稍微大一点就上传失败现象几百 KB 的小文件没事上到十几 MB 就失败进度条走到一半断掉。原因前面只调了前端的 sizeLimit但服务端还有几道闸门Tomcat 的 maxPostSize 默认值可能只有 2MBnginx 的 client_max_body_size 也可能是 1MB。任何一个环节比文件小请求都会在半路被掐断。解决后端 ServletFileUpload 的 setFileSizeMax 保持 10MB同时把 server.xml 的 maxPostSize 上调到业务上限之外nginx 的 client_max_body_size 也同步改。改完重启容器用同一个文件重传。注意 maxPostSize 是请求体上限不是单个文件上限多个文件加起来别超过它。5.5 页面从 HTTP 切到 HTTPS 后上传按钮失效现象原来 HTTP 环境一切正常上了 HTTPS 之后选文件没反应浏览器控制台有 mixed content 报错。原因页面是 HTTPS组件里的 swf 却按 HTTP 去加载被浏览器拦截。Flash 本身不是问题资源协议不一致才是问题。解决让 swf 使用和页面同源的绝对路径例如把 upload.swf 的地址改成 https 开头的绝对地址更省事的是在页面里把上传资源路径写成协议相对地址 //your-static-host/upload/upload.swf浏览器会自动选择当前协议。改完清缓存再测。6. 再进一步把 zyUpload 包成可复用组件顺手验证zyUpload 接通后下一步做两个小改造一个是在队列全部结束时拿所有结果另一个是在进入队列时做类型过滤。这两件事能让组件真正融入业务而不是一个孤零零的上传框。用 onComplete 收集结果提交业务表单var uploaded []; $(#uploaderBox).zyUpload({ url: /upload/receive, multiple: true, drag: true, onSuccess: function(file, data) { var res JSON.parse(data); uploaded.push(res.url); }, onComplete: function(files) { $(#photos).val(uploaded.join(,)); $(#saveBtn).prop(disabled, false); } });onComplete 在队列全部处理完触发此时把收集到的 url 塞进隐藏域用户点保存时随表单提交。注意 onSuccess 的触发不一定按用户选择的顺序所以用数组收集不要用 file.id 排序。在 onSelect 里做类型过滤onSelect: function(file) { var ext file.name.split(.).pop().toLowerCase(); if ([jpg, png, pdf].indexOf(ext) -1) { alert(只支持 jpg、png、pdf); return false; } return true; }有的版本 return false 可以阻止文件加入队列有的不行所以后端仍要对类型做校验。这个钩子真正的意义是让用户在选择时就得到反馈而不是传完才被告知失败。我现在接到 zyUpload.rar 这类压缩包第一件事永远是先把 swf、js、demo 三者之间的路径关系画出来确认它们能在同一个静态目录下稳定访问然后才谈参数和回调。这套排查顺序帮我少加了很多班。希望帮到你。本文还有配套的精品资源点击获取
返回列表