互聯網開發--web文件上傳原理

前臺

<form name="form1" action="test.htm" enctype="multipart/form-data" method="post" >
      <input type="text" name="p1" value="測試1"></input></BR>
      <input type="text" name="p2" value="測試2"></input></BR>

      <input type="file" name="f1_file1" ></input></BR>
      <input type="file" name="f1_file2" ></input></BR>

      <input type="submit" value="開始上傳" /></BR>
</form>
  • 如果form裏有文件上傳控件,一定要有enctype=”multipart/form-data” 屬性,否則文件是提交不到後臺的。
  • 表單中enctype=”multipart/form-data”的意思是設置表單的MIME編碼。默認情況這個編碼格式是application/x-www-form-urlencoded,不能用於文件上傳。只有使用了multipart/form-data,才能完整的傳遞文件數據。

後臺

@RequestMapping("/test.htm")
    public void test(HttpServletRequest request, HttpServletResponse response) {

        //(1)標記1
        // String p1 = request.getParameter("p1");
        // String p2 = request.getParameter("p2");
        // System.out.println(p1 + " && " + p2);

        //(2)標記2
        System.out.println(request.getHeader("Content-type"));

        //(3)保存參數流到本地
        java.io.InputStream is = null;
        java.io.FileOutputStream fos = null;
        try {

            is = request.getInputStream();
            fos = new java.io.FileOutputStream("d:/out.txt");
            byte[] buffer = new byte[8192];
            int count = 0;
            while ((count = is.read(buffer)) > 0) {
                fos.write(buffer, 0, count);
            }
            fos.close();

            System.out.println("---上傳完畢---");

        } catch (IOException e) {
            e.printStackTrace();
        } 


    }

如果表單以文件流的形式提交參數,那麼後臺只能通過request.getInputStream()方法獲取所有參數流來接收參數了。
在request.getInputStream()操作之前不能調用其他的獲取參數的方法,否則參數流爲空,會獲取不到的。
比如代碼(1)處使用了request.getParameter(“p1”);這時本地的out.txt會爲空。我個人理解是request.getParameter(“p1”)阻斷了流,所以會爲空。
打開本地的out.txt文件,內容如下:

------WebKitFormBoundaryrFwIRHZT5SfIkx05
Content-Disposition: form-data; name="p1"

測試111
------WebKitFormBoundaryrFwIRHZT5SfIkx05
Content-Disposition: form-data; name="p2"

測試222
------WebKitFormBoundaryrFwIRHZT5SfIkx05
Content-Disposition: form-data; name="f1_file1"; filename="bigbang歌詞.xlsx"
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

文件二進制流............
------WebKitFormBoundaryrFwIRHZT5SfIkx05
Content-Disposition: form-data; name="f1_file2"; filename="壁紙20130301160822.jpg"
Content-Type: image/jpeg

文件二進制流...........
------WebKitFormBoundaryrFwIRHZT5SfIkx05--

分析參數流,我們可以看出參數流裏的參數結構如下:
(1)參數分割符:

------WebKitFormBoundaryrFwIRHZT5SfIkx05

當前這次請求的所有參數,分隔符都一樣。但是每次請求的參數分割符都不一樣,可以通過request.getHeader(“Content-type”)獲取當前的參數分隔符。見代碼(2)處.注意,通過這個方法獲得的值比實際文件裏的分隔符前面少了兩個小橫線-,不知道爲啥。
(2)參數屬性:

Content-Disposition: form-data; name=”f1_file2”; filename=”壁紙20130301160822.jpg”
Content-Type: image/jpeg

Content-Disposition: form-data; name=”p1”

name對應表單裏控件元素的name,普通表單控件只有name屬性,文件控件多了個 filename屬性。注意瀏覽器不同,filename會有所不同。比如谷歌和火狐,filename就是文件原始名稱,而在IE瀏覽器下,filename就是客戶端的文件絕對路徑了。
(3)一個空行
(4)參數值
以上就是參數結構了。
在所有參數最後,有一個參數流結束符,如下:

------WebKitFormBoundaryrFwIRHZT5SfIkx05--

注意:參數流結束符比參數分隔符後面多了兩個-小橫線。

總結:
設置了enctype=”multipart/form-data”的話,form裏面的所有input的值都會以2進制的方式傳到服務器。所以通過request.getParams(“參數名”)的方式獲取參數值就行不通了。網上有好多封裝好的工具類可以直接拿過來用,用來接收二進制參數。比如SmartUpload類,可以下載相應的jar引入到自己的工程裏。使用方法:

smart.getRequest().getParameter(); //獲取普通文本參數
File[] myFiles= smart.getFiles();// 獲得上傳的所有文件
String ext = smart.getFiles().getFile(0).getFileExt();// 獲得某文件後綴

獲取表單的二進制參數不侷限於這一個方法。如果你的項目是spring項目的話,可以通過配置如下的bean:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8"></property>
    <property name="maxUploadSize" value="10485760000"></property>
    <property name="maxInMemorySize" value="40960"></property>
</bean>

然後在相應的action裏通過註解就可以接收文本參數、文件了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章