詳細闡述Web開發中的圖片上傳問題

    Web開發中,圖片上傳是一種極其常見的功能。可是呢,每次作上傳,都花費了很多時間。

    一個「小功能」花費我這麼多時間,真心不愉快。

   So,要得認真分析下緣由。

1.在最初學習Java Web開發的時候,經驗不足,屬於能力問題,好比對技術認識不到位。

2.圖片上傳是一類問題,而不是一個問題。
   好比,你們都會作飯,但每一個人本身作飯是有不一樣的。作了一我的吃、一家人吃、喜事待客作好幾桌,是不一樣的問題。
   一樣的,圖片上傳,是上傳一張仍是多張,前端的用戶體驗如何,後端邏輯處理是否正確,圖片存儲是否可靠。
   本文主要探討這個問題。

3. 有些狀況,真不是個人問題。
   好比,前端上傳組件是別人寫的,一會這樣作,一會那樣作,後端不斷改。
   好比,代碼原本都不是我寫的,是由於需求變化了,我接手了,而後本身改。 

-------------------------------------------------------------------------
   下面,重點探討第2個緣由,技術問題。

a.上傳單個圖片
  html寫個file類型的input,form設置一下,enctype="multipart/form-data"。
  
  後端寫個方法處理下就好,簡要2點,1是用
@RequestParam MultipartFile 接收一個文件,2是用FileUtils複製臨時文件到目標文件
  
   
 @RequestMapping(value = "oneFileUpload", method = RequestMethod.POST)
    public String uploadLoginSplash(HttpServletRequest request, @RequestParam("file") MultipartFile file)
            throws IOException {
        if (!file.isEmpty()) {
            String realPath = request.getSession().getServletContext().getRealPath(SPLASH);
            // 這裏沒必要處理IO流關閉的問題,由於FileUtils.copyInputStreamToFile()方法內部會自動把用到的IO流關掉,我是看它的源碼才知道的
            FileUtils.copyInputStreamToFile(file.getInputStream(), new File(realPath, SPLASH_JPG));
        }

        return "manager/setting/settingManager";
    }



b. 上傳多個圖片。
 方法一:
  定義多個file,後端用數組接收 @RequestParam ( "file" ) CommonsMultipartFile[] files。
 一種比較靈活的方式是,寫JS方法,點擊「添加」和「刪除」,能夠選擇增長上傳圖片的「上傳框」。

 這種方式,我沒有去實踐,在CSDN上看到了一篇不錯的帖子,屬於看了但沒有去實踐。

方法二:
使用圖片上傳組件,相比方法一,更加靈活,但也有缺點,後端接收不能直接使用數組CommonsMultipartFile[] files,我嘗試了不太行。
前端上傳組件,嘗試的有webuploader,能夠一次性選擇多張圖片,可是分批上傳的。
尼瑪,百度了下,原來是百度團隊搞的,怪不得看起來用起來,好高端大氣的樣子。
官網:http://fex-team.github.io/webuploader/

最早用的是,dropzone,感受還行,可是沒有百度的看起來美觀,一次性能夠選擇多張圖片,但一次性所有上傳。
官網:http://www.dropzonejs.com/
最早的最早,某個同事用的是jquery的上傳組件,印象中是的。

 後端處理多張圖片的代碼,比較通用的。
@RequestMapping("/idCardImageUpload")
	public void idCardImageUpload(HttpServletRequest request,
			HttpServletResponse response) throws IllegalStateException,
			IOException {
		// 建立一個通用的多部分解析器
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
				request.getSession().getServletContext());
		String finalFileName="";
		// 判斷 request 是否有文件上傳,即多部分請求
		if (multipartResolver.isMultipart(request)) {
			// 轉換成多部分request
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
			// 取得request中的全部文件名
			Iterator<String> iter = multiRequest.getFileNames();
			while (iter.hasNext()) {
				// 取得上傳文件
				MultipartFile file = multiRequest.getFile(iter.next());
				if (file != null) {
					// 取得當前上傳文件的文件名稱
					String fileName = file.getOriginalFilename();
					// 若是名稱不爲「」,說明該文件存在,不然說明該文件不存在
					if (StringUtils.isNotEmpty(fileName)) {
						String[] strs = fileName.split("\\.");
						String fileExtention="png";
						// 重命名上傳後的文件名
						if(strs.length >=2){
							fileExtention=strs[strs.length-1];
						}
						try {
							fileName = AES.Encrypt(fileName, DateFormatUtil
									.format(new Date(), "yyyyMMddHHmmssSSS")
									.substring(1))+"."+fileExtention;
							finalFileName +=fileName+",";
							// 定義上傳路徑
							String imagePath = (String) BasePropertyConfigurer
									.getContextProperty("idCardImageUploadPath");
							String path = imagePath + fileName;
							File localFile = new File(path);
							file.transferTo(localFile);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			
			}
			JSONObject jsonObj = new JSONObject();
			response.setContentType("text/html;charset=UTF-8");
			jsonObj.put("success", true);
			jsonObj.put("fileName",finalFileName);
			returnJsonObject(response, jsonObj);
		}
	
	} 


--------------------------------------------------------------------------------------------
上面介紹了緣由,而後重點闡述了先後端的組件和實踐方法,下面迴歸「圖片上傳問題」的本質,即流程問題。

圖片上傳流程
第一步:經過上傳組件,選擇一張或多張圖片。
第二步:肯定上傳,把圖片傳到後端,後端接收圖片,保存到某個位置。
第三步:前端提交表單,包括圖片的名字等。

這個問題有點複雜,再補充幾點:
第一:上傳是能夠同步的,也能夠是異步的。
   好比經過form提交到後端,也能夠是經過jquery等插件AJAX提交。
   異步提交的時候,須要後端「回顯圖片信息」,好比圖片的名字、圖片的URL。

第二:是否容許圖片存儲位置,有「髒數據」,即沒有實際價值的圖片。
  好比,一個用戶選擇了圖片,上傳到了後端,可是表單可能沒有提交。

  若是,直接把用戶的圖片,放到實際的存儲位置,就有髒數據了,但不影響圖片的展現。

  另一種方式是,用戶上傳的圖片,先存到一個特定的臨時位置,用戶肯定上傳圖片後,把這裏的圖片移動到,實際的存儲位置。

第三:圖片信息存到數據庫。
  我的以爲,只存儲圖片的名字比較好,至於路徑,存到數據庫以後,會很是不靈活。
  前端展現圖片,自定義url路徑,好比/image/a.jpg,後端把/image路徑映射到實際的圖片位置。

第四:圖片的名字。
 把用戶上傳時的名字,做爲實際存儲的圖片名字很差,一是中文容易出問題,二是不能保證惟一性,會存在覆蓋的可能性。
 我的以爲,圖片的名字用時間+隨機數等方式生成惟一的名字,好比abcd.jpg。
 這個時候須要注意,圖片的後綴,須要從用戶上傳的圖片名字解析出來,好比從「小雷FansUnion.png」解析出後綴".png",把
「小雷FansUnion.gif」存爲「abcd.png」可能沒法正常顯示。

第五:圖片上傳也可使用雲服務。
 2014年春,作ITFriend的時候,用的是「美圖秀秀的圖片上傳組件」。雲服務用着仍是不錯的,上傳以後,能夠當即進行「美化」「塗鴉」等操做。
最終,再保存到數據庫。

第六:圖片存儲 也可使用雲服務。
我的以爲,圖片必定要存儲到Tomcat等服務器的外部。有的人爲了方便,把圖片存儲到Tomcat的webapps目錄,這樣比較危險,tomcat重啓-從新部署,可能會把圖片給搞丟了。

存儲到硬盤等外部,作個圖片請求映射就好。

還有一種方式,圖片存儲也使用「雲存儲」,又拍雲用着還湊合。
-------------------------------------------------
總結,圖片上傳實際上是個很複雜的問題。
沒有足夠經驗,不懂實際需求的開發者,進度會估計不許。

參考資料
http://fex-team.github.io/webuploader/
http://www.dropzonejs.com/
http://blog.csdn.net/a1314517love/article/details/24183273 秒針工做時,BrandCenter項目積累朋來谷工做時,ITFriend項目積累一塊兒好工做時,p2p項目積累 
相關文章
相關標籤/搜索