1. 程式人生 > >圖片上傳之fileupload

圖片上傳之fileupload

       最近學習了圖片上傳這個功能,這個功能比較常見,因此來整理一下,瞭解上傳的基本原理,以便後期遇到圖片上傳功能可以很快上手。

       要說圖片上傳,我們先來說一下圖片上傳後儲存的兩種方式:一種是將圖片儲存到資料庫中;一種是將圖片儲存在伺服器檔案目錄中。首先,對於將圖片儲存到資料庫中適合資料量小的情況,因為寫到資料庫的圖片需要轉換成二進位制流的格式,佔用資料空間比較,適合少量圖片的儲存,比如,系統中某些小圖示,寫到資料庫中的優點是比較安全,不容易被使用者不小心刪除。但是,圖片存在資料庫的操作方面的侷限性太大,還要拼湊sql,db server還要parse sql, write into file,讀寫效能不高,備份越來越大。

如果是大量的圖片儲存通常的做法是儲存到伺服器的某個目錄下。一方面,其完成圖片上傳有很多方式,可以採用流的方式,可以採用ftp的方式等;另一方面備份方便(只備DB),讀取高效能。這種方式便於直接訪問,適用於直接顯示方面的需求,但路徑與圖片的對映容易出問題。對於超級大型應用,需要的是資料庫的批量查詢和返回結果,這時應用分散式將圖片儲存在資料庫中,比如谷歌的Bigtable,也可以理解成nosql,以及Amazon的S3儲存服務是基於文件型資料庫的,也是nosql現在很多網站直接把自己的二進位制資料放在S3,能夠滿足全球分散式管理,並且不用自己動手。想說一句,看應用的規模,以及擴充套件性的需要,選擇適合的圖片儲存方式,沒有絕對的答案。

      下面我將以圖片儲存在伺服器目錄中的形式,介紹一下fileupload方式的圖片上傳。common-fileupload元件是apache的一個開源專案之一,可以從

下面我就講一下基本實現:

       首先需要在lib目錄下引入:commons-io-1.3.2.jar和commons-fileupload-1.3.1.jar

前端程式碼:

<span style="font-size:14px;"><%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
<html>  
  <head>
  
    <title>fileUpload</title>
    
    <meta http-equiv="Content-Type" content="text/html; charset=GB18030">

  </head>

  <body>
  
   <form action="./servlet/FileUploadServlet" method="post" enctype="multipart/form-data" name="form1">
   
     <input type="file" name="file">
     
     <input type="submit" name="Submit" value="upload">
     
   </form>
   
   <form action="./servlet/HelloWord" method="post">
   
    <input type="submit"/>
    
   </form>
   
    <form name="uploadform" method="POST" action="./servlet/FileUploadServlet" ENCTYPE="multipart/form-data">

        <table border="1" width="450" cellpadding="4" cellspacing="2" bordercolor="#9BD7FF">

        <tr><td width="100%" colspan="2">

                        檔案1:<input name="x" size="40" type="file">

        </td></tr>

        <tr><td width="100%" colspan="2">

                        檔案2:<input name="y" size="40" type="file">

        </td></tr>

        <tr><td width="100%" colspan="2">

                        檔案3:<input name="z" size="40" type="file">

        </td></tr>

        </table>

        <br/><br/>

        <table>

        <tr><td align="center"><input name="upload" type="submit" value="開始上傳"/></td></tr>

       </table>
       
     </form>

  </body>
</html>
</span>

      注意:檔案上傳在前端要使用file標籤,採用form表單提交enctype=" multipart/form-data "關於enctype="multipart/form-data"的說明:在jsp中使用了該格式,對應的Servlet就不能使用request.getParameter()取得引數,要使用ServletFileUpload物件的parseRequest方法先把request物件中的資料解析,然後,使用解析出的元素的isFormField標誌,配合getFieldName方法來獲取資料。

 java程式碼:

<span style="font-size:14px;">package uploadPack;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@SuppressWarnings("serial")
public class FileUploadServlet extends HttpServlet {
	
	 //儲存圖片到資料庫類的方法
	 ItemManager itemManager  = new  ItemManagerImpl() ; 

	 //用於存放上傳檔案
	 private File uploadPath;
	 //用於存放臨時檔案的目錄
	 private File tempPath;
	 
	 @Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
	
		 doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		//從test_upload.jsp中拿取資料,因為上傳頁的編碼格式跟一般的不同,使用的是enctype="multipart/form-data"
		//form提交採用multipart/form-data,無法採用req.getParameter()取得資料
		
		//DiskFileItemFactory:建立FileItem物件的工廠,這個工廠類中可以配置記憶體緩衝池大小和臨時檔案的目錄
		 DiskFileItemFactory factory = new DiskFileItemFactory();
		// maximum size that will be stored in memory
		 factory.setSizeThreshold(4096);
		// the location for saving data that is larger than getSizeThreshold()
		 factory.setRepository(tempPath);
		 
		 //ServletFileUpload:負責處理上傳的檔案資料,並將每部分的資料封裝成到FileItem物件中
		 
		 //在接收上傳檔案資料時,會將內容儲存到記憶體快取區中,如果檔案內容超過了 DiskFileItemFactory 指定的緩衝區的大小,   
         //那麼檔案將被儲存到磁碟上,儲存為DiskFileItemFactory指定目錄中的臨時檔案
		 //等檔案資料都接收完畢後,ServletFileUpload再從檔案中將資料寫入到上傳檔案目錄下的檔案中
		 
		 ServletFileUpload upload = new ServletFileUpload(factory);
		// maximum size before a FileUploadException will be thrown   
		 upload.setSizeMax(1000000* 100);
		 
		 try {
			 

			 //從test_upload.jsp中拿取資料,因為上傳頁的編碼格式跟一般的不同,使用的是enctype="multipart/form-data"
			 //form提交採用multipart/form-data,無法採用req.getParameter()取得資料
			 List fileItems =upload.parseRequest(req);
			 
			 //迴圈提交的表單
			 for (Iterator iter = fileItems.iterator(); iter.hasNext();) {
				
				 FileItem item = (FileItem) iter.next();
				 String itemNo = "";  
                 
			    //判斷是檔案還是文字資訊   
                //是普通的表單輸入域   
                if(item.isFormField()) {  
                    if ("itemNo".equals(item.getFieldName())) {  
                    	
                    	//將FileItem物件中儲存的主體內容作為一個字串返回,亂碼可以加編碼方式
                        itemNo = item.getString();  
                    }  
                }  

				 
                 //是否為input="type"輸入域
				 if(!item.isFormField()){
					 
					//上傳檔案的名稱和完整路徑 
				    String name =item.getName();
				    long size =item.getSize();
				    
				  //判斷是否選擇了檔案
				    if ((name ==null || name.equals("")) && size==0) {
						continue;
					}
				    
				    //擷取字串 
                    name = name.substring(name.lastIndexOf("\\") + 1, name.length());
				    
                    //將檔案儲存到目錄下,不修改檔名   
                    item.write(new File(uploadPath, name));  
                    
                    //將圖片檔名寫入打資料庫                     
                    itemManager.uploadItemImage(itemNo, name);  

				 }
				
			}
		
			 resp.sendRedirect(req.getContextPath() + "/servlet/item/SearchItemServlet");  
	 
		} catch (Exception e) {
			e.printStackTrace();
			throw new ApplicationException("上傳失敗!");  

		}
	}

	    /**
	     * 在系統啟動的時候就初始化,在初始化時,檢查上傳圖片的資料夾和存放臨時檔案的資料夾,如果不存在就建立
	     */
	    @Override  
	    public void init() throws ServletException {  

		    //獲取根目錄對應的真實物理路徑   
	        uploadPath = new File(getServletContext().getRealPath("/upload"));  
	       
	        //如果目錄不存在   
	        if (!uploadPath.exists()) {  
	            //建立目錄   
	            uploadPath.mkdir();  
	        }  
	          
	        //臨時目錄   
	        //File tempFile = new File(item.getName())構造臨時物件   
	        tempPath = new File(getServletContext().getRealPath("/temp"));  
	        if (!tempPath.exists()) {  
	            tempPath.mkdir();  
	        }  
	        
	 }
}
</span>

配置檔案:

<span style="font-size:14px;"><?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" 
	xmlns="http://java.sun.com/xml/ns/j2ee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
     <servlet-name>FileUploadServlet</servlet-name>
     <servlet-class>uploadPack.FileUploadServlet</servlet-class>
     <load-on-startup>10</load-on-startup>
  </servlet>
  <servlet-mapping>
     <servlet-name>FileUploadServlet</servlet-name>
     <url-pattern>/servlet/FileUploadServlet</url-pattern>
  </servlet-mapping>
</web-app>
</span>

         後面還會遇到很多其他上傳圖片的方法,會繼續總結整理。