Uploadify是一个Jquery框架下处理批量文件上传的插件,支持多种服务器端软件。遗憾的是,官网(www.uploadify.com)的说明文档做得很不完善,着重于说明Js部分的配置,而没有对服务端的数据接口进行详细说明。而且由于与服务器端进行数据交互的部分被封装在swf文件中,也很难从源代码进行分析。
1)分析
基于此,为了探索Uploadify在Struts2下的应用接口数据,编写了个小工具程序RequestObserver如下:
package utils;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.opensymphony.xwork2.ognl.OgnlValueStack;
public class RequestObserver {
private HttpServletRequest request;
public RequestObserver(HttpServletRequest request) {
this.request = request;
}
public void observe() {
String name,pvalue;
Object avalue;
Enumeration enum1;
System.out.println("/***************** Request Observer (Author: Alex Nie)**************/");
// observe Request Header
enum1 = request.getHeaderNames();
System.out.println("Request Header:");
while (enum1.hasMoreElements()) {
name = (String)enum1.nextElement();
pvalue = request.getHeader(name);
System.out.println(" " + name + " ---- " + pvalue);
}
enum1 = request.getParameterNames();
// observe Request Parameters
System.out.println("Request Parameters:");
while (enum1.hasMoreElements()) {
name = (String)enum1.nextElement();
pvalue = request.getParameter(name);
System.out.println(" " + name + " ---- " + pvalue);
}
enum1 = request.getAttributeNames();
// observe Request Attributes
System.out.println("Request Attributes:");
while (enum1.hasMoreElements()) {
name = (String)enum1.nextElement();
avalue = request.getAttribute(name);
System.out.println(" " + name + " ---- " + avalue);
// observe OgnlValueStack bind by Struts 2
if (avalue instanceof OgnlValueStack) {
avalue = (OgnlValueStack)avalue;
Map<String,Object> m = ((OgnlValueStack) avalue).getContext();
System.out.println(" >> OgnlValueStack:");
Iterator it = m.keySet().iterator();
Object key;
while (it.hasNext()) {
key = it.next();
System.out.println (" " + key + " ---- " + m.get(key));
}
}
}
// observe Request Session
HttpSession session = request.getSession(false);
System.out.println("session: " + session);
if (session!=null)
{
System.out.println(" sessionId: " + session.getId());
enum1 = session.getAttributeNames();
System.out.println("Session Attributes:");
while (enum1.hasMoreElements()) {
name = (String)enum1.nextElement();
avalue = session.getAttribute(name);
System.out.println(" " + name + " ---- " + avalue);
}
}
System.out.println("/***************** End of Request Observer (Author: Alex Nie)**************/");
}
}
在按照官网的说明进行简单配置后,从浏览器触发上传文件操作,在服务器端的Action中接收到相应的Request后,利用上述工具程序输出分析Request中的数据,发现如下:
分析结果
在进行批量文件上传时,Uploadify为每一个上传文件发起一次服务器连接。
在每一次连接中,Uploadify向服务器端传递了7个参数,其中通过request parameters传递了4个String类型参数
Filename: 待上传的文件原名, 内容与后述的xxxxFileName相同
fileext: 允许上传的文件类型,由客户段Js代码中指定的fileExt参数指定
folder: 上传文件在服务期上的保存路径,由客户段Js代码中指定的folder参数指定
Upload: 暂无用处
通过request attributes 传递了3个参数
xxxx : 文件类型,上传的文件内容,xxxx由客户段Js代码中指定的fileDataName参数指定
xxxxFileName: 字符串类型,上传的文件的原名,xxxx由客户段Js代码中指定的fileDataName参数指定,内容与前述的Filename相同
uploadifyContentType: 暂无用处
以上7个参数在服务器端都被Struts2封装,在Action都可直接使用。要注意的是参数名称的大小写和Js端的大小写并不完全相同,有的在Js中小写服务器端大写,有的刚好相反。此外有两个参数内容相同,这些大约是Uploadify未来在代码风格与约定方面可以改进的地方。
清楚了数据接口,Struts2下对应Uploadify的Action该怎么写就很清楚了,接下来以批量上传照片为例进行说明。
2)详细分析
html
<input id="file_upload" name="photo" type="file"/>
<div id="fileQueue"></div>
Javascript
引入jquery-1.4.2.min.js, swfobject.js, jquery.uploadify.v2.1.4.min.js
引入自己的上传用Js代码如下(精简说明版):
$(document).ready(function() {
$('#file_upload').uploadify({
// 页面相关
'uploader' : '/js/uploadify/uploadify.swf', //组件自带的flash,路径根据情况自行调整
'cancelImg' : '/js/uploadify/cancel.png',//取消上传文件的按钮图片
'queueID' : 'fileQueue', //放置上传文件及上传进度的Html元素Id
'queueSizeLimit' : 10, //一次最多选择多少个文件上传
// 控制开关
'auto' : false, //是否选取文件后自动上传,建议关闭
'multi' : true, //多文件上传必须打开
// 服务器脚本
'script' : 'uploadify.action', //Struts2下处理上传的action路径
'scriptData' : {'userid': '12345', 'username': 'Alex Nie'}, //自身业务需要向服务器端传递的数据
// 传递给服务器参数
'folder' : '/upload', //上传文件的目录,将作为'folder'参数传递给服务器
'fileDataName' : 'photo', //它决定了最重要的两个上传参数名称,本例中将为文件'photo'和文件名'photoFileName'
'fileExt' : '*.gid;*.jpg;*.jpeg', //允许的文件类型,在客户端约束用户的文件选择,并将作为'fileext'参数传递给服务器供校验用
// 其它
'fileDesc' : '*.gif;*.jpg;*.jpeg', //显示在本地选择文件对话框的文件类型下拉框中
'sizeLimit' : 100*1024 // 单个文件的最大尺寸(字节为单位)
});
});
function uploadFile(){//上传文件
jQuery('#file_upload').uploadifyUpload();
}
Java
在此不列出具体代码了,只说明一下服务器端UploadifyAction程序的大致流程:
定义以下变量,且生成它们的get和set方法
private File photo;
private String photoFileName,fileext,folder;
1) 分析'fileext',分解出允许的所有文件类型;
2) 校验photoFileName是否在允许的文件类型中
3) 校验文件photo的大小是否超标(遗憾的是,Uploadify不会把Js中定义的'sizeLimit'传递给服务器,服务器端必须自行定义)
4) 校验folder指定的路径是否合法
5) 在folder指定的路径下保存文件photo,根据业务需要可能要为它取名而不是用原文件名photoFileName
6) 向response写入成功或失败返回信息,供页面使用
注:如果信任浏览器端的文件类型和文件尺寸约束校验,也可以省略第2、第3步和第4步,不过为了防止恶意的客户端伪装,最好不要省略它们。
其它几个值得使用的Uploadify选项
'removeCompleted': false //完成上传后是否自动清除网页上的文件列表
'displayData' : 'percentage',//有speed和percentage两种选择,一个显示速度,一个显示完成百分比
'buttonImg' : '/images/mybutton.jpg', 可用图片替换掉页面上传按钮的英文文字显示,避开直接替换成中文文字会遇到的编码问题。
解决Uploadify缺省的英文提示窗问题
编辑jquery.uploadify.v2.1.4.min.js,查找'alert'和'confirm'调用,把提示信息从英文改成中文。