關於Ajax的檔案上傳我在網上尋找了一些方法,一種方法用的是使用javascript讀取用戶端的檔案內容並將其封裝在HTTP的協議中,然後再上傳給伺服器,但我認為這樣的做法對於使用者來說是不安全的。於是查了一些相關的書,幸運的在《Ajax完全手冊》找到了一個基於HTML標籤<iframe>的檔案上傳方法,特此總結 希望能對閱讀的你有協助:
總體的思想是將上傳後的資訊在頁面是的iframe標籤內顯示,即將form表單的target屬性設為iframe的name值,這樣服務端的資訊就反饋在了頁面上的iframe內,實現了局部的重新整理上傳。
對應的HTML源碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml"><br /><head><br /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><br /><title>彈出表單</title><br /></head></p><p><body style="position:absolute; z-index:0; margin:0; padding:0; width:100%; height:100%;"><br /><mce:script type="text/javascript"><!--<br /> var windowStatus=false;<br />//由於得到CSS像數值時帶的單位"px"為字串,故要轉換<br /> function getPxNumber(px)<br />{<br />px=px.replace("px", "");<br />return Number(px);<br />}<br /> function showWindows()<br />{</p><p>var lockWindows=document.getElementById("breakDiv");<br />var loginframe=document.getElementById("login");<br />//得到頁面的可見區的寬和高<br />var windowWidth=(document.layers)?window.innerWidth:document.body.clientWidth;<br />var windowHeight=(document.layers)?window.innerHeight:window.document.body.clientHeight;<br />lockWindows.style.width=windowWidth;<br />lockWindows.style.height=windowHeight;<br />//將表單置中<br />loginframe.style.left=parseInt((windowWidth-getPxNumber(loginframe.style.width)+document.body.scrollLeft)/2)+document.body.scrollLeft;<br />loginframe.style.top=parseInt((windowHeight-getPxNumber(loginframe.style.height))/2)+document.body.scrollTop;<br />lockWindows.style.display="block";<br />loginframe.style.display="block";<br />windowStatus=true;<br />}<br />function closeWindows()<br />{<br />var lockWindows=document.getElementById("breakDiv");<br />var loginframe=document.getElementById("login");<br />lockWindows.style.display="none";<br />loginframe.style.display="none";<br />windowStatus=false;<br />}</p><p>window.onresize=function()<br />{<br />if(windowStatus)<br /> showWindows();<br />};</p><p>//當上傳成功後關閉表單<br />function uploadFile()<br />{<br />closeWindows(); //關閉表單顯示傳回資訊<br />}<br />// --></mce:script><br /><!--一個鎖住表單的DIV--><br /><div id="breakDiv" style="filter:alpha(opacity=40); position:absolute; top:0px; left:0px; z-index:6; display:none; background-color:#000;"><br /></div><br /><div id="login"<br /> style="position:absolute; z-index:10; width:271px; height:122px; text-align:center; border:#00C solid 1px; display:none; background-color:#FFF;"><br /> <div id="title" style="font-family:'微軟雅黑', '宋體'; font-size:18px; background-color:#03F; color:#FFF; width:271px; height:25px;"><br /> <div style="float:left; width:200px; font-family:Verdana, Geneva, sans-serif; font-weight:bold; "> 檔案上傳</div><br /> <input type="button" style="color:#C00; border:solid 1px #9C0; float:right; width:30px; background-color:#03F;" onclick="closeWindows();" value="X" /><br /> </div><br /> <div id="form" style="width:230px; padding-top:20px; margin-top:20px; margin:0 auto;"><br /> <form action="http://localhost:8080/Ajax/uploadImage.jsp" method="post" enctype="multipart/form-data" target="uploadInfo"><br /> <input type="file" name="uploadFile" /><br /><br /><br /> <input type="submit" value="上傳"/> <br /> <input type="button" value="取消" onclick="closeWindows();" /><br /> </form><br /> </div><br /></div></p><p><input type="button" onclick="showWindows();" value="單擊" /><br /><iframe name="uploadInfo" scrolling="no" width="100%" height="20%" frameborder="0" onload="uploadFile();"><br /></iframe><br /></body><br /></html>
對應的伺服器上傳處理這裡用jsp中的servlet處理,源碼如下:
package servlet;</p><p>import javax.servlet.*;<br />import javax.servlet.http.*;<br />import java.io.*;</p><p>public class ImgUploadServlet extends HttpServlet<br />{<br />//編碼中文<br />public String codeToString(String str)<br />{<br />try<br />{<br />byte[] buf=str.getBytes("ISO-8859-1");<br />return new String(buf);<br />}<br />catch(Exception e)<br />{<br />e.printStackTrace();<br />}<br />return null;<br />}</p><p>public void doPost(HttpServletRequest request, HttpServletResponse response)<br /> throws ServletException, IOException<br />{<br />request.setCharacterEncoding("utf-8");<br />String tempFilePath=getServletContext().getRealPath("/")+"/tempFile.tmp";<br />String tempFileName=new String(tempFilePath);<br />File tempFile=new File(tempFileName);<br />if(!tempFile.exists())<br /> tempFile.createNewFile();</p><p>byte[] buf=new byte[1000];<br />FileOutputStream writer=new FileOutputStream(tempFile);<br />//得到使用者提交的流<br />InputStream fileSource=request.getInputStream();<br />//將使用者提交的流寫入臨時檔案中<br />int n;<br />while((n=fileSource.read(buf))!=-1)<br /> writer.write(buf, 0, n);<br />fileSource.close();<br />writer.close();</p><p>//解析所讀到的檔案內容,為唯讀模式<br />RandomAccessFile randAccessFile=new RandomAccessFile(tempFile, "r");<br />//讀取檔案的第一行,為一個分隔字元<br />randAccessFile.readLine();<br />//讀取第二行資料,這行包含了上傳檔案的檔案名稱和路在用戶端的路徑資訊<br />String fileInfo=randAccessFile.readLine();<br />//處理得到檔案名稱並進行編碼轉換<br />int index=fileInfo.lastIndexOf('//');<br />String filename=codeToString(fileInfo.substring(index+1, fileInfo.length()-1));</p><p>//重新置放讀取檔案指標到檔案的開頭<br />randAccessFile.seek(0);<br />//得到第4行斷行符號符的位置,這是上傳檔案正真內容的開始位置<br />int forth=1;<br />long forthEntherPosition=0;<br />while((n=randAccessFile.readByte())!=-1&&(forth<=4))<br /> if(n=='/n')<br /> {<br /> forthEntherPosition=randAccessFile.getFilePointer();<br /> forth++;<br /> }</p><p>//得到倒數第3行斷行符號符的位置,為上傳檔案內容的結束位置<br />randAccessFile.seek(randAccessFile.length());<br />long endPosition=randAccessFile.getFilePointer();<br />int j=1;<br />while(endPosition>=0&&(j<=3))<br />{<br />endPosition--;<br />randAccessFile.seek(endPosition);<br />if(randAccessFile.readByte()=='/n')<br /> j++;<br />}</p><p>//儲存解析後的上傳檔案的內容<br />String savePath=getServletContext().getRealPath("/")+"/"+filename;<br />File saveFile=new File(savePath);<br />if(!saveFile.exists())<br /> saveFile.createNewFile();<br />RandomAccessFile writerFile=new RandomAccessFile(saveFile, "rw");</p><p>randAccessFile.seek(forthEntherPosition);<br />long startPoint=randAccessFile.getFilePointer();<br />while(startPoint<endPosition)<br />{<br />writerFile.write(randAccessFile.readByte());<br />startPoint=randAccessFile.getFilePointer();<br />}<br />writerFile.close();<br />randAccessFile.close();<br />tempFile.delete(); //刪除臨時檔案</p><p>response.setHeader("Cache-Control","no-cache");<br /> response.setHeader("Pragma", "on-cache");<br /> response.setContentType("HTTP/1.1 204 NO Content/n/n");<br /> response.setContentType("text/html; charset=UTF-8");</p><p> PrintWriter out=response.getWriter();</p><p> out.println(filename+"上傳成功!");<br />}<br />}
這裡得到的是使用者上傳請求的流,而直接得到的流還包含了HTTp協議中的一些資訊。我在這個過程中得到的臨時檔案的形式如:
-----------------------------7db2ee1b100318<br />Content-Disposition: form-data; name="沒有尾碼的檔案名稱"; filename="檔案在用戶端的絕對檔案名稱(含路徑)"<br />Content-Type: MIME的類型</p><p>"檔案的正真內容"<br />-----------------------------7db2ee1b100318--<br />
故要一定的處理後才能得到真正的上傳檔案內容。
在這裡如果想更加清楚HTTP的協議互動過程資訊,建議可用HttpWatch這個工具,它可以記錄瀏覽器發送和接收的HTTP協議,非常方便Ajax的學習!
如上文章如有問題,歡迎批評指出!