1. 程式人生 > >(轉) 淘淘商城系列——使用FastDFS-Client客戶端進行上傳圖片的測試

(轉) 淘淘商城系列——使用FastDFS-Client客戶端進行上傳圖片的測試

row 構造方法 無法 空間 依賴 ron 文件下載 信息 utils

http://blog.csdn.net/yerenyuan_pku/article/details/72804018

不久之前,我們實現了商品的類目選擇這個功能,但這只是萬裏長征的第一步,我們還有很多事情需要做,例如怎樣實現圖片上傳這個功能。本文就來教大家如何實現圖片上傳。

圖片上傳分析

我們知道,對於傳統項目來說,所有的模塊都在一個項目中開發,包括所有靜態資源文件比如圖片等,都存儲在這一個tomcat服務器上,如下圖所示。
技術分享
如果訪問量小的話,這樣做問題倒不大,但是對於互聯網項目來說,用戶訪問量很大,這樣一個tomcat服務器是遠遠不能滿足業務需求的。這就需要部署tomcat集群,有集群就需要用到負載均衡,我們一般都會使用nginx來作為負載均衡服務器,如下圖所示。

技術分享
但是這種tomcat集群的缺點也很明顯,假如我們把一張a.jpg的圖片上傳到了tomcat1的images目錄下了,由於Nginx負責均衡處理請求,當用戶去請求訪問這張圖片的時候,假設第一次,Nginx把請求交給tomcat1去處理,它到自己的images目錄下去找這張圖片,發現是可以找到的,於是我們便能看到這張圖片,當我們第二次通過Nginx去請求訪問該圖片時,Nginx把請求交給tomcat2去處理了,這時tomcat2去它自己的images目錄下去查找這張圖片,發現並沒有這張圖片,因此頁面上便看不到圖片。作為用戶來講,一次訪問能看到,再刷新就看不到,再刷新能看到,用戶會很不理解,直觀的感覺便是我們的系統太爛了。
針對上面提到的問題,我們對集群做下改善,我們專門搞一個圖片服務器,所有的tomcat都將用戶上傳的圖片上傳到圖片服務器上,tomcat本身並不保存圖片。我們采用http的方式來訪問圖片,這樣我們就需要使用http服務器,能作為http服務器的有很多種選擇。

  1. tomcat可以作為http服務器,但是由於tomcat服務器的強項並不在於處理靜態資源( 它的強項是處理servlet和jsp等動態頁面)因此我們不選擇tomcat。
  2. 使用Apache作為http服務器,Apache是由C語言編寫的一款服務器(註意,這裏指的並不是Apache組織,而僅僅是一個服務器),這款服務器在以前用的人是很多的,不過現在用的人少了。
  3. 使用nginx,nginx因為其獨特的優勢,作為http服務器是目前最火的。我們就使用nginx來統一管理這些圖片,這樣用戶要訪問圖片的時候,nginx直接把圖片服務器上的圖片給返回就可以了,從而解決了tomcat集群資源無法共享的問題。

但是這裏需要考慮一個問題,那就是作為服務器,容量肯定是有限的,當這個服務器容量滿了,怎麽辦呢?還有就是圖片服務器掛了,怎麽辦呢?這些都是必須要解決的問題,為了解決這兩個問題,我們使用FastDFS集群來解決。FastDFS是一個開源的輕量級分布式文件系統,它對文件進行管理,功能包括:文件存儲、文件同步、文件訪問(文件上傳、文件下載)等,解決了大容量存儲和負載均衡的問題。特別適合以文件為載體的在線服務,如相冊網站、視頻網站等等。它的優勢是可以水平擴容,FastDFS存儲資源的設備是按組來區分的,當存儲空間不足時,便可以通過水平增加分組並相應添加設備來達到擴容的目的,而且是沒有上限的。它還有個優勢是高可用,也就是說FastDFS集群能夠做到當提供服務的nginx發生故障時,自動切換到另一臺nginx設備上,保障服務的穩定。
技術分享

圖片服務器的安裝

在此提醒大家搭建FastDFS集群是非常非常麻煩的,至少我現在就不會,所以,作為練習,我們只需搭建單機版FastDFS即可。一個最簡單的FastDFS架構如下:
技術分享
這個架構就是我給大家提供的一個圖片服務器的架構,當然了,這個最簡單的架構在真正的生產環境中是遠遠不夠的。由於圖片服務器的安裝過程非常復雜,就不需要大家掌握了,所以我會給大家提供一個安裝好的圖片服務器。大家可參考我的這篇文章淘淘商城系列——VMware添加已配置好的虛擬機進行學習。

使用FastDFS-Client客戶端上傳圖片

下面我便用FastDFS-Client來進行上傳和下載圖片的測試,不過在這之前我們需要先做兩件事。
第一件事:由於中央倉庫並沒有fastdfs-client的包,因此需要我們自己整。這裏我提供了一個有關fastdfs-client的maven工程,如下圖所示。
技術分享
我們所要做的就是將fastdfs-client這個maven工程導入到Eclipse中,如下圖所示,導入完成之後定要將這個maven工程打包到本地maven倉庫中。
技術分享
至此,是不是萬事大吉了呢?很顯然並不是,我們直接通過表現層上傳圖片到圖片服務器,大可不必再經過Service層,所以taotao-manager-web工程需要依賴fastdfs-client工程,因此需要在taotao-manager-web工程的pom.xml文件中添加對fastdfs-client的依賴,如下所示。

<dependency>
    <groupId>fastdfs_client</groupId>
    <artifactId>fastdfs_client</artifactId>
    <version>1.25</version>
</dependency>
  • 1

第二件事:在taotao-manager-web工程的src/main/resources目錄下新建一個resource文件夾並在它下面創建fast_dfs.conf文件,fast_dfs.conf文件中輸入tracker所在的設備的IP及端口,由於我的tracker是在ip為192.168.25.133的虛擬機上,因此我這裏寫的是”tracker_server=192.168.156.13:22122”,如下圖所示。
技術分享
下面我們新建一個測試類來進行圖片上傳的測試,我們在src/test/java目錄下新建一個com.taotao.fdfs包,並在該包下新建一個測試類TestFastDfs.java,如下圖所示。
技術分享
為方便復制,現把測試類代碼粘貼如下:

public class TestFastDfs {

    @Test
    public void testUpload() throws Exception {
        // 1.先創建一個配置文件——fast_dfs.conf,配置文件的內容就是指定TrackerServer的地址

        // 2.使用全局方法加載配置文件
        ClientGlobal.init("F:/Java/my-taotao/taotao-manager-web/src/main/resources/resource/fast_dfs.conf");
        // 3.創建一個TrackerClient對象
        TrackerClient trackerClient = new TrackerClient();
        // 4.通過TrackerClient對象獲得TrackerServer對象
        TrackerServer trackerServer = trackerClient.getConnection();
        // 5.創建StorageServer的引用,null就可以了
        StorageServer storageServer = null;
        // 6.創建一個StorageClient對象,其需要兩個參數,一個是TrackerServer,一個是StorageServer
        StorageClient storageClient = new StorageClient(trackerServer, storageServer);
        // 7.使用StorageClient對象上傳文件(圖片)
        // 參數1:文件名,參數名:擴展名,不能包含".",參數3:文件的元數據,保存文件的原始名、大小、尺寸等,如果沒有可為null
        String[] strings = storageClient.upload_file("F:/fastdfs_test/meinv.jpg", "jpg", null);
        for (String string : strings) {
            System.out.println(string);
        }
    }

}

上面的代碼有兩點需要註意:

  1. taotao-manager-web工程還未添加對junit的依賴,因此需要在pom.xml文件中添加對junit的依賴,如下所示,這裏之所以不用寫版本是因為在taotao-parent工程中已經統一定義好版本了。

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
  2. 我們在復制粘貼win10系統的本地文件絕對路徑(例如F:\fastdfs_test\meinv.jpg)時,Eclipse是識別不了的,運行會報如下錯誤。解決方法是手動輸入,而且要註意把包括雙引號在內的這個路徑串刪除("E:/images/2.jpg"),然後手動輸入一遍。
    技術分享

註意上面兩點之後,我們再執行這個測試方法便可成功,如下圖所示。回顯信息的第一行是該圖片被保存到哪個組了,由於我們現在只是用的單機FastDFS服務器,因此現在都是group1。第二行是存放的具體位置。
技術分享
既然圖片上傳上去了,現在我們試著用http的方式來訪問下該圖片,我們需要把group1和M00/00/00/wKgZhVksG-6AOre0AAFkkATUCZ8885.jpg拼接到一塊來訪問,這樣我們便可以查看到我們剛才上傳的照片了,如下圖所示。
技術分享
經過上面的操作,說明我們搭建的圖片服務器沒問題。但有個問題是,圖片上傳的操作步驟繁瑣,因此我們迫切需要對其進行封裝,現在我把封裝好的工具類——FastDFSClient.java的內容粘貼如下。

public class FastDFSClient {

    private TrackerClient trackerClient = null;
    private TrackerServer trackerServer = null;
    private StorageServer storageServer = null;
    private StorageClient1 storageClient = null;

    public FastDFSClient(String conf) throws Exception {
        if (conf.contains("classpath:")) {
            conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
        }
        ClientGlobal.init(conf);
        trackerClient = new TrackerClient();
        trackerServer = trackerClient.getConnection();
        storageServer = null;
        storageClient = new StorageClient1(trackerServer, storageServer);
    }

    /**
     * 上傳文件方法
     * <p>Title: uploadFile</p>
     * <p>Description: </p>
     * @param fileName 文件全路徑
     * @param extName 文件擴展名,不包含(.)
     * @param metas 文件擴展信息
     * @return
     * @throws Exception
     */
    public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
        String result = storageClient.upload_file1(fileName, extName, metas);
        return result;
    }

    public String uploadFile(String fileName) throws Exception {
        return uploadFile(fileName, null, null);
    }

    public String uploadFile(String fileName, String extName) throws Exception {
        return uploadFile(fileName, extName, null);
    }

    /**
     * 上傳文件方法
     * <p>Title: uploadFile</p>
     * <p>Description: </p>
     * @param fileContent 文件的內容,字節數組
     * @param extName 文件擴展名
     * @param metas 文件擴展信息
     * @return
     * @throws Exception
     */
    public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {

        String result = storageClient.upload_file1(fileContent, extName, metas);
        return result;
    }

    public String uploadFile(byte[] fileContent) throws Exception {
        return uploadFile(fileContent, null, null);
    }

    public String uploadFile(byte[] fileContent, String extName) throws Exception {
        return uploadFile(fileContent, extName, null);
    }
}

該工具類構造方法中的

conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());

這句話的意思是,如果用戶傳入的文件路徑是相對路徑(相對路徑以src/main/resources目錄為根目錄),比如用戶傳入的文件路徑是”classpath:applications.properties”,那麽需要轉為絕對路徑,因此需要把”classpath:”給替換掉,改為F:/Java/my-taotao/taotao-manager-web/src/main/resources。而且封裝類中使用的Storage客戶端是StorageClient1而不是StorageClient。這個客戶端的好處是能夠幫我們自動把文件所在的組以及存放位置拼接到一塊。
我們在taotao-manager-web工程下新建一個com.taotao.utils工具包,然後把我們的封裝類FastDFSClient.java放到下面。我們來測測這個工具類是否好使,我們再在TestFastDfs單元測試類中新建一個測試方法testFastDfsClient,如下圖所示。
技術分享
testFastDfsClient單元測試方法代碼如下:

@Test
public void testFastDfsClient() throws Exception {
    FastDFSClient fastDFSClient = new FastDFSClient("F:/Java/my-taotao/taotao-manager-web/src/main/resources/resource/fast_dfs.conf");
    String string = fastDFSClient.uploadFile("F:/fastdfs_test/a.jpg");
    // 註意,你再上傳一遍,剛才你上傳的那個圖片就已經丟了,它已經存在服務器上了,你再也訪問不到了
    System.out.println(string);
}

我們運行testFastDfsClient方法,返回的結果如下圖所示。
技術分享
我們來訪問這個圖片,如下圖所示。
技術分享

(轉) 淘淘商城系列——使用FastDFS-Client客戶端進行上傳圖片的測試