做多文件/圖片上傳應該注意的幾個前後端問題

最近在做微信端的文件上傳,遇到了幾個問題,折騰完後這裏統一總結下,希望對其他人能有點幫助。
我前端未使用其他上傳組件,用的原生的HTML、JS、CSS。
廢話不多說,直接羅列你可能關心的點:

前端:

1.html自帶file控件樣式醜陋,如何達到UI設計要求效果;
2.選擇圖片後,按照一定的樣式回顯示圖片如何實現;
3.無刷新提交;
4.form序列化無法提交二進制文件(這裏是針對Query ajax的serialize()而言),該如何提交文件類型;
5.JS選擇器獲取單個文件、“multiple”類型多文件及非“multiple”類型的多個同類型input控件文件;

後端:

6.如何在後端接收文件類型(這裏特指spring框架)
7.文件傳入爲空後端報錯如何解決;
8.如何在後端接收一組文件;
9.寫入文件;

實現(以下實現中,只截取了必要的代碼)

問題1: html自帶file控件樣式醜陋,如何達到UI設計要求效果;

html默認的file控件樣式往往達不到我們的要求,所以需要採用一定的css樣式達到UI設計的效果。
我們先看下沒有添加任何樣式的file類型input控件的樣式:

這裏寫圖片描述

我們期望的樣式,for example:

這裏寫圖片描述

實現的HTML、CSS:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        html,body{
            margin:0;
            padding:0;
        }
        img{
            width: 100px;
            height: 100px;
            border:1px dotted blue;
        }
        input{
            width:100px;
            height:100px;
            z-index: 999;
            opacity: 0;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>
<body>
<img id="preview" src="http://avatar.csdn.net/E/A/1/3_irokay.jpg" alt="">
<input id="file" type="file" name="file">
</body>
</html>

效果圖:
這裏寫圖片描述

請自行把我的頭像腦補成UI設計中的圖片 - -!重點在於opacity、z-index、positon,然後調整位置使之大小、位置重合即可。

問題2: 選擇圖片後,按照一定的樣式回顯示圖片如何實現;

我們採用FileReader對象的readAsDataURL回顯圖片,下面是介紹:

FileReader對象的readAsDataURL方法可以將讀取到的文件編碼成Data URL。Data URL是一項特殊的技術,可以將資料(例如圖片)內嵌在網頁之中,不用放到外部文件。使用Data URL的好處是,您不需要額外再發出一個HTTP 請求到服務器端取得額外的資料;而缺點便是,網頁的大小可能會變大。它適合應用在內嵌小圖片,不建議將大圖像文件編碼成Data URL來使用。您的圖像文件不能夠超過瀏覽器限定的大小,否則無法讀取圖像文件。

JS代碼:

<script type="text/javascript">
    function previewImg(){
        let preview = document.querySelector('img[id=preview]');
        let file = document.querySelector('input[id=file]').files[0];
        let reader = new FileReader();
        reader.onloadend = function () {
          preview.src = reader.result;
        }
        if (file) {
          reader.readAsDataURL(file);
        } else {
         preview.src = "";
        }

    }
</script>

問題3: 無刷新提交

這裏採用原始的ajax提交,jquery ajax提交見我的另外一篇博客:
http://blog.csdn.net/irokay/article/details/72984048
步驟:
1)let request = new XMLHttpRequest()
2)request.open(“POST”, url)
3)request.onload = function(oEvent) {
if (request.status == 200) {
//alert(“success”);
} else {
//alert(“出錯啦!請稍後再試。” + request.status);
}
};
4) request.send(formData);

問題4: form序列化無法提交二進制文件(這裏是針對Query ajax的serialize()而言),該如何提交文件類型;

若採用Jquery ajax,序列化(serialize())表單是無法序列化二進制數據的,故我們採用FormData的方式提交文件類型。FormData對瀏覽器版本的要求見上面博客地址。當然我們這裏沒有采用jquery封裝的ajax提交。

注:我這裏是移動開發,移動端瀏覽器內核版本還是比較高的,所以使用FormData無問題。

FormData的使用:

let formData = new FormData();

//FormData添加文件類型:
formData.append("file",document.querySelector('input[id=file]').files[0]);

問題5: JS選擇器獲取單個文件、“multiple”類型多文件及非“multiple”類型的多個同類型input控件文件;

這裏重點說一下。

1)單個文件的選擇上述已經寫到:

document.querySelector('input[id=file]').files[0]

2)若是“multiple”類型的input控件,即一個input控件可以同時選擇多個文件(<input type=”file” multiple=”multiple” />);
選擇器獲取的寫法:

<input id="file" type="file" multiple="multiple" />
//獲取一個多選input file控件上的文件
document.querySelector('input[id=file]').files;
//alert("length:" + document.querySelector('input[id=file]').files.length);

3) 我們考慮下另外一種方式,採用追加的方式實現多圖預覽,譬如有多個id同爲file的input組件,且全是單選(非multiple),這些照片爲一組,需要統一獲取並上傳。
選擇器獲取方法爲:

let files = document.querySelectorAll('input[id=file]');
let formData = new FormData();
for(let i = 0; i < files.length; i++){
    //alert("路徑爲:" + files[i].value);
    //alert("file對象:" + files[i].files[0]);
    //將一組文件類型追加至file集合中
    formData.append("file",files[i].files[0]);
  }

這樣即可將一組文件加入FormData的同一key下,一同提交。

問題6: 如何在後端接收文件類型(這裏特指spring框架)

//接收單個文件
//且file文件不可爲空,否則報錯
public void savePic(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request, HttpServletResponse response,) throws IOException {...}

問題7:文件傳入爲空後端報錯如何解決;

若前端未傳入任何文件,上述寫法會報錯:

Cannot convert value of type [java.lang.String] to required type [org.springframework.web.multipart.commons.CommonsMultipartFile]

當前端傳入文件可能爲空時,後端接收不可寫入方法參數中,避免報錯。正確寫法如下:

MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartRequest.getFile("file"); //獲取單個文件
//爲空判斷以及處理等...

問題8: 如何在後端接收一組文件;

MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//MultipartFile file = multipartRequest.getFile("file"); 獲取單個文件
List<MultipartFile> fileList = multipartRequest.getFiles("file"); //獲取一組文件
if(null != fileList && fileList.size()>0){
    for(int i = 0; i < fileList.size(); i++){
    System.out.println("第(" + i + ")個文件名:" + fileList.get(i).getOriginalFilename());
    }
}

問題9: 寫入文件;

File newFile=new File(path);
//通過CommonsMultipartFile的方法直接寫文件
file.transferTo(newFile);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章