Java文件上傳


參考帖子

https://stackoverflow.com/questions/32160662/upload-multiple-files-with-formdata-using-angularjs-and-asp-net-mvc 

<input type="file" id="file1" name="file1" multiple="multiple" />
<input type="file" id="file2" name="file2" multiple="multiple" />
<input type="file" id="file3" name="file3" multiple="multiple" />
<input type="file" id="file4" name="file4" multiple="multiple" />
<input type="file" id="file8" name="file8" multiple="multiple" />
<input type="file" id="file9" name="file9" multiple="multiple" />
//不需要包在form表單里面也可以
//傳輸的方式在js中指定為multipart/form-data 即可
//multiple="multiple"屬性表示一個文件筐可以上傳多個文件
多文件異步上傳的HTML代碼
 console.log("-------#imgform-----"+JSON.stringify($("#imgform")));
            console.log("-------#imgform-----"+$("#imgform")[0]);
            console.log("-------#file1-----"+$("#file1")[0].files);
            /*var  fileForm = new FormData();
            fileForm.append("file1" , $("#file1")[0].files );
            fileForm.append("file2" , $("#file2")[0].files );
            fileForm.append("file3" , $("#file3")[0].files );
            fileForm.append("file4" , $("#file4")[0].files );
            fileForm.append("file8" , $("#file8")[0].files );
            fileForm.append("file9" , $("#file9")[0].files );*/
             $http({
                method : 'POST',
                url : '/omss/uploadCheckImg',
                data : 
                 {
                    file1: $("#file1")[0].files,
                    file2: $("#file2")[0].files,
                    file3: $("#file3")[0].files,
                    file4: $("#file4")[0].files,
                    file8: $("#file8")[0].files,
                    file9: $("#file9")[0].files,
                },
                header: {
                    'Content-Type': 'multipart/form-data'
                },
                transformRequest: function (data, headersGetter) {
                    var formData = new FormData();
                     formData.append("new_id",$scope.employee.id);
                    ///angular.forEach(data, function (value, key) {
                       // debugger;
                       // formData.append(key, value);
                       //var formData = new FormData();
                    //https://stackoverflow.com/questions/32160662/upload-multiple-files-with-formdata-using-angularjs-and-asp-net-mvc
                    for (var i = 0; i < data.file1.length; i++) {
                        formData.append("file1", data.file1[i]);
                       }
                    for (var i = 0; i < data.file2.length; i++) {
                        formData.append("file2", data.file2[i]);
                       }
                    
                    for (var i = 0; i < data.file3.length; i++) {
                        formData.append("file3", data.file3[i]);
                       }
                    for (var i = 0; i < data.file4.length; i++) {
                        formData.append("file4", data.file4[i]);
                       }
                    for (var i = 0; i < data.file8.length; i++) {
                        formData.append("file8", data.file8[i]);
                       }
                    for (var i = 0; i < data.file9.length; i++) {
                        formData.append("file9", data.file9[i]);
                       }
                       
                       
                    //});
                    var headers = headersGetter();
                    delete headers['Content-Type'];
                    return formData;
                }
//                transformRequest: function(data) {
//                    var formData = new FormData();
//                    for (var i = 0; i < data.files.length; i++) {
//                        formData.append("files[" + i + "]", data.files[i]);
//                    }
//                   return formData;
//                }
                 
                //processData: false,
               // contentType: false
            }).success(function(data, status, headers, config) { 
                $scope.status = status;
                console.log(data);    
                //alert(data);
            }).error(function(data, status, headers, config) {
                $scope.data = data || "Request failed";
                $scope.status = status;
                $scope.tips = '對不起,您的網絡情況不太穩定。';
            });
多文件異步上傳的js代碼
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

public String uploadCheckImg(HttpServletRequest request,
            HttpServletResponse res, String id) {
        String msgString1 = "";
        String msgString2 = "";
        String msgString3 = "";
        String msgString4 = "";
        String msgString5 = "";
        String msgString6= "";
        String msgString7 = "";
        String msgString8 = "";
        String msgString9 = "";
        // 解析器解析request的上下文
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                request.getSession().getServletContext());
        // 先判斷request中是否包涵multipart類型的數據,
        if (multipartResolver.isMultipart(request)) {
            msgString1=writerImg1(request,"file1",id,"001");//寫入身份證
            msgString2=writerImg1(request,"file2",id,"002");//寫入畢業證
            msgString3=writerImg1(request,"file3",id,"003");//寫入學位證
            msgString4=writerImg1(request,"file4",id,"004");//寫入簡歷
            //msgString5=writerImg1(request,"file5",id,"005");//寫入社保卡
            //msgString6=writerImg1(request,"file6",id,"006");//寫入公積金
            //msgString7=writerImg1(request,"file7",id,"007");//寫入銀行卡
            msgString8=writerImg1(request,"file8",id,"008");//寫入離職證明
            msgString9=writerImg1(request,"file9",id,"009");//寫入個人頭像
        }
        return msgString1 + msgString2 + msgString3 + msgString4+msgString5 + msgString6 + msgString7 + msgString8 + msgString9;
    
    }

public String writerImg1(HttpServletRequest request,
            String inputname,String id, String fileType4){
        String fileTypeName="";
        switch(fileType4){
            case "001" :fileTypeName="身份證";break;
            case "002" :fileTypeName="畢業證";break;
            case "003" :fileTypeName="學位證";break;
            case "004" :fileTypeName="簡歷";break;
            case "005" :fileTypeName="社保卡";break;
            case "006" :fileTypeName="公積金";break;
            case "007" :fileTypeName="銀行卡";break;
            case "008" :fileTypeName="離職證明";break;
            case "009" :fileTypeName="個人頭像";break;
        }
        String msgString4="";
        String realPath = request.getSession().getServletContext()
                .getRealPath("/")
                + "img_file";// 取系統當前路徑
        // 文件保存目錄URL
        String saveUrl = request.getContextPath() + "/img_file";
        String[] fileTypes = new String[] { "jpeg", "jpg", "pdf", "doc",
                "docx", "gif", "png", "htm", "html", "txt" }; // 定義允許上傳的文件擴展名
        long maxSize = 1024000 * 10; // 允許最大上傳文件大小
        MultiPartRequestWrapper multipartRequest = (MultiPartRequestWrapper) request;
        File[] files4 = multipartRequest.getFiles(inputname);
        if (files4 == null) {

        } else {
            for (int i = 0; i < files4.length; i++) {

                // 得到上傳文件的擴展名
                String fileName = multipartRequest.getFileNames(inputname)[i];
                String fileName1 = fileName.substring(0,
                        fileName.lastIndexOf("."));
                String fileExt = fileName.substring(
                        fileName.lastIndexOf(".") + 1).toLowerCase();

                File file = files4[i];

                // 檢查擴展名
                if (!Arrays.asList(fileTypes).contains(fileExt)) {
                    msgString4 = msgString4 + fileTypeName+"—" + "上傳文件擴展名是不允許的擴展名。<br>";
                }
                // 檢查文件大小
                if (file.length() > maxSize) {
                    msgString4 = msgString4 + fileTypeName+"—" + "上傳文件大小超過限制。<br>";
                }
                // 檢查目錄寫入權限
                File uploadDir = new File(realPath);
                if (!uploadDir.canWrite()) {
                    msgString4 = msgString4 + fileTypeName+"—" + "上傳目錄沒有寫入權限。<br>";
                }
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat(
                        "yyyyMMddHHmmss");
                String time = sdf.format(date);
                String realDesc = realPath + "/" + fileType4 + "/"
                        + fileName1 + time + i + "." + fileExt;
                String saveDesc = saveUrl + "/" + fileType4 + "/"
                        + fileName1 + time + i + "." + fileExt;
                logger.info("-----絕對路徑realDesc------" + realDesc);
                if (file.renameTo(new File(realDesc))) {
                    // 將文件的映射關系寫入數據庫
                    db.insertCheckImg(id, fileName, fileType4, realDesc,
                            saveDesc);
                    msgString4 = msgString4 + fileTypeName+"—" + "[" + fileName + "]"
                            + "上傳成功!<br>";
                } else {
                    msgString4 = msgString4 + fileTypeName+"—" + "[" + fileName + "]"
                            + "上傳失敗!該文件已存在,請重新命名!<br>";
                }

            }
        }
        return msgString4;
        
    }
多文件異步上傳的java后台代碼

 

本文轉載自 文件上傳與 Angular

最近項目需要使用 Angular,對於初學 Angular 的我只能硬着頭皮上了,項目中有一個需求是文件上傳,磕磕絆絆之下也實現了,將實現過程中學習到的一些知識記錄下來以備將來查閱。

與表單數據編碼相關的知識


通常,我們使用 HTML 的標簽 <form> 來為用戶輸入創建一個表單,使用 <input type="file"> 作為文件上傳的控件。

要將表單的數據發送給后台,不僅要通過指定 <form> 的屬性 method 來確定發送數據的 HTTP 方法而且需要通過指定 <form> 的屬性 enctype 來確定對發送數據的編碼方式。

下面對這兩個屬性進行簡單說明。

表單 form 的屬性 method

<form> 的屬性 method 規定用於發送 form-data 的 HTTP 方法,其值可以為 get 或者 postget 請求會將表單的數據編碼后以 name1=value1&name2=value2 的形式附加到請求的 url 后面進行發送。post 請求會將表單的數據進行編碼之后置於請求體中進行發送。

本文接下來的討論主要基於 post 請求方式。

表單 form 的屬性 enctype

<form> 標簽的屬性 entype 用來規定在發送表單數據之前應該如何對其進行編碼,其實就是用來指定請求的編碼類型。

enctype屬性有 3 個取值,在 w3school 中對於其取值的描述如下:

取值 描述
application/x-www-form-urlencoded 空格轉換為 "+" 加號,特殊符號轉換為 ASCII HEX 值
multipart/form-data 不對字符編碼。在使用包含文件上傳控件的表單時,必須使用該值
text/plain 空格轉換為 "+" 加號,但不對特殊字符編碼

其中 application/x-www-form-urlencoded 是默認采用的編碼的方式,如果表單 <form> 中有用到文件上傳的控件,就要手動指定編碼為 multipart/form-data

下面分別對上述這幾種編碼方式進行舉例(均基於 post 請求方式)

  • 編碼為 application/x-www-form-urlencoded 的情況

首先,構造一個表單:

<form method="post" action="/" enctype="application/x-www-form-urlencoded">
  <input type="text" name="name1" placeholder="name1">
  <input type="text" name="name2" placeholder="name2">
  <input type="submit">
</form>

在輸入框內分別輸入 i'm name1 和 name@2 ,根據編碼規則,提交表單的時候,表單數據會被編碼成 name1=i%27m+name1&name2=name%402 置於請求體中進行傳遞,在 chrome 瀏覽器中執行結果也正如預期所示。


以  application/x-www-form-urlencoded 編碼來發送的表單數據
  • 編碼為 multipart/form-data 的情況

編碼為 multipart/form-data 的情況又有所不同,先來看看示例代碼的結果。

示例代碼:

<form method="post" action="/" enctype="multipart/form-data">
  <input type="text" name="name1" placeholder="name1">
  <input type="text" name="name2" placeholder="name2">
  <input type="file" name="inputfile">
  <input type="submit">
</form>

在輸入框內分別輸入 i'm name1 和 name@2 ,再選擇一個名為 testfile.txt 的文件上傳,可以在 chrome 中看到發送的請求如下:


以  multipart/form-data 編碼來發送的表單數據

注意圖片中的紅框部分,Content-Type 值為 multipart/form-data; boundary=----WebKitFormBoundaryBdpfgMg4VKAZat6C ,其中多了一個叫做 boundary 的字段,它是由瀏覽器隨機生成的一個字符串,作為表單數據的分割邊界來使用的,在服務器端會根據這個 boundary 邊界字段來解析表單數據。

可以明顯看到,以邊界分割的每一段均對應於一項表單數據,每項數據均包含有一個 Content-Disposition 字段和一個 name 字段,而對於上傳的文件則會多一個指定上傳文件名字的 filename 的屬性和上傳文件的類型的 Content-Type 字段,由於例子中上傳的文件是 .txt 格式的文件,因此 Content-Type 的值為 text/plain,有關文件的擴展名和 Content-Type 的對照表可以看這里

  • 編碼為 text/plain 的情況
    這種情況與編碼為 application/x-www-form-urlencoded 的情況類似,唯一的差別就在於 text/plain 不對特殊字符進行編碼。

文件上傳的 Angular 實現


基於 FormData 的實現

實現的思路:通過 File API 獲取控件中上傳的文件,利用 FormData 類型構造表單數據上傳。

基本知識:File API 和 FormData 類型
  • File API

File API(文件API)為Web 開發人員提供一種安全的方式來訪問用戶計算機中的文件,並更好地對這些文件執行操作。

具體來講,File API 在表單中的文件輸入字段的基礎上,又添加了一些直接訪問文件信息的接口。HTML5 在 DOM 中為文件輸入元素添加了一個 files 集合。在通過文件輸入字段選擇了一或多個文件時,files 集合中將包含一組 File 對象,每個 File 對象對應着一個文件。

構造一個文件上傳的表單,通過如下 jQuery 代碼:

$("input[type='file']")[0].files

在 chrome 瀏覽器控制台中可以看到獲得的信息如下:

可以看到選取的文件 testfile.txt 的相關信息,因此可以通過上述方式來獲得上傳的文件。

關於 File API 的更多敘述可以在這里獲得。

  • FormData 類型

FormData 是在 XMLHttpRequest Level 2 中定義的,為序列化表單以及創建與表單格式相同的數據(用於通過XHR 傳輸)提供了便利。

下面這段對於 FormData 對象的描述引用自 MDN,更多關於 FormData 類型的敘述可以在這里獲得。

XMLHttpRequest Level 2 添加了一個新的接口 FormData. 利用FormData 對象,我們可以通過 JavaScript 用一些鍵值對來模擬一系列表單控件,我們還可以使用 XMLHttpRequest 的 send() 方法來異步的提交這個"表單". 比起普通的 ajax, 使用 FormData 的最大優點就是我們可以異步上傳一個二進制文件.

可見,我們可以使用 FormData 對象來模擬實現文件上傳時候提交的表單數據,而構造提交的數據是通過 FormData 的方法 append() 實現的,它用於給當前 FormData 對象添加一個鍵/值對。

Angular 實現

有了上面所說的實現思路和基礎知識,現在可以着手進行代碼的實現了。

  • 首先,編寫一個指令用來獲取上傳文件的 File 對象。

代碼如下:

.directive( "fileModel", [ "$parse", function( $parse ){ return { restrict: "A", link: function( scope, element, attrs ){ var model = $parse( attrs.fileModel ); var modelSetter = model.assign; element.bind( "change", function(){ scope.$apply( function(){ modelSetter( scope, element[0].files[0] ); // console.log( scope ); } ) } ) } } }])

這個指令的使用方式如下:

<input type="file" file-model="fileToUpload">

對於 <input> 元素,在它們失去焦點且 value 值改變時會觸發 change 事件,因此我們在指令的 link 函數中監聽元素上的 change 事件,在事件響應函數中獲取用戶上傳的文件信息,並且將該文件賦值給 $scope 對象中與指令 fileModel 綁定的屬性(上例中為 fileToUpload)。

可以運行例子中的代碼,選擇一個文件 filetest.txt,打印出賦值后的 $scope 對象如下:


將獲取的上傳文件賦給  $scope 對象

如紅框所示,$scope 的屬性 fileToUpload 即是上傳的文件 filetest.txt 的信息。

  • 然后,編寫一個服務用於發送上傳文件的 multipart/form-data 請求。

代碼如下:

.service( "fileUpload", ["$http", function( $http ){ this.uploadFileToUrl = function( file, uploadUrl ){ var fd = new FormData(); fd.append( "file", file ) $http.post( uploadUrl, fd, { transformRequest: angular.identity, headers: { "Content-Type": undefined } }) .success(function(){ // blabla... }) .error( function(){ // blabla... }) } }])

在服務 fileUpload 的方法 uploadFileToUrl 中,通過 FormData 的 append() 方法將上傳的文件序列化為表單數據,然后通過 $http.post() 方法發送給后台。

Angular 默認的 transformRequest 方法會嘗試序列化我們的 FormData 對象,因此此處我們使用 angular.identity 函數來覆蓋它;另外,angular 在發送 POST 請求的時候使用的默認 Content-Type 是 application/json,因此此處需要調整為 undefined,這時瀏覽器會自動的幫我們設置成 multipart/form-data 的編碼方式,同時還會生成一個合適的 boundary,如果手動設置成 multipart/form-data 的話就不會生成 boundary 字段了。

  • 最后,在控制器的合適地方發送這個請求。

現在我們已經獲得了上傳的文件的相關信息,也有一個用於發送該文件的服務,那么只要在控制器中定義一個用於發送的函數,然后在合適的時機調用它即可將文件上傳到后台去了。

舉個例子,在控制器的 $scope 里面定義一個發送請求的函數 sendFile

.controller( "myCtrl", [ "$scope", "fileUpload", function( $scope, fileUpload ){ $scope.sendFile = function(){ var url = "/server", file = $scope.fileToUpload; if ( !file ) return; fileUpload.uploadFileToUrl( file, url ); } }])

然后我們可以定義一個按鈕,當用戶點擊這個按鈕的時候就會將上傳的文件發送出去。

<button type="button" ng-click="sendFile()">Submit</button>

結果是這樣的:


通過  FormData 上傳文件的請求
兼容性

由於 FormData 只兼容 IE10+ ,因此上述方法也只是在 IE10+ 中可以使用。

如果你的應用需要兼容 IE8 ,老老實實封裝一個含有 iframe 的指令即可,請接着往下看。

含有 iframe 的實現

指令代碼如下

.directive( "iframeFileUpload", [function(){ var inner = "<div>"; inner += "<form action=\"/server\" method=\"post\" enctype=\"multipart/form-data\" target=\"uploadIframe\">"; inner += "<input type=\"file\" name=\"filename\">"; inner += "<input type=\"submit\">"; inner += "</form>"; inner += "<iframe id=\"uploadIframe\" name=\"uploadIframe\" style=\"display:none\"></iframe>"; inner += "</div>"; return{ restrict: "A", template: inner, // or // templateUrl: "components/iframeFileUpload.html", replace: true, scope: {}, link: function( scope, element, attrs ){ // blabla... } } }])

調用方式大概是這樣的:

<div iframe-file-upload></div>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM