1、首先准备uploadify上传插件包,拷贝到项目目录下
2、注意其中的特殊文件:uploadify-init.js文件,是包含了封装后的特殊函数:
/** * uploadify上传插件相关JS */ $.extend( { /** * uploadify上传插件初始化设置 * params: * */ initUploadify : function(params) { var opts = { //'buttonImage' : '', // 选择文件按钮图片 'buttonClass' : 'but but_blue', // 选择文件按钮样式 'debug': false, // 是否开启调试模式 'auto': true, // 是否自动上传 'multi': true, // 是否允许多个上传 'removeCompleted': true, // 上传完毕上传列表是否消失 'removeTimeout': 0, // 上传完毕到列表消失的间隔时间 'fileObjName': 'uploadFile', // 上传文件数据的名字(服务器端获取文件时使用的名字) 'queueID': false, // 装载进度条的标签ID 'progressData': 'percentage', // 进度条效果percentage或speed 'buttonText': '上传', // 上传按钮文本内容 'formData' : {}, // 表单数据(json格式) 'method': 'post', // 提交方法(post或get) 'fileSizeLimit': '2MB', // 上传文件大小设置 单位可以是B、KB、MB、GB 'fileTypeDesc' : '*.gif; *.jpg; *.png', // 选择文件框类型处提示文本 'fileTypeExts' : '*.gif; *.jpg; *.png', // 上传时支持的文件类型 'swf': 'js/uploadify/uploadify.swf',// swf文件位置(必设参数,插件自带文件,不可替换) 'width': 120, // 上传按钮宽度 'height': 30, // 上传按钮高度 'successTimeout': 999999, // 上传超时时间,若达到时间服务器没有响应,则当作成功(很扯淡的设置,默认为30秒) 'uploader': '', // 服务器处理上传的Action 'queueSizeLimit': 10, // 允许一次上传的文件数 'uploadLimit': 999999, // 允许的总上传文件次数(刷新页面后重置) //'overrideEvents' : [], // 设置不执行的默认事件 // 选中文件时事件 'onSelect': function (event, queueID, fileObj) { }, // 上传文件出错事件 'onUploadError': function (file,errorCode,errorMsg,errorString,swfuploadifyQueue) { alert(errorMsg); }, // 上传完成时事件 'onUploadComplete': function (file) { }, // 上传时发生错误事件 'onUploadError': function (file, errorCode, errorMsg) { var msg = "服务器故障。"; switch(errorCode) { case -100: msg = "上传的文件数量已经超出系统限制的"+$('#file_upload').uploadify('settings','queueSizeLimit') + "个文件。"; break; case -110: msg = "文件 ["+file.name+"] 大小超出系统限制的" + $('#file_upload').uploadify('settings','fileSizeLimit') + "大小。"; break; case -120: msg = "文件 ["+file.name+"] 大小异常。"; break; case -130: msg = "文件 ["+file.name+"] 类型不正确。"; break; case -280: return; } alert(msg); }, // 检测Flash失败调用 'onFallback': function(){ var fallBackMsg = '您未安装Flash控件,无法上传图片!请安装FLASH控件后再试。'; alert(fallBackMsg); }, // 成功上传到服务器,服务器返回相应信息(服务器回写的数据存放于data中) 'onUploadSuccess': function(file, data, response){ }, inputFile:"#file_upload" }; if (typeof params !== "undefined") $.extend(opts,params); if (typeof opts.uploader === "undefined" || opts.uploader === ""){ alert("必须指定上传的地址"); return; } if (typeof opts.inputFile === "undefined" || opts.inputFile === ""){ alert("没有指定上传表单元素"); return; } $(opts.inputFile).uploadify(opts); } });
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="http://localhost:8080/snjob/"> <title>上传示范</title> <link rel="stylesheet" href="js/uploadify/uploadify.css" type="text/css" /> <script type="text/javascript" src="js/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="js/uploadify/jquery.uploadify.min.js"></script> <script type="text/javascript" src="js/uploadify/uploadify-init.js"></script> <style type="text/css"> body{ font-size:12px; } .uploadform{ background-color: gray; border:1px solid; } table{ width:80%; border-width: 1px; } </style> <script type="text/javascript"> $(function(){ $.initUploadify({ inpufFile:"#file_upload", uploader:'http://localhost:8080/snjob/corpasyn/UploadAction!uploadMethod1.action', formData:{param1 : "jiang"}, onUploadSuccess:function(file, ptl, response){ eval("var ptl = "+ptl); var d = new Date(); if (ptl.status==="Success"){ var tr = "<tr>"; tr+="<td>"+file.name+"</td>"; tr+="<td>"+(file.size/1024)+"K</td>"; tr+="<td>"+d+"</td>"; tr+="<td><a href='2/"+ptl.data+"'>下载</a></td>"; tr+="</tr>"; $("table tbody").append(tr); } else { alert(ptl.msg); } } }); }); </script> </head> <body> <h3>上传文件示范</h3> <div class="uploadform"> <input id="file_upload" type="file" name="file_upload" /> </div> <h5>文件列表</h5> <div> <table id="upfiles" border="1"> <tbody> <tr> <th>文件名</th> <th>文件大小</th> <th>上传时间</th> <th>操作</th> </tr> </tbody> </table> </div> <a href="demo/corp_feedback.jsp"><h3>Ajax异步加载示范和Ajax分页示范</h3></a> </body> </html>
5、看一下最关心的服务器代码是如何编写的
服务器采用Struts2,具体Action的设计如下:
我们要直接使用的是UploadDemoAction。
BaseAction源码:
package org.job.web.action; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.InvalidParameterException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.json.annotations.JSON; import org.apache.struts2.util.ServletContextAware; import org.job.biz.ServiceTemplate; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Action类的基类,实现了ServletRequestAware接口、ServletResponseAware接口、ServletContextAware接口用于注入Servlet对象,因此与Servlet API有耦合 * 也可以采用ServletActionContext.getXxx()方法实现访问Servlet API更加优雅 * @author 江橦 * */ public abstract class BaseAction extends ActionSupport implements ServletRequestAware,ServletResponseAware,ServletContextAware,IAction { /** * */ private static final long serialVersionUID = 7897085684034354314L; /** * 添加属性到请求上下文 * @param key * @param value */ protected void addAttr(String key,Object value,VScope...scopes){ VScope scp = scopes==null||scopes.length==0?VScope.REQ:scopes[0]; switch (scp) { case PAGE: ((java.util.Map<String,Object>)ActionContext.getContext().get("page")).put(key, value); break; case REQ: ((java.util.Map<String,Object>)ActionContext.getContext().get("request")).put(key, value); break; case SESSION: ActionContext.getContext().getSession().put(key, value); break; case APPLICATION: ActionContext.getContext().getApplication().put(key, value); break; default: break; } } /** * 获得当前登录的会员用户 * @return */ protected <T> T getLoginedPersonUser(){ Object u = ActionContext.getContext().getSession().get(LOGINED_PERSON_USER); return u==null?null:(T)u; } /** * 获得当前登录的企业用户 * @return */ protected <T> T getLoginedCorpUser(){ Object u = ActionContext.getContext().getSession().get(LOGINED_CORP_USER); return u==null?null:(T)u; } /** * 获得当前登录的运营商用户 * @return */ protected <T> T getLoginedManagerUser(){ Object u = ActionContext.getContext().getSession().get(LOGINED_MANAGE_USER); return u==null?null:(T)u; } protected HttpServletRequest request; protected HttpServletResponse response; protected ServletContext servletContext; /* * *注入 HttpServletRequest */ public void setServletRequest(HttpServletRequest arg0) { // TODO 子类重写 this.request = arg0; } /* * * 注入 HttpServletResponse */ public void setServletResponse(HttpServletResponse arg0) { // TODO 子类重写 this.response = arg0; } /* * * 注入 setServletContext */ public void setServletContext(ServletContext arg0) { // TODO 子类重写 this.servletContext = arg0; } Map<String,Object> _paramMap = new HashMap<String,Object>(); /** * 获得表单元素值 * @param name * @return */ public Object getParam(String key){ if (_paramMap.size()==0){ Map<String,Object> paramMap = ActionContext.getContext().getParameters(); for (Map.Entry<String,Object> kvp : paramMap.entrySet()) { _paramMap.put(kvp.getKey().toUpperCase(),kvp.getValue()); } } if(!_paramMap.containsKey(key.toUpperCase())) return ""; Object[] values = (Object[])_paramMap.get(key.toUpperCase()); if (values==null || values.length==0) return ""; if (values.length==1) return values[0]==null?"":values[0]; return values; } /** * 绑定参数到对象属性 * @param entity * @param params */ public void bindParam2Bean(Object entity){ Map<String,Object> paramMap = ActionContext.getContext().getParameters(); if (paramMap==null || paramMap.size()==0) throw new InvalidParameterException("没有有效的参数可以绑定"); Class classzz = entity.getClass(); //將所有私有字段裝入Map<字段名,字段對象> Map<String,Field> fieldMap = new HashMap<String,Field>(); for (Field f : classzz.getDeclaredFields()) { fieldMap.put(f.getName().toUpperCase(),f); } Field f = null; Object fvalue = null; for (Map.Entry<String,Object> kvp : paramMap.entrySet()) { try { Object[] values = (Object[])kvp.getValue(); if (null != values && values.length==1){ //f = classzz.getDeclaredField(kvp.getKey()); f = fieldMap.get(kvp.getKey().toUpperCase());//從HashMap中取得字段對象[不區分大小寫] if ( null == f) continue; f.setAccessible(true); if (f.getType()==String.class){ f.set(entity, values[0]); }else{ fvalue = f.getType().getDeclaredMethod("valueOf",String.class).invoke(null, values[0]); f.set(entity, fvalue); } } } catch (Exception e) { if (super.LOG.isInfoEnabled()) super.LOG.info(java.text.MessageFormat.format("封装请求参数{0}到JavaBean的{1}属性失败[{2}]", kvp.getKey(),f.getName(),e.getMessage())); } } } protected ServiceTemplate serviceTemplate = new ServiceTemplate(); /** * 存放验证的消息 */ private Map<String,String> validateMsgs = new HashMap<String,String>(); protected void addValidateMsg(String msgKey,String msgValue){ validateMsgs.put(msgKey, msgValue); request.setAttribute(VALIDATE_MSG, this.validateMsgs); } protected Boolean isValid(){ if(this.validateMsgs.size()>0) request.setAttribute(VALIDATE_MSG, this.validateMsgs); return this.validateMsgs.size()==0; } /** * 獲得客戶端IP * @param request * @return */ public String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } }
package org.job.web.action; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import net.it028.foundation.global.ExceptionUtil; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.exception.ExceptionUtils; import org.job.uptl.*; import org.job.uptl.UProtocol.*; import org.job.web.convertor.*; /** * * 所有客户端接口请求的Action的基类 * @author jiangtong * */ public class BaseJSONAction extends BaseAction { static { ConvertUtils.register(new SqlDateConverter(null), java.sql.Date.class); ConvertUtils.register(new SqlTimestampConverter(null), java.sql.Timestamp.class); } /** * */ private static final long serialVersionUID = -3138932274689672883L; /** * 執行子類Action的模板方法 * @param actionCallback * @return */ public String executeAction(IExecuteActionCallback actionCallback){ String result = super.SUCCESS; try { getUp().status = ERspStatus.Success; if (actionCallback!=null) result = actionCallback.execute(this); getUp().msg = "success"; }catch (Exception e2) { getUp().status = ERspStatus.Exception; getUp().msg=ExceptionUtil.getMsg(e2); if (getUp().msg.contains("ConstraintViolationException")){ getUp().msg = "数据项重复录入"; } } return result; } /** *通讯协议 */ private UProtocol up; /** *获得通讯协议 */ public UProtocol getUp() { if (up==null) up= new UProtocol(); return up; } /** *设置通讯协议 */ public void setUp(UProtocol up) { this.up = up; } }
package org.job.web.action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.UUID; import net.it028.foundation.global.StringUtils; import org.apache.struts2.ServletActionContext; public class BaseUploadAction extends BaseJSONAction { private static final long serialVersionUID = 5196594946316620265L; private String savePath; private File uploadFile; private String uploadContentType; private String filename; /** * 保存路径,通过struts配置文件注入 * * @return */ public String getSavePath() { return ServletActionContext.getRequest().getSession() .getServletContext().getRealPath(savePath); } public void setSavePath(String savePath) { this.savePath = savePath; } /** * 上传的文件 * * @return */ public File getUploadFile() { return uploadFile; } public void setUploadFile(File uploadFile) { this.uploadFile = uploadFile; } /** * 上传文件的内容类型 * * @return */ public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } /** * 上传的文件名 * * @return */ public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } /** * 保存文件 */ protected String saveFile(String filename) { String savePath = getSavePath(); File fileSavePath = new File(savePath); if (!fileSavePath.exists() && !fileSavePath.mkdirs()) {// 如果目录不存在则主动创建 throw new RuntimeException("保存文件前创建目录路径失败......"); } FileOutputStream fos = null; FileInputStream fis = null; String saveFileName = filename; if (filename == null || "".equals(filename)) saveFileName = StringUtils.getUniqueString() + getFilename().substring(getFilename().lastIndexOf(".")); try { // 以服务器的文件保存地址和源文件名建立上传文件输出流 fos = new FileOutputStream(savePath + File.separatorChar + saveFileName, false); // 以上传文件建立一个文件上传流 fis = new FileInputStream(getUploadFile()); // 将上传文件的内容写入服务器 byte[] buffer = new byte[1024 * 1024]; int len = 0; while ((len = fis.read(buffer)) > 0) { fos.write(buffer, 0, len); } } catch (Exception e) { throw new RuntimeException(e); } finally { try { if (fos != null) { fos.flush(); fos.close(); } if (fis != null) { fis.close(); } } catch (IOException e) { throw new RuntimeException(e); } } return saveFileName; } }
package org.job.enterprice.web; import java.sql.Timestamp; import java.util.Date; import javax.annotation.Resource; import net.it028.foundation.global.DateUtil; import org.apache.commons.lang.xwork.StringUtils; import org.job.uptl.UPDataProtocol; import org.job.web.action.BaseJSONAction; import org.job.web.action.BaseUploadAction; import org.job.web.action.IExecuteActionCallback; public class UploadDemoAction extends BaseUploadAction { private static final long serialVersionUID = -871233872187381L; /** * 上传文件示范1 * * @return */ public String uploadMethod1() { return this.executeAction(new IExecuteActionCallback() { @Override public String execute(BaseJSONAction action) { String param1 = getParam("param1").toString(); System.out.println("接收到的上传参数:"+param1); // 处理文件扩展名 String fileName = getFilename(); //取得扩展名 String exName = fileName.substring(fileName .lastIndexOf(".") + 1); //新文件名[根据自己的规则生成] //String nfilename = DateUtil.getTimestamp().getTime()+"."+exName; String nfilename = saveFile("");//该方法返回保存后的文件名,如果给定的文件无效将重新生成 UPDataProtocol up = new UPDataProtocol(); up.setData(nfilename); setUp(up); return SUCCESS; } }); } }Struts配置示范:
<package name="corpasyn_demo" namespace="/corpasyn" extends="jobcommon"> <!-- 上传示范 --> <action name="UploadAction" class="org.job.enterprice.web.UploadDemoAction"> <!-- 保存目录 --> <param name="savePath">/2</param> <!-- 返回格式 --> <result type="json"> <param name="ignoreHierarchy">false</param> <param name="root">up</param> </result> <!-- 系统上传拦截器 --> <interceptor-ref name="fileUpload"> <param name="allowedExtensions">.jpg,.gif,.png,.bmp</param> <param name="maximumSize">2097152</param> </interceptor-ref> <!-- 自定义身份认证拦截器 --> <interceptor-ref name="authenInterceptStack"></interceptor-ref> </action> </package>
瞥一眼jobcommon这个包的关键代码:
<!-- 通用Action --> <package name="jobcommon" namespace="/" extends="json-default"> <interceptors> <interceptor name="authenticationInterceptor" class="org.job.web.interceptor.AuthenticationInterceptor" /> <!-- 自定义拦截器需要和缺省拦截器栈整合,否则可能丢失struts2的一些既定功能,比如参数赋值--> <interceptor-stack name="authenInterceptStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="authenticationInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!--Action的缺省拦截器[身份认证和授权] --> <default-interceptor-ref name="authenInterceptStack" /> </package>