用Iframe來實現無刷新文件上傳的注意點javascript
1. 頁面須要放一個iframe,並隱藏,而後讓上傳頁面表單的target指定到這個iframecss
2. struts2裏面,中文文件編碼處理,能夠在配置文件,也能夠在action取上傳文件名字的地方,看下面代碼。html
3. 上傳完成後,仍是提交返回到上傳頁面,可是後臺上傳成功的提示信息回傳時,在js 裏面,都必須用parent.xxx的方式,才能訪問到iframe外面的變量和js方法,有點嵌套的意思,比較搞。java
4. 上傳頁面能夠再放一個form,用來下載用。web
5. struts2通常出錯或者取不到值,都是對valueStack和ognl 理解不許確致使的,#號訪問valuestack中非root節點的值,不用#訪問的是action裏面屬性的值,由於action默認是這個valuestack的root節點。ajax
6. struts2 action要取得屬性值,前臺form必須提交過去,就算沒用到,就用隱藏域傳,不然後臺取回報空指針。多文件上傳下載例子裏有實例。spring
7. 無刷新上傳,仍是不要用iframe,太麻煩。尤爲是js訪問iframe外面的方法和變量,或者提交表單,所有要加parent
apache
上代碼json
上傳action,BaseAction其實沒啥,只是提煉了些公用方法,也是直接繼承ActionSupport瀏覽器
package com.hello.web.upAndDownload; import java.io.File; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.hello.util.CommonConstants; import com.hello.util.FileUtil; import com.hello.web.BaseAction; import com.opensymphony.xwork2.ActionContext; /** * 單文件上傳Action * */ public class FileUploadAction extends BaseAction { private static final long serialVersionUID = 3458871754829140760L; private Logger logger = LoggerFactory.getLogger(FileUploadAction.class); private File upload;//頁面上傳文件欄位名 private String uploadContentType;//文件類型 struts2框架使用,用於判斷是否包含不支持的上傳類型 private String uploadFileName;//文件名稱 private String saveFileName;//文件轉存後的名字 /**跳轉到上傳界面*/ public String goUploadPage(){ logger.debug("跳轉到上傳界面"); return "uploadPage"; } /** * 執行文件上傳 * */ public String uploadFile(){ logger.debug("上傳文件名稱:"+uploadFileName); logger.debug("上傳文件類型:"+uploadContentType); try { String fileName = FileUtil.generDateStrFilename(uploadFileName); HttpServletRequest request = ServletActionContext.getRequest(); String contextPath = request.getContextPath();//獲取應用上下文路徑 String destPath = ServletActionContext.getServletContext().getRealPath("/"+CommonConstants.uploadFilePath); //logger.debug("保存路徑:"+destPath); File destFile = new File(destPath+File.separator+fileName); //拷貝文件 FileUtil.copyFile(upload, destFile); //將文件路徑返回到頁面,以供顯示 //<s:property value="#request.saveFileName"/>方式訪問 request.setAttribute("realFilePathName", contextPath+"/"+CommonConstants.uploadFilePath+"/"+fileName); //文件重名後的名字 this.setSaveFileName(fileName); }catch(Exception e){ logger.error(uploadFileName+"文件上傳出錯:",e); } return SUCCESS; } /** * 無刷新 * */ public String iframeUpload(){ logger.debug("上傳文件名稱:"+uploadFileName); logger.debug("上傳文件類型:"+uploadContentType); try { String fileName = FileUtil.generDateStrFilename(uploadFileName); HttpServletRequest request = ServletActionContext.getRequest(); String contextPath = request.getContextPath();//獲取應用上下文路徑 String destPath = ServletActionContext.getServletContext().getRealPath("/"+CommonConstants.uploadFilePath); //logger.debug("保存路徑:"+destPath); File destFile = new File(destPath+File.separator+fileName); //拷貝文件 FileUtil.copyFile(upload, destFile); //將文件路徑返回到頁面,以供顯示 request.setAttribute("realFilePathName", contextPath+"/"+CommonConstants.uploadFilePath+"/"+fileName); //文件重名後的名字 this.setSaveFileName(fileName); ActionContext.getContext().put("message", "上傳成功!"); }catch(Exception e){ logger.error(uploadFileName+"文件上傳出錯:",e); } return SUCCESS; } /**跳轉到上傳界面*/ public String goIframeUploadPage(){ logger.debug("跳轉到上傳界面"); return "iframeUpload"; } public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } public String getSaveFileName() { return saveFileName; } public void setSaveFileName(String saveFileName) { this.saveFileName = saveFileName; } }
下載Action
package com.hello.web.upAndDownload; import java.io.InputStream; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.apache.struts2.ServletActionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.hello.util.CommonConstants; import com.hello.web.BaseAction; /** * 文件下載 * 必須用表單提交,且方法爲POST,才能將隱藏域的值傳進來 * jsp裏面有fileName,則action裏面使用setFileName方法對應,其餘變量相似 * jsp裏面取${downloadFileName},至關於調用action裏面的getDownloadFileName方法 * * */ public class FileDownLoadAction extends BaseAction { private static final long serialVersionUID = -929993646660508444L; private Logger logger = LoggerFactory.getLogger(FileDownLoadAction.class); //下載顯示的文件名 private String downloadFileName; private String realFileName; /** * 執行下載 * */ public String download(){ logger.debug("下載的文件顯示名:"+downloadFileName); logger.debug("下載的文件實際名:"+realFileName); HttpServletRequest request = ServletActionContext.getRequest(); logger.debug("從隱藏域裏面取得的值:"+request.getParameter("realFileName")); return SUCCESS; } public InputStream getInputStream() { logger.debug("下載的文件顯示名:"+downloadFileName); logger.debug("下載的文件實際名:"+realFileName); //InputStream in = ServletActionContext.getServletContext().getResourceAsStream("/" +CommonConstants.uploadFilePath+"/"+ downloadFileName); InputStream in = ServletActionContext.getServletContext().getResourceAsStream("/" +CommonConstants.uploadFilePath+"/"+ realFileName); if(in==null){ logger.debug("檢查action中文件下載路徑是否正確!"); } return in; } public void setFileName(String fileName) { this.downloadFileName = fileName; } public String getDownloadFileName() { String finalFileName = downloadFileName; try { // 解決文件名稱包含中文 HttpServletRequest request = ServletActionContext.getRequest(); String userAgent = request.getHeader("USER-AGENT"); if (StringUtils.contains(userAgent, "MSIE")) {// IE瀏覽器 finalFileName = URLEncoder.encode(downloadFileName, "UTF8"); } else if (StringUtils.contains(userAgent, "Mozilla")) {// google,火狐瀏覽器 finalFileName = new String(downloadFileName.getBytes(), "ISO8859-1"); } else { finalFileName = URLEncoder.encode(downloadFileName, "UTF8");// 其餘瀏覽器 } } catch (Exception e) { logger.error("下載時,文件名稱轉碼出錯:", e); } return finalFileName; } public String getRealFileName() { logger.debug("調用 getRealFileName 方法:"+realFileName); return realFileName; } public void setRealFileName(String realFileName) { logger.debug("調用 setRealFileName 方法:"+realFileName); this.realFileName = realFileName; } }
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>使用Iframe實現無刷新文件上傳</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> <style type="text/css"> body { line-height: 1.6em; font-size: 12px; } .errorMessage ul { font-size: 12px; font-colr: red; backgroundColor:red; } </style> <script type="text/javascript"> var showName; var realName; function uploadfile(){ var ff = document.getElementsByName("upload"); if(ff[0].value==''|| ff[0].value==null){ alert('請至少選擇文件!'); }else{ document.fileUpload.submit(); } } function download(){ parent.document.getElementById("fileName").value=parent.showName; //alert(parent.document.getElementById("fileName").value); parent.document.getElementById("realFileName").value=parent.realName; parent.document.downloadForm.action="<%= request.getContextPath()%>/file/fileDownload!download.htm"; parent.document.downloadForm.submit(); } function show(){ var msg = '<s:property value="#message"/>'; parent.showName = '<s:property value="uploadFileName"/>'; //var realFilePathName = '<s:property value="#request.realFilePathName"/>';//帶路徑的 parent.realName='<s:property value="saveFileName"/>';//不帶路徑的真實文件名 parent.document.getElementById("msg").innerHTML = msg; parent.document.getElementById("showFileName").innerHTML = "<a href=\"javascript:download();\">"+parent.showName+"</a>"; } </script> </head> <body onload="show();"> <s:form action ="iframeFileUpload" name="fileUpload" method ="POST" enctype ="multipart/form-data" namespace="/file" theme="simple" target="hidden_frame"> <s:actionerror/> <s:fielderror /> <!-- FF和IE瀏覽器顯示的上傳界面不同 --> 請選擇文件:<s:file name ="upload"/><br/> (只支持上傳JPG,PNG,GIF,TXT文件)<br/> <input type="button" name="btnUpload" value="上傳" onclick="javascript:uploadfile();"/><br/> ---------------------------------------------------------------------<br/> <span id="msg"></span><br/> <span id="showFileName"></span><br/> <s:property value="#message"/> <s:if test="%{uploadFileName!=null}"> <s:if test="%{uploadFileName.lastIndexOf(\"txt\")>0}"></s:if> <s:else> <img src="<s:property value="#request.realFilePathName"/>"/><br/> </s:else> <a href="javascript:download();"><s:property value="uploadFileName"/></a><br/> </s:if> <iframe name='hidden_frame' id="hidden_frame" style="display:none;"></iframe> </s:form> <form action="<%= request.getContextPath()%>/file/fileDownload!download.htm" name="downloadForm" method="post"> <input type="hidden" name="fileName" id="fileName"/> <input type="hidden" name="realFileName" id="realFileName"/> </form> <a href="<s:url action="index" method="index" namespace="/"/>">返回首頁</a><br> </body> </html>
配置文件
struts.xml主文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- struts2常量配置 --> <constant name="struts.objectFactory" value="spring" /> <constant name="struts.objectFactory.spring.useClassCache" value="true" /> <!-- 國際化配置 --> <constant name="struts.locale" value="zh_CN" /> <constant name="struts.i18n.encoding" value="UTF-8" /> <constant name="struts.custom.i18n.resources" value="resource.messages,resource.exceptions" /> <constant name="struts.action.extension" value="htm" /> <constant name="struts.ui.theme" value="simple" /> <!-- 部署時修改成false --> <constant name="struts.devMode" value="true" /> <!-- 該屬性指定處理 MIME-type multipart/form-data文件上傳 --> <constant name="struts.multipart.saveDir" value="/tmp"/> <!-- <constant name="struts.multipart.paeser" value="cos"/> --> <!-- 單位字節Byte 默認2M--> <constant name="struts.multipart.maxSize" value="2097152" /> <package name="my-default" extends="struts-default"> <result-types> <!-- 配置Json返回類型 --> <result-type name="json" class="org.apache.struts2.json.JSONResult"/> </result-types> <!-- 全局攔截器 --> <interceptors> <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/> <interceptor name="globalErrInterceptor" class="com.hello.web.ErrorInterceptor"/> <interceptor-stack name="myDefaultStack"> <!-- 自定義錯誤攔截器棧 --> <interceptor-ref name="globalErrInterceptor"/> <!-- struts2 提供的攔截器棧,包含了struts2的不少核心攔截器 --> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="myDefaultStack"/> <default-action-ref name="acctionNotFoundError"/> <global-results> <result name="jsonMsg" type="json"> <param name="root">message</param> </result> <result name="error">/WEB-INF/pages/error/404.jsp</result> <result name="500">/WEB-INF/pages/error/500.jsp</result> <result name="index">/index.jsp</result> <result name="testMessage">/WEB-INF/pages/msg/message.jsp</result> </global-results> <!-- 全局異常配置 --> <global-exception-mappings> <exception-mapping result="500" exception="java.lang.Exception"/> </global-exception-mappings> <action name="index" class="com.hello.web.IndexAction" method="index"> <result name="welcome">/index.jsp</result> </action> <!-- 使用 default-action-ref 配置struts2攔截到的404錯誤--> <action name="acctionNotFoundError" class="com.hello.web.PageNotFoundAction" method="go404Page"> <result name="pageNotFound">/WEB-INF/pages/error/404.jsp</result> </action> </package> <!-- struts2 修改配置文件路徑後,必須加進來 有這裏看出,當前文件的路徑是跟路徑下classes路徑,因此其餘的文件要從classes這個路徑開始找 --> <include file="struts-plugin.xml" /> <include file="struts-default.xml" /> <!-- 本身添加的配置文件 注意路徑 --> <include file="../config/struts-i18n-test.xml" /> <include file="../config/struts-validate-test.xml" /> <include file="../config/struts-tags-test.xml" /> <include file="../config/struts-upload2download-test.xml" /> </struts>
struts-upload2download-test.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="fileUpload2download" extends="my-default" namespace="/file"> <!-- 單文件上傳 --> <action name="fileUpload" class="com.hello.web.upAndDownload.FileUploadAction" method="uploadFile"> <interceptor-ref name ="fileUpload"> <!-- 默認1M 若是上傳文件在 maximumSize 和 struts.xml裏面配置的 struts.multipart.maxSize 之間--> <!-- 會提示struts.messages.error.file.too.large這個錯誤 --> <!-- 大於struts.multipart.maxSize 提示 struts.messages.upload.error.SizeLimitExceededException 這個錯誤 --> <param name="maximumSize">1048576</param> <!-- 文件上傳容許類型 --> <param name ="allowedTypes">image/bmp,image/png,image/gif,image/jpeg,image/jpg,text/plain</param> </interceptor-ref> <!-- 默認攔截器必須放在fileUpload以後 --> <interceptor-ref name ="defaultStack"/> <!-- 出錯時跳轉頁面 --> <result name="input">/WEB-INF/pages/upload2down/upload.jsp</result> <!-- 上傳成功顯示頁面 --> <result name="success">/WEB-INF/pages/upload2down/uploadSuccess.jsp</result> <result name="uploadPage">/WEB-INF/pages/upload2down/upload.jsp</result> </action> <!-- 文件下載 --> <action name="fileDownload" class="com.hello.web.upAndDownload.FileDownLoadAction" method="download"> <!-- 不指定result name 成功默認到success 出錯到 input --> <result name="success" type="stream"> <!-- 下面這種方式也能避免亂碼 --> <!-- <param name="contentType">application/octet-stream;charset=ISO8859-1</param> --> <param name="contentType">application/octet-stream</param> <param name="inputName">inputStream</param> <!-- 至關於fileDownload.getDownloadFileName --> <param name="contentDisposition">attachment;filename="${downloadFileName}"</param> <param name="bufferSize">4096</param> </result> </action> <!-- 多文件上傳 --> <action name="multiFileUpload" class="com.hello.web.upAndDownload.MultiFileUploadAction" method="uploadFile"> <interceptor-ref name ="fileUpload"> <!-- 默認1M 若是上傳文件在 maximumSize 和 struts.xml裏面配置的 struts.multipart.maxSize 之間--> <!-- 會提示struts.messages.error.file.too.large這個錯誤 --> <!-- 大於struts.multipart.maxSize 提示 struts.messages.upload.error.SizeLimitExceededException 這個錯誤 --> <param name="maximumSize">1048576</param> <!-- 文件上傳容許類型 --> <param name ="allowedTypes">image/bmp,image/png,image/gif,image/jpeg,image/jpg,text/plain</param> </interceptor-ref> <!-- 默認攔截器必須放在fileUpload以後 --> <interceptor-ref name ="defaultStack"/> <!-- 出錯時跳轉頁面 --> <result name="input">/WEB-INF/pages/upload2down/multiUpload.jsp</result> <!-- 上傳成功顯示頁面 --> <result name="success">/WEB-INF/pages/upload2down/multiUploadSuccess.jsp</result> <result name="multiUploadPage">/WEB-INF/pages/upload2down/multiUpload.jsp</result> </action> <action name="iframeFileUpload" class="com.hello.web.upAndDownload.FileUploadAction" method="iframeUpload"> <interceptor-ref name ="fileUpload"> <param name="maximumSize">1048576</param> <param name ="allowedTypes">image/bmp,image/png,image/gif,image/jpeg,image/jpg,text/plain</param> </interceptor-ref> <interceptor-ref name ="defaultStack"/> <result name="input">/WEB-INF/pages/upload2down/ajax1Upload.jsp</result> <!-- 上傳成功顯示頁面 --> <result name="success">/WEB-INF/pages/upload2down/ajax1Upload.jsp</result> <result name="iframeUpload">/WEB-INF/pages/upload2down/ajax1Upload.jsp</result> </action> </package> </struts>