FastDFS 入門
分布式檔案系統
-
分布式檔案系統 (Distributed File System) 是一個軟體/軟體服務器,這個軟體可以用來管理檔案,但這個軟體所管理的檔案通常不是在一個服務器節點上,而是在多個服務器節點上,這些服務器節點通過網路相連構成一個龐大的檔案存盤服務器集群,這些服務器都用于存盤檔案資源,通過分布式檔案系統來管理這些服務器上的檔案,
-
常見的分布式檔案系統有:FastDFS、GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS 等,
分布式檔案系統與傳統檔案系統對比:


傳統方式弊端:
-
如果用戶數量多,IO 操作比較多,對磁盤訪問壓力很大
-
如果磁盤發生故障,會造成資料丟失
-
存盤容量有限
分布式檔案系統優點:
- 解決單點故障問題,多服務器節點保證檔案讀寫
- 提供資料備份
- 提供擴容等
FastDFS 簡介
-
FastDFS 是一個開源的輕量級分布式檔案系統,為互聯網應用量身定做,簡單、靈活、高效,采用 C 語言開發,由阿里巴巴開發并開源,
-
FastDFS 對檔案進行管理,功能包括:檔案存盤、檔案同步、檔案訪問(檔案上傳、檔案下載、檔案洗掉)等,解決了大容量檔案存盤的問題,特別適合以檔案為載體的在線服務,如相冊網站、檔案網站、圖片網站、視頻網站等等,
-
FastDFS 充分考慮了冗余備份、線性擴容等機制,并注重高可用、高性能等指標,使用 FastDFS 很容易搭建一套高性能的檔案服務器集群提供檔案上傳、下載等服務,
-
FastDFS 代碼托管在 github 上:https://github.com/happyfish100/fastdfs
FastDFS 整體架構
-
FastDFS 檔案系統由兩大部分構成,一個是客戶端,一個是服務端
-
客戶端通常指我們的程式,比如我們的 Java 程式去連接 FastDFS、操作 FastDFS,那我們的 Java 程式就是一個客戶端,FastDFS 提供專有 API 訪問,目前提供了 C、Java 和 PHP 幾種編程語言的 API,用來訪問 FastDFS 檔案系統,
-
服務端由兩個部分構成:一個是跟蹤器(tracker),一個是存盤節點(storage)
-
跟蹤器(tracker)主要做調度作業,在記憶體中記錄集群中存盤節點 storage 的狀態資訊,是前端 Client 和后端存盤節點 storage的樞紐,因為相關資訊全部在記憶體中,Tracker server 的性能非常高,一個較大的集群(比如上百個group)中有3臺就足夠了,
-
存盤節點(storage)用于存盤檔案,包括檔案和檔案屬性(meta data)都保存到存盤服務器磁盤上,完成檔案管理的所有功能:檔案存盤、檔案同步和提供檔案訪問等,
-
FastDFS 環境搭建
資源準備
資源下載地址(或百度云盤直取):https://github.com/happyfish100

資源介紹:
- fastdfs-6.08.tar.gz:FastDFS 的安裝包(只能在 Linux 上安裝)
- fastdfs-client-java-1.28.zip:FastDFS 的 Java 客戶端源代碼
- fastdfs-nginx-module-1.22.zip:FastDFS-Nginx 的擴展模塊
- libfastcommon-1.0.56.tar.gz:FastDFS 的公共函式庫(Linux 上安裝)
FastDFS 安裝
FastDFS 沒有 Windows 版本,不能在 Windows 下使用,
FastDFS 需要安裝部署在 Linux 環境下,
-
安裝 gcc、libevent、libevent-devel 前置依賴
yum install gcc libevent libevent-devel -y -
將 FastDFS 的安裝包 fastdfs-6.08.tar.gz 和 FastDFS 的公共函式庫 libfastcommon-1.0.56.tar.gz 上傳到 /home/soft/ 下
-
解壓縮公共函式庫
tar -zxvf libfastcommon-1.0.56.tar.gz -
進入解壓縮后的公共函式庫根目錄,執行編譯命令:
./make.sh -
編譯完成后,執行安裝命令:
./make.sh install,以上,公共函式庫安裝完畢 -
同樣,按照此步驟,將 FastDFS 先后進行解壓,編譯,安裝!
-
至此 FastDFS 安裝完成!
所有編譯出來的檔案存放在 /usr/bin 目錄下(放在 /usr/bin 下的命令,我們可在任何地方使用,不用切目錄)
所有組態檔存放在 /etc/fdfs 目錄下,如下:(后面會使用到這些組態檔)
client.conf storage.conf storage_ids.conf tracker.conf -
注意:還需要將
/home/soft/fastdfs-6.08/conf/下的 http.conf 和 mime.types 兩個檔案拷貝到 /etc/fdfs/ 目錄下;后期程式會使用到這兩個檔案,避免報錯;
cp /home/soft/fastdfs-6.08/conf/http.conf /etc/fdfs/ cp /home/soft/fastdfs-6.08/conf/mime.types /etc/fdfs/
FastDFS 配置
-
如果你使用的安裝版本中
/etc/fdfs下的組態檔有類似 .sample 擴展名,則其為示例組態檔,需要去掉 .sample 后綴才能生效,這點需要注意下, -
將 storage.conf 和 tracker.conf 下載到本機,進行相關配置
-
配置 tracker.conf 檔案:(跟蹤器組態檔)
找到 base_path 引數,配置 tracker 存盤資料的目錄并手動創建:(需要確保該目錄存在,目錄需要我們手動創建好)
base_path:配置 tracker 存盤資料的目錄
base_path = /opt/fastdfs/tracker -
配置 storage.conf 檔案:(存盤節點組態檔)
找到 base_path 引數,配置 storage 存盤資料的目錄并手動創建:(需要確保該目錄存在,目錄需要我們手動創建好)
base_path:配置 storage 存盤資料的目錄
path_path = /opt/fastdfs/storage找到 store_path0 引數,配置 storage 的磁盤存放路徑,即真正存放檔案的目錄:(需確保該目錄存在,需我們手動創建好)
store_path0:真正存放檔案的目錄
store_path0 = /opt/fastdfs/storage/files找到 tracker_server 引數,配置當前存盤節點的跟蹤器地址:(只需要配置 IP 即可,埠不要改動)
tracker_server:注冊當前存盤節點的跟蹤器地址
tracker_server = 192.168.154.129:22122 -
將在 Windows 中配置完成并保存的 tracker.conf 和 storage.conf 兩個檔案上傳到
/etc/fdfs目錄下,并覆寫原檔案;上傳并覆寫的命令:
rz -y
FastDFS 啟動
FastDFS 服務啟動需要啟動兩個腳本:tracker 服務和 storage 服務
命令語法參考:
fdfs_trackerd <config_file> [start | stop | restart]
fdfs_storaged <config_file> [start | stop | restart]
- 在確保需要手動創建的目錄存在的情況下,分別執行下列命令啟動 FastDFS:(不加 start 默認是啟動)
fdfs_trackerd /etc/fdfs/tracker.conf
fdfs_storaged /etc/fdfs/storage.conf
ps -ef|grep fdfs 查看相關行程,是否啟動成功
FastDFS 重啟
- 分別執行下列命令重啟 FastDFS:
fdfs_trackerd /etc/fdfs/tracker.conf restart
fdfs_storaged /etc/fdfs/storage.conf restart
ps -ef|grep fdfs 查看相關行程,是否重啟成功
FastDFS 關閉
- 分別執行下列命令關閉 FastDFS:(其實也可使用 kill 關閉,但為了防止上傳檔案中資料丟失,不建議使用 kill 方式)
fdfs_trackerd /etc/fdfs/tracker.conf stop
fdfs_storaged /etc/fdfs/storage.conf stop
ps -ef|grep fdfs 查看相關行程,是否成功關閉
FastDFS 測驗
此處示例的上傳下載操作其實開發中用不到,主要是感受下 FastDFS 的執行;重點是上傳成功后組名和遠程檔案名的解讀!
測驗說明:測驗檔案上傳和洗掉
測驗前配置修改
-
需要修改
/etc/fdfs/client.conf組態檔的兩個引數(自行修改,步驟不再復述;需確保所填的 client 目錄存在)修改小技巧:直接在該檔案目錄下打開 xftp 傳輸,直接在傳輸頁面打開檔案,修改并保存!
注意:client.conf 檔案只在測驗的時候才會用到!
base_path = /opt/fastdfs/client tracker_server = 192.168.154.129:22122
測驗檔案上傳
測驗命令語法參考:
Usage: fdfs_test <config_file> <operation>
operation: upload, download, getmeta, setmeta, delete and query_servers
-
啟動或重啟 FastDFS 服務:
fdfs_trackerd /etc/fdfs/tracker.conf restart fdfs_storaged /etc/fdfs/storage.conf restart ps -ef|grep fdfs 查看相關行程,是否重啟成功 -
在 /home 下創建一個用于測驗的檔案
vim test.txt -
上傳該檔案,執行:
fdfs_test /etc/fdfs/client.conf upload /home/test.txt -
上傳成功后會顯示一些相關資訊,其中最重要的有如下兩個資訊:【重點!】
group_name:組名(決定檔案存到哪個機器)
remote_filename:遠程檔案名(決定檔案存放到哪個磁盤目錄下)
FastDFS 存盤檔案時會自動將檔案重命名
該檔案存盤的路徑:
/opt/fastdfs/storage/files/data/00/00/wKiagGJUGnWAGvVNAAAAFU1LnYY803.txtgroup_name=group1, remote_filename=M00/00/00/wKiagGJUGnWAGvVNAAAAFU1LnYY803.txt

測驗檔案下載
下載命令格式:
Usage: fdfs_test <config_file> download <group_name> <remote_filename>
-
在 /home 目錄下執行下列命令:
fdfs_test /etc/fdfs/client.conf download group1 M00/00/00/wKiagGJUGnWAGvVNAAAAFU1LnYY803.txt -
在 /home 當前目錄下看到下載成功的 wKiagGJUGnWAGvVNAAAAFU1LnYY803.txt 檔案
測驗檔案洗掉
洗掉命令格式:
Usage: fdfs_test <config_file> delete <group_name> <remote_filename>
-
直接執行:
fdfs_test /etc/fdfs/client.conf delete group1 M00/00/00/wKiagGJUGnWAGvVNAAAAFU1LnYY803.txt -
可在
/opt/fastdfs/storage/files/data/00/00路徑下看到對應的原檔案已經被洗掉
注意
- 沒有搭建集群默認只有一個組 group1
- FastDFS 存盤檔案的同時會存盤一個與其對應的屬性檔案(備份檔案也是,一個備份檔案對應一個屬性檔案)
- 后綴名包含 -m 的為屬性檔案(meta)
- 在Linux中并沒有磁盤一說,是虛擬的
分布式檔案系統 FastDFS 的 HTTP 訪問
- 在檔案上傳的時候,上傳成功的資訊中有提示我們可以通過某個路徑去訪問上傳的檔案,但是我們直接訪問這個路徑,卻不可以,那么已經上傳到 FastDFS 檔案系統中的檔案,我們如何在瀏覽器中訪問呢?FastDFS 提供了一個 Nginx 擴展模塊,利用該模塊,我們可以通過 Nginx 訪問已經上傳到 FastDFS 上的檔案,
步驟示例:
1.前期準備
- 將 FastDFS-Nginx 的擴展模塊 fastdfs-nginx-module-1.22.zip 上傳到 /home/soft 下;
- 解壓:
unzip fastdfs-nginx-module-1.22.zip; - 將解壓縮的
/home/soft/fastdfs-nginx-module-1.22/src/mod_fastdfs.conf檔案下載到 Windows 中,后邊會進行配置使用; - 將解壓縮的擴展模塊源代碼的 src 路徑
/home/soft/fastdfs-nginx-module-1.22/src拷貝下來,先存著,后面配置重新安裝的 Nginx 時會用到這個路徑;
2.重裝 Nginx
注意:Nginx 的安裝需要 Linux 安裝相關的幾個庫,否則編譯會出現錯誤;
如果之前沒有安裝過 Nginx,則先執行下列命令安裝!如果之前安裝過 Nginx,下面這相關庫的安裝步驟就可直接跳過!
yum install gcc openssl openssl-devel pcre pcre-devel zlib zlib-devel –y
-
接下來重新安裝 Nginx:因為擴展模塊必須在 Nginx 的安裝程序中才能添加,所以我們需要重新安裝一個 nginx,為了和原來已安裝的 Nginx 進行區分,我們把新安裝的 Nginx 取名為 nginx_fdfs(指定 nginx 安裝路徑時進行取名)
-
將 Nginx 壓縮包上傳到 /home/soft/ 目錄下,并進行解壓縮;
-
進入解壓縮后的 Nginx 目錄下,按照下面的說明檢查路徑,并執行下列配置命令:
./configure --prefix=/usr/local/nginx_fdfs --add-module=/home/soft/fastdfs-nginx-module-1.22/src --prefix 是指定nginx安裝路徑 --add-module 指定fastDFS的nginx模塊(即擴展模塊)的源代碼路徑(之前已讓拷貝存著了) -
執行編譯命令:
make; -
執行安裝命令
make install,完成 Nginx 的重新安裝
3.FastDFS 的 Nginx 訪問配置
-
對之前下載下來的擴展模塊 src 下的 mod_fastdfs.conf 檔案進行如下四項配置:(nginx_mod 目錄需要手動創建)
創建目錄可使用:
mkdir -p /opt/fastdfs/nginx_mod命令base_path=/opt/fastdfs/nginx_mod tracker_server=192.168.154.129:22122 url_have_group_name = true store_path0=/opt/fastdfs/storage/files -
使用
rz -y命令將配置后的 mod_fastdfs.conf 檔案上傳到/etc/fdfs目錄下 -
在
/usr/local/nginx_fdfs/conf目錄下,使用sz nginx.conf命令,將 nginx.conf 檔案下載到 Windows 中,進行如下配置:(注意:是在 server 下新建一個 location 進行配置,千萬不要直接在原有的 location 中進行修改!)下面正則使用固定,可直接復制!
#攔截請求路徑中包含 /group[1-9]/M0[0-9] 的請求,用 fastdfs的Nginx 模塊進行轉發 location ~ /group[1-9]/M0[0-9] { ngx_fastdfs_module; } -
在
/usr/local/nginx_fdfs/conf路徑下輸入rz -y上傳配置好的 nginx.conf 進行原檔案覆寫; -
檢查組態檔是否有語法錯誤后,啟動 Nginx
注意:檢查語法錯誤這步驟可以省略,這里復習一下
/usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf -t /usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf -
查看是否啟動成功;
如果 master 和 worker 行程都啟動成功,則啟動成功;
若上面兩個缺少一個,則有可能是之前的配置出錯!可能是 nginx_mod 目錄沒有創建,或 nginx.conf 中配置資訊有問題!
ps -ef|grep nginx -
啟動成功后,則可通過 Nginx 訪問已經上傳到 FastDFS 上的檔案,
4.瀏覽器訪問測驗
-
再進行一次檔案上傳:在
/home/路徑下創建一個檔案,如t.text,隨便寫進去一些內容;上傳到 FastDFS 中,執行:
fdfs_test /etc/fdfs/client.conf upload t.text -
復制控制臺中回傳的示例檔案地址,進行訪問測驗即可(如果訪問時直接是下載檔案了,而不是顯示檔案內容;解決這個問題,可參考https://blog.csdn.net/qq_21457601/article/details/51853248?utm_source=blogxgwz3;其實問題不大,目的已經達到了,即使是直接下載了檔案,訪問測驗也是成功的)
http://192.168.154.129/group1/M00/00/00/wKiagGJURUuAMfHuAAAAHUAYZwU38.text
訪問流程
訪問流程/擴展模塊執行流程圖:

FastDFS 在普通 Java 專案中開發示例
在實際專案開發,FastDFS 提供的主要功能
- upload:上傳檔案
- download:下載檔案
- delete:洗掉檔案
FastDFS 檔案系統的 Java 客戶端
- FastDFS 檔案系統 Java 客戶端是指采用 Java 語言撰寫的一套程式,專門用來訪問 fastDFS 檔案系統,其實就是一個 jar 包,
- 它并沒有添加到 maven 的中央倉庫中,我們要使用,需要手動下載源代碼,編譯到自己的本地 maven 倉庫,【現在中央倉庫好像有了?自己看著選擇吧,可以用自己編譯的,也可以直接使用中央倉庫的】
- 下載地址:https://github.com/happyfish100/fastdfs(其實之前準備資源,已經讓下載過)
將 FastDFS 檔案系統 Java 客戶端編譯到本地 maven 倉庫步驟:
-
下載 FastDFS 客戶端源代碼 fastdfs-client-java-1.28.zip,解壓縮;
-
進入解壓縮的根目錄,在檔案路徑地址欄輸入 cmd 命令,進入 dos 視窗,輸入
mvn clean install命令,即可將其編譯到自己的本地 maven 倉庫中,在專案中配置其依賴后可直接使用,[INFO] Installing C:\Users\linwe\Downloads\fastdfs-client-java-1.28\pom.xml to D:\Java\maven\repository\org\csource\fastdfs-client-java\1.28-SNAPSHOT\fastdfs-client-java-1.28-SNAPSHOT.pom [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
注意:當在專案 pom 中引入該 maven 依賴時,若無法識別出來,則可以在 IDEA 中設定更新下本地倉庫,

Java 專案中使用 FastDFS(用的少,一般在web專案中用)
需求:在普通 Java 專案中使用 FastDFS 檔案系統實作對檔案的上傳,下載和洗掉操作
步驟示例:
-
創建普通 maven java 專案,不需要使用 archetype 原型模板
-
在 pom 中添加 FastDFS 客戶端依賴,并重繪 pom(可用自己編譯的,也可在中央倉庫中自己找)
<dependencies> <!--中央倉庫中的FastDFS依賴--> <!--<dependency>--> <!-- <groupId>com.github.tobato</groupId>--> <!-- <artifactId>fastdfs-client</artifactId>--> <!-- <version>1.27.2</version>--> <!--</dependency>--> <!--自己手動編譯的本地倉庫中FastDFS依賴--> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.28-SNAPSHOT</version> </dependency> </dependencies> -
在 resources 下創建一個 fastdfs.conf 檔案,配置 tracker 跟蹤器服務,配置自己的 IP
tracker_server=192.168.154.129:22122 -
此處直接創建并將相關方法封裝為工具類,改引數進行測驗呼叫
public class FastDFSUtil { public static void main(String[] args) { upload(); // download(); // delete(); } /** * 檔案上傳 */ public static void upload() { try { //讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中 ClientGlobal.init("fastdfs.conf"); // 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件 TrackerClient tc = new TrackerClient(); // 通過tracker客戶端物件獲取tracker和storage的服務端物件 TrackerServer ts = tc.getTrackerServer(); StorageServer ss = tc.getStoreStorage(ts); // 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料 StorageClient sc = new StorageClient(ts, ss); /** * 檔案上傳 * 引數1:需上傳檔案的絕對路徑 * 引數2:檔案擴展名 * 引數3:檔案的屬性檔案(通常不用上傳) * 回傳值:回傳一個String陣列,此資料非常重要,必須妥善管理,建議存入資料庫 * 陣列中第一個元素為檔案所在組名 * 陣列中第二個元素為檔案所在遠程路徑名 */ String[] result = sc.upload_file("D:/image/love.png", "png", null); for (String str : result) { System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } } /** * 檔案下載 */ public static void download() { try { //讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中 ClientGlobal.init("fastdfs.conf"); // 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件 TrackerClient tc = new TrackerClient(); // 通過tracker客戶端物件獲取tracker和storage的服務端物件 TrackerServer ts = tc.getTrackerServer(); StorageServer ss = tc.getStoreStorage(ts); // 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料 StorageClient sc = new StorageClient(ts, ss); /** * 檔案下載 * 引數1:需下載檔案的組名 * 引數2:需下載檔案的遠程檔案名 * 引數3:需要保存的本地檔案名(絕對路徑+檔案名) * 回傳值:回傳0則下載成功;其他值,則下載失敗 */ String groupName = "group1"; String remoteFileName = "M00/00/00/wKiagWJU6gyEWTbdAAAAAD_4r6Y944.png"; String localFileName = "D:/temp/a.png"; int ret = sc.download_file(groupName, remoteFileName, localFileName); System.out.println("download========> " + ret); } catch (IOException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } } /** * 檔案洗掉 */ p static void delete() { try { //讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中 ClientGlobal.init("fastdfs.conf"); // 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件 TrackerClient tc = new TrackerClient(); // 通過tracker客戶端物件獲取tracker和storage的服務端物件 TrackerServer ts = tc.getTrackerServer(); StorageServer ss = tc.getStoreStorage(ts); // 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料 StorageClient sc = new StorageClient(ts, ss); /** * 檔案洗掉 * 引數1:需洗掉檔案的組名 * 引數2:需洗掉檔案的遠程檔案名 * 回傳值:回傳0則洗掉成功;其他值,則洗掉失敗 */ String groupName = "group1"; String remoteFileName = "M00/00/00/wKiagWJU6gyEWTbdAAAAAD_4r6Y944.png"; int ret = sc.delete_file(groupName, remoteFileName); System.out.println("delete========> " + ret); } catch (IOException e) { e.printStackTrace(); } catch (MyException e) { e.printStackTrace(); } } } -
在瀏覽器中輸入訪問地址進行資源訪問測驗的時候注意下地址中資源拼接方式:
上傳成功回傳String陣列中兩個引數: group1 M00/00/00/wKiagWJU-t-EJfOFAAAAAD_4r6Y931.png 則訪問地址格式為:ip/group1/M00/00/00/wKiagWJU-t-EJfOFAAAAAD_4r6Y931.png 即: 192.168.154.129/group1/M00/00/00/wKiagWJU-t-EJfOFAAAAAD_4r6Y931.png
FastDFS 在 web 專案中開發示例
需求:對專案進行管理,在 WEB 專案中實作對檔案的上傳下載和洗掉操作,
流程分析:將檔案從本地上傳到 tomcat 中,在 tomcat 中拿到檔案流,將檔案流傳到 FastDFS 中,并將上傳回傳的資料存入資料庫中,
步驟:
1.資料庫環境搭建
-
創建 fastdfs 資料庫
-
新建查詢,執行下列命令,創建 creditor_info 表
示例表中:只有 id、group_name、remote_file_path、old_file_name、file_size、file_type 這幾個是重要欄位!
-- ---------------------------- -- Table structure for creditor_info -- ---------------------------- DROP TABLE IF EXISTS `creditor_info`; CREATE TABLE `creditor_info` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `real_name` varchar(35) DEFAULT NULL COMMENT '債權借款人姓名', `id_card` varchar(18) DEFAULT NULL COMMENT '債權借款人身份證', `address` varchar(150) DEFAULT NULL COMMENT '債權借款人地址', `sex` int(1) DEFAULT NULL COMMENT '1男2女', `phone` varchar(11) DEFAULT NULL COMMENT '債權借款人電話', `money` decimal(10,2) DEFAULT NULL COMMENT '債權借款人借款金額', `group_name` varchar(10) DEFAULT NULL COMMENT '債權合同所在組', `remote_file_path` varchar(150) DEFAULT NULL COMMENT '債權合同所在路徑', `old_file_name` varchar(255) DEFAULT NULL COMMENT '檔案上傳前的名字,用于下載檔案時指定默認檔案名使用', `file_size` bigint(20) DEFAULT NULL COMMENT '檔案大小,用于下載檔案啊時提供下載進度', `file_type` varchar(255) DEFAULT NULL COMMENT '檔案型別,用于顯示與檔案型別相同的圖示,作用不是很大', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; -- ---------------------------- -- Records of creditor_info -- ---------------------------- INSERT INTO `creditor_info` VALUES ('1', '張三', '123412341', '北京', '1', '23412341', '12433.00', '1', '1', '1', '1', '1'); INSERT INTO `creditor_info` VALUES ('2', '李四', '132414123', '上海', '0', '12344312', '21343.00', null, null, null, null, null); -
此處用的是 Linux 中的 mysql:用戶名 root,密碼 123
2.Web 專案環境搭建
-
創建 Spring Boot 專案,選擇 Spring Boot DevTools(熱部署工具)、Spring Web、Thymeleaf、MySQL、MyBatis 依賴;
注意:如果組態檔中使用的是低版本的 mysql 驅動配置,pom 中的 mysql 需要添加下低版本的版本號對應;
-
配置 application.properties
# 配置資料庫連接資訊 注意mysql新舊版本配置不同(如果用的低版本的驅動,pom里需要將mysql也指定下使用低版本的版本號) spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.154.129:3306/fastdfs?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123 # 開發階段,關閉thymeleaf的快取,不然無法看到實時頁面 spring.thymeleaf.cache=false # 去掉html5的語法驗證(thymeleaf對html的標簽約束非常嚴格,所有的標簽必須有開有閉,比如<br></br>或者<br/>是可以的,但是<br>會報錯, # 配置spring.thymeleaf.mode=LEGACYHTML5 目的就是為了解決這個問題,可以使頁面松校驗,) spring.thymeleaf.mode=LEGACYHTML5 #配置mapper檔案路徑 mybatis.mapper-locations=classpath:mapper/*.xml #開啟日志 #mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl #檔案上傳大小參考配置 #設定SpringMVC允許上傳的單個檔案大小,默認為1MB #spring.servlet.multipart.max-file-size=1MB #設定SpringMVC表單請求中允許上傳檔案的總大小,默認為10MB #spring.servlet.multipart.max-request-size=10MB -
在 templates 下創建 creditors.html 測驗頁面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 1111111111111111111 </body> </html> -
創建控制器類
@Controller public class CreditorInfoController { @RequestMapping("/") public String creditors() { return "creditors"; } } -
運行主啟動類,訪問測驗
localhost:8080/
3.使用mybatis生成器(逆向工程生成代碼)
PS:使用 mybatis 自動代碼生成器,可自動生成 model 物體類, dao 介面以及 mapper 映射檔案,
此處使用 mapper 檔案和 dao 介面分開管理的方式,
-
在 pom 的 plugins 標簽下添加 mybatis 自動代碼生成插件
<!--mybatis自動代碼生成插件--> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.6</version> <configuration> <!--組態檔的位置:在專案的根目錄下,和src平級--> <configurationFile>GeneratorMapper.xml</configurationFile> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> </plugin> -
在 pom 的 build 標簽下添加資源插件,處理資源檔案
<!-- 處理資源檔案 --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/**.*</include> </includes> </resource> </resources> -
在專案根目錄下創建
GeneratorMapper.xml檔案,其與 src 平級;將下列內容拷貝到檔案中;依照注釋修改配置,修改完后,點開右側 maven 快捷視窗,使用當前專案下 plugins 下 mybatis-genetate 下的 mybatis 自動代碼生成插件進行生成,<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- 指定連接資料庫的JDBC驅動包所在位置,指定到你本機的完整路徑 --> <classPathEntry location="D:\Java\tools\mysql-connector-java-8.0.28.jar"/> <!-- 配置table表資訊內容體,targetRuntime指定采用MyBatis3的版本 --> <context id="tables" targetRuntime="MyBatis3"> <!-- 抑制生成注釋,由于生成的注釋都是英文的,可以不讓它生成 --> <commentGenerator> <property name="suppressAllComments" value="https://www.cnblogs.com/luisblog/p/true" /> </commentGenerator> <!-- 配置資料庫連接資訊 --> <jdbcConnection driver connectionURL="jdbc:mysql://192.168.154.129:3306/fastdfs?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8" userId="root" password="123"> <!--MySQL 不支持 schema 或者 catalog 所以需要添加這個--> <!--設定原因參考:https://blog.csdn.net/qq_40233736/article/details/83314596--> <property name="nullCatalogMeansCurrent" value="https://www.cnblogs.com/luisblog/p/true" /> </jdbcConnection> <!-- 生成model類,targetPackage指定model類的包名, targetProject指定生成的model放在eclipse的哪個工程下面--> <javaModelGenerator targetPackage="com.luis.model" targetProject="D:\1a-Projects\test-projects\fastdfs\springboot-web-fastdfs\src\main\java"> <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/p/false" /> <property name="trimStrings" value="https://www.cnblogs.com/luisblog/p/false" /> </javaModelGenerator> <!-- 生成MyBatis的Mapper.xml檔案,targetPackage指定mapper.xml檔案的包名, targetProject指定生成的mapper.xml放在eclipse的哪個工程下面 --> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/p/false" /> </sqlMapGenerator> <!-- 生成MyBatis的Mapper介面類檔案,targetPackage指定Mapper介面類的包名, targetProject指定生成的Mapper介面放在eclipse的哪個工程下面 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.luis.dao" targetProject="src/main/java"> <property name="enableSubPackages" value="https://www.cnblogs.com/luisblog/p/false" /> </javaClientGenerator> <!-- 資料庫表名及對應的Java模型類名 --> <table tableName="creditor_info" domainObjectName="CreditorInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="b_bid_info" domainObjectName="BidInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="b_income_record" domainObjectName="IncomeRecord" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="b_recharge_record" domainObjectName="RechargeRecord" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="u_user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> <table tableName="u_finance_account" domainObjectName="FinanceAccount" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/> </context> </generatorConfiguration> -
application.properties 中添加 mybatis 相關配置
#配置mapper檔案路徑 mybatis.mapper-locations=classpath:mapper/*.xml #開啟日志 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl -
在主啟動類上添加包掃描注解
@MapperScan,掃描 dao 所在的包(防止后面忘記了,先加上)作用:掃描 dao 下的所有 mapper 類作為 Mapper 映射檔案,
@SpringBootApplication @MapperScan(basePackages = "com.luis.dao") public class SpringbootWebFastdfsApplication { public static void main(String[] args) { SpringApplication.run(SpringbootWebFastdfsApplication.class, args); } }
4.顯示資料串列
-
控制器類補充查詢功能
@Controller public class CreditorInfoController { @Resource private CreditorInfoServer creditorInfoServer; @RequestMapping("/") public String creditors(Model model) { List<CreditorInfo> creditorInfoList = creditorInfoServer.queryAll(); model.addAttribute("creditorInfoList", creditorInfoList); return "creditors"; } } -
補充 service 介面和實作類
public interface CreditorInfoServer { List<CreditorInfo> queryAll(); } @Service public class CreditorInfoServiceImpl implements CreditorInfoServer { @Resource private CreditorInfoMapper creditorInfoMapper; @Override public List<CreditorInfo> queryAll() { List<CreditorInfo> list = creditorInfoMapper.selectAll(); return list; } } -
dao 中添加全查方法
public interface CreditorInfoMapper { int deleteByPrimaryKey(Integer id); int insert(CreditorInfo record); int insertSelective(CreditorInfo record); CreditorInfo selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(CreditorInfo record); int updateByPrimaryKey(CreditorInfo record); // 新增的全查方法 List<CreditorInfo> selectAll(); } -
mapper 中補充全查的 SQL
<select id="selectAll" resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> from creditor_info </select> -
完善顯示資料的頁面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>test</title> </head> <body> <table> <tr> <th>序號</th> <th>姓名</th> <th>性別</th> <th>電話</th> <th>地址</th> <th></th> </tr> <tr th:each="creditorInfo:${creditorInfoList}"> <td th:text="${creditorInfo.id}">序號</td> <td th:text="${creditorInfo.realName}">姓名</td> <td th:text="${creditorInfo.sex == 1?'男':'女'}">性別</td> <td th:text="${creditorInfo.phone}">電話</th> <td th:text="${creditorInfo.address}">地址</td> <td> <span th:if="${creditorInfo.remoteFilePath == null || creditorInfo.remoteFilePath == ''}"> <a th:href="https://www.cnblogs.com/luisblog/p/@{|/upload/${creditorInfo.id}|}">上傳</a> </span> <span th:if="${creditorInfo.remoteFilePath != null && creditorInfo.remoteFilePath != ''}"> <a th:href="https://www.cnblogs.com/luisblog/p/@{|/download|}">下載</a> <a th:href="https://www.cnblogs.com/luisblog/p/@{|/delete|}">洗掉</a> </span> </td> </tr> </table> </body> </html> -
運行主啟動類,測驗

5.Web 中操作 FastDFS 完成上傳
6.Web 中操作 FastDFS 完成下載
7.Web 中操作 FastDFS 完成洗掉
由于操作不好記錄,以下相關實作提供相關實作參考:
相關頁面參考:
creditors.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>creditors.html</title>
</head>
<body>
<table>
<tr>
<th>序號</th>
<th>姓名</th>
<th>性別</th>
<th>電話</th>
<th>地址</th>
<th></th>
</tr>
<tr th:each="creditorInfo:${creditorInfoList}">
<td th:text="${creditorInfo.id}">序號</td>
<td th:text="${creditorInfo.realName}">姓名</td>
<td th:text="${creditorInfo.sex == 1?'男':'女'}">性別</td>
<td th:text="${creditorInfo.phone}">電話</th>
<td th:text="${creditorInfo.address}">地址</td>
<td>
<span th:if="${creditorInfo.remoteFilePath == null || creditorInfo.remoteFilePath == ''}">
<a th:href="https://www.cnblogs.com/luisblog/p/@{|/upload/${creditorInfo.id}|}">上傳</a>
</span>
<span th:if="${creditorInfo.remoteFilePath != null && creditorInfo.remoteFilePath != ''}">
<a th:href="https://www.cnblogs.com/luisblog/p/@{|/download/${creditorInfo.id}|}">下載</a>
<a th:href="https://www.cnblogs.com/luisblog/p/@{|/delete/${creditorInfo.id}|}">洗掉</a>
</span>
</td>
</tr>
</table>
</body>
</html>
upload.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>upload.html</title>
</head>
<body>
<!-- 上傳檔案的表單,method必須為post,并且必須指定enctype屬性為multipart/form-data -->
<!-- enctype="multipart/form-data" 簡單說明:讓表單以二進制的形式傳遞資料,支持流檔案型別 -->
<form th:action="@{|/upload|}" target="curPage" method="post" enctype="multipart/form-data">
姓名:<span th:text="${creditorInfo.realName}"></span><br/>
性別:<span th:text="${creditorInfo.sex==1?'男':'女'}"></span><br/>
電話:<span th:text="${creditorInfo.phone}"></span><br/>
地址:<span th:text="${creditorInfo.address}"></span><br/>
檔案:<input type="file" name="myFile" /><br/>
<input type="hidden" name="id" th:value="https://www.cnblogs.com/luisblog/p/${creditorInfo.id}" /><br/>
<input type="submit" value="https://www.cnblogs.com/luisblog/p/上傳檔案"><br/>
</form>
<!-- 嵌入式框架框架 -->
<iframe name="curPage" style="display: none"></iframe>
</body>
</html>
success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript">
if (confirm("[[${msg}]]")) {
window.top.location.href = "https://www.cnblogs.com/luisblog/p/[[${url}]]";
}
</script>
</head>
<body>
</body>
</html>
工具類參考:
public class FastDFSUtil {
private FastDFSUtil() {
}
/**
* 檔案上傳
*
* @param fileBuff 上傳檔案的位元組陣列
* @param fileExtName 上傳檔案的擴展名
* @return String陣列
* 陣列中第一個元素為檔案所在組名
* 陣列中第二個元素為檔案所在遠程路徑名
*/
public static String[] upload(byte[] fileBuff, String fileExtName) {
try {
//讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中
ClientGlobal.init("fastdfs.conf");
// 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件
TrackerClient tc = new TrackerClient();
// 通過tracker客戶端物件獲取tracker和storage的服務端物件
TrackerServer ts = tc.getTrackerServer();
StorageServer ss = tc.getStoreStorage(ts);
// 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料
StorageClient sc = new StorageClient(ts, ss);
/**
* 檔案上傳
* 引數1:需上傳檔案的位元組陣列
* 引數2:檔案擴展名
* 引數3:檔案的屬性檔案(通常不用上傳)
* 回傳值:回傳一個String陣列,此資料非常重要,必須妥善管理,建議存入資料庫
* 陣列中第一個元素為檔案所在組名
* 陣列中第二個元素為檔案所在遠程路徑名
*/
return sc.upload_file(fileBuff, fileExtName, null);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return null;
}
/**
* 檔案下載
*
* @param groupName 需下載檔案的組名
* @param remoteFileName 需下載檔案的遠程檔案名
* @return byte[] 需下載檔案的位元組陣列
*/
public static byte[] download(String groupName, String remoteFileName) {
try {
//讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中
ClientGlobal.init("fastdfs.conf");
// 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件
TrackerClient tc = new TrackerClient();
// 通過tracker客戶端物件獲取tracker和storage的服務端物件
TrackerServer ts = tc.getTrackerServer();
StorageServer ss = tc.getStoreStorage(ts);
// 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料
StorageClient sc = new StorageClient(ts, ss);
return sc.download_file(groupName, remoteFileName);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
return null;
}
/**
* 檔案洗掉
* @param groupName 需洗掉檔案的組名
* @param remoteFileName 需洗掉檔案的遠程檔案名
*/
public static void delete(String groupName, String remoteFileName) {
try {
//讀取FastDFS組態檔,用于將所有的tracker的地址讀取到記憶體中
ClientGlobal.init("fastdfs.conf");
// 使用無參構造方式創建tracker客戶端物件(配合組態檔使用),用于獲取tracker和storage的服務端物件
TrackerClient tc = new TrackerClient();
// 通過tracker客戶端物件獲取tracker和storage的服務端物件
TrackerServer ts = tc.getTrackerServer();
StorageServer ss = tc.getStoreStorage(ts);
// 通過tracker和storage的服務端物件創建Storage客戶端物件,來操作資料
StorageClient sc = new StorageClient(ts, ss);
sc.delete_file(groupName, remoteFileName);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
}
}
控制器類參考:
@Controller
public class CreditorInfoController {
@Resource
private CreditorInfoServer creditorInfoServer;
@RequestMapping("/")
public String creditors(Model model) {
List<CreditorInfo> creditorInfoList = creditorInfoServer.queryAll();
model.addAttribute("creditorInfoList", creditorInfoList);
return "creditors";
}
@GetMapping("/upload/{id}")
public String toUpload(@PathVariable Integer id, Model model) {
CreditorInfo creditorInfo = creditorInfoServer.findById(id);
model.addAttribute("creditorInfo", creditorInfo);
return "upload";
}
/**
* 檔案上傳
* 引數MultipartFile:為Spring提供的一個類,專門用于封裝請求中的檔案資料,
* 其屬性名必須與表單中檔案域的名字完全相同!否則無法獲取檔案資料!
*/
@PostMapping("/upload")
public String upload(Integer id, MultipartFile myFile, Model model) throws IOException {
// System.out.println(myFile.getBytes()); // 獲取檔案對應位元組陣列
// System.out.println(myFile.getContentType()); // 獲取檔案型別
// System.out.println(myFile.getInputStream()); // 獲取檔案對應的輸入流
// System.out.println(myFile.getName()); // 獲取表單元素名
// System.out.println(myFile.getOriginalFilename()); // 獲取文件名
// System.out.println(myFile.getSize()); // 獲取檔案大小
// System.out.println(myFile.isEmpty()); //判斷檔案是否為空;檔案沒有上傳或檔案大小為0,這個值都是true
// 獲取上傳檔案對應的位元組陣列
byte[] fileBuff = myFile.getBytes();
// 獲取上傳檔案的檔案名
String fileName = myFile.getOriginalFilename();
// 獲取上傳檔案的擴展名
// #TODO 可能會出現問題,因為有的檔案有可能沒有擴展名,所以必要時需要做邏輯控制
String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
Long fileSize = myFile.getSize(); // 檔案大小
String fileType = myFile.getContentType(); // 檔案型別
// ================進行檔案上傳========上傳到FastDFS檔案系統中=============
String[] result = FastDFSUtil.upload(fileBuff, fileExtName);
CreditorInfo creditorInfo = new CreditorInfo();
creditorInfo.setId(id); // id
creditorInfo.setGroupName(result[0]); // 組名
creditorInfo.setRemoteFilePath(result[1]); // 遠程檔案地址
creditorInfo.setOldFileName(fileName); // 檔案名
creditorInfo.setFileSize(fileSize); // 檔案大小
creditorInfo.setFileType(fileType); // 檔案型別
// ==========更新資料庫資訊==========
creditorInfoServer.updateFileInfo(creditorInfo);
model.addAttribute("msg", "上傳成功,是否回傳串列頁面?");
model.addAttribute("url", "/");
return "success";
}
/**
* 檔案下載
* @param id 需要下載的檔案主鍵
* @return ResponseEntity 表示一個回應的物體,這個類是Spring提供的一個類,是Spring回應資料時的一個物件,
* 這個物件有包含著回應時的編碼如404 202 等,以及回應的頭檔案資訊,以及回應時的具體資料;
* 這個物件可以是一段html代碼,也可是是一段JS,也可以是一段普通字串,也可以是一個檔案的流
*/
@RequestMapping("/download/{id}")
public ResponseEntity<byte[]> download(@PathVariable Integer id) {
// 獲取回應資料(即下載后成功回傳的位元組陣列)
CreditorInfo info = creditorInfoServer.findById(id);
String groupName = info.getGroupName();
String remoteFilePath = info.getRemoteFilePath();
byte[] buffFile = FastDFSUtil.download(groupName, remoteFilePath);
// 設定回應時的頭檔案資訊
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 設定回應型別為檔案型別
headers.setContentLength(info.getFileSize()); // 設定回應時的檔案大小,用于提供下載進度顯示使用
// 設定下載時的默認檔案名
headers.setContentDispositionFormData("attachment", info.getOldFileName());
/**
* 創建回應物體物件,Spring會將這個物件回傳給瀏覽器,作為回應資料;(我們需要填充資料)
* 引數1:回應時的具體資料
* 引數2:回應時的頭檔案資訊
* 引數3:回應時的狀態碼
*/
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffFile, headers, HttpStatus.OK);
return responseEntity;
}
/**
* 檔案洗掉
* 檔案洗掉操作選擇在業務層進行,因為需要先查資料,才能進行洗掉,減少方法呼叫,
* @param id
* @return
*/
@RequestMapping("/delete/{id}")
public String delete(@PathVariable Integer id) {
creditorInfoServer.deleteFileById(id);
return "redirect:/";
}
}
service 介面實作類參考:
@Service
public class CreditorInfoServiceImpl implements CreditorInfoServer {
@Resource
private CreditorInfoMapper creditorInfoMapper;
@Override
public List<CreditorInfo> queryAll() {
List<CreditorInfo> list = creditorInfoMapper.selectAll();
return list;
}
@Override
public CreditorInfo findById(Integer id) {
CreditorInfo creditorInfo = creditorInfoMapper.selectByPrimaryKey(id);
return creditorInfo;
}
@Override
public int updateFileInfo(CreditorInfo creditorInfo) {
int ret = creditorInfoMapper.updateByPrimaryKeySelective(creditorInfo);
return ret;
}
@Override
public void deleteFileById(Integer id) {
CreditorInfo creditorInfo = creditorInfoMapper.selectByPrimaryKey(id);
String groupName = creditorInfo.getGroupName();
String remoteFilePath = creditorInfo.getRemoteFilePath();
// 先洗掉遠程檔案
FastDFSUtil.delete(groupName, remoteFilePath);
// 再修改資料庫檔案資料
creditorInfo.setGroupName("");
creditorInfo.setRemoteFilePath("");
creditorInfo.setOldFileName("");
creditorInfo.setFileSize(0L);
creditorInfo.setFileType("");
creditorInfoMapper.updateByPrimaryKeySelective(creditorInfo);
}
}
gitee 上完整示例專案參考:
Web 中操作 FastDFS 完成上傳,下載,洗掉相關步驟,參考下列完整的示例專案:
https://gitee.com/lw2gitee/springboot-web-fastdfs
可克隆下來,在本地查看實作流程以及步驟,
FastDFS 分布式檔案系統集群
其實之前做的集群都算是偽集群,因為之前都是在一臺機器上搭建的集群服務;
下面示例的 FastDFS 分布式檔案系統集群是在七個虛擬機中進行搭建,相當于七臺機器,是真正的集群架構,
架構圖

- 同一個組中資料相同,機器之間有資料備份,建議同一個組中所有機器性能和配置要相同
- 不同組中存的資料不同
- 如果有4臺機器存盤資料,每個機器有1G存盤空間,那么我們檔案的存盤上限是2G(因為每臺機器對應一個備份機器)
環境搭建步驟
PS:建議如果實際操作,不要直接按照下面步驟來!其中有很多細節需要注意,建議跟著視頻操作!
視頻鏈接:https://www.bilibili.com/video/BV1ta4y1v7Kw?p=25
FastDFS分布式檔案系統集群環境搭建-操作步驟手冊
搭建一個FastDFS分布式檔案系統集群,推薦至少部署6個服務器節點;
================================搭建FastDFS的集群==============================
第一步:安裝6個迷你版的Linux,迷你版Linux沒有圖形界面,占用磁盤及資源小,企業里面使用的Linux都是沒有圖形界面的Linux;
第二步:由于迷你版Linux缺少一些常用的工具庫,操作起來不方便,推薦安裝如下的工具庫:(不要分別安裝,一次全安裝)
1、安裝lrzsz, yum install lrzsz -y
2、安裝wget, yum install wget -y
4、安裝vim, yum install vim -y
5、安裝unzip,yum install unzip -y
6、安裝ifconfig,yum install net-tools -y
一次性全部安裝:
yum install lrzsz wget vim unzip net-tools -y
7、安裝nginx及fastdfs需要的庫依賴:
yum install gcc perl openssl openssl-devel pcre pcre-devel zlib zlib-devel libevent libevent-devel -y
第三步 安裝fastdfs
1、 上傳fastdfs的安裝包和libfastcommon的安裝包
2、 解壓libfastcommon 安裝libfastcommon
3、 解壓fastdfs 安裝fastdfs
4、 拷貝fastdfs目錄中的http.conf和mime.types到/etc/fdfs 目錄中
注:6臺機器全部執行這些操作
第四步:部署兩個tracker server服務器,需要做的作業:
修改兩個tracker服務器的組態檔:
tracker.conf: 修改一個地方:
base_path=/opt/fastdfs/tracker #設定tracker的資料檔案和日志目錄(需預先創建)
啟動tracker服務器 fdfs_trackerd /etc/fdfs/tracker.conf
第五步 修改兩個組中的4臺storage中storage.conf檔案
第一組group1的第一個storage server(修改storage.conf組態檔):
group_name=group1 #組名,根據實際情況修改,值為 group1 或 group2
base_path=/opt/fastdfs/storage #設定storage的日志目錄(需預先創建)
store_path0=/opt/fastdfs/storage/files #存盤路徑
tracker_server=192.168.171.135:22122 #tracker服務器的IP地址以及埠號
tracker_server=192.168.171.136:22122
第二組group2的第一個storage server(修改storage.conf組態檔):
group_name=group2 #組名,根據實際情況修改,值為 group1 或 group2
base_path=/opt/fastdfs/storage #設定storage的日志目錄(需預先創建)
store_path0=/opt/fastdfs/storage/files #存盤路徑
tracker_server=192.168.171.135:22122 #tracker服務器的IP地址以及埠號
tracker_server=192.168.171.136:22122
啟動storage服務器
使用之前的Java代碼測驗FastDFS的6臺機器是否可以上傳檔案
注意:FastDFS默認是帶有負載均衡策略的可以在tracker的2臺機器中修改tracker.conf檔案
store_lookup=1
0 隨機存放策略
1 指定組
2 選擇磁盤空間的優先存放 默認值
修改后重啟服務
fdfs_trackerd /etc/fdfs/tracker.conf restart
======================使用Nginx進行負載均衡==============================
第六步 安裝 nginx ,使用nginx 對fastdfs 進行負載均衡
上傳 nginx-1.12.2.tar.gz以及 nginx的fastdfs擴展模塊安裝包fastdfs-nginx-module-master.zip
添加nginx的安裝依賴
yum install gcc openssl openssl-devel pcre pcre-devel zlib zlib-devel -y
解壓nginx
tar -zxvf nginx-1.12.2.tar.gz
解壓fastdfs擴展模塊
unzip fastdfs-nginx-module-master.zip
配置nginx的安裝資訊
2臺tracker服務器的配置資訊(不需要fastdfs模塊)
./configure --prefix=/usr/local/nginx_fdfs
4臺storage服務器其的配置資訊(需要使用fastdfs模塊)
./configure --prefix=/usr/local/nginx_fdfs --add-module=/root/fastdfs-nginx-module-master/src
編譯并安裝nginx
./make
./make install
4臺storage的服務器需要拷貝mod_fastdfs檔案
將/root/fastdfs-nginx-module-master/src目錄下的mod_fastdfs.conf檔案拷貝到 /etc/fdfs/目錄下,這樣才能正常啟動Nginx;
第七步 配置tracker 的兩臺機器的nginx
進入安裝目錄
cd /usr/local/nginx_fdfs
添加一個location 對請求進行攔截,配置一個正則規則 攔截fastdfs的檔案路徑, 并將請求轉發到其余的4臺storage服務器(修改 conf目錄下nginx.conf 檔案)
#nginx攔截請求路徑:
location ~ /group[1-9]/M0[0-9] {
proxy_pass http://fastdfs_group_server;
}
添加一個upstream 執行服務的IP為 另外的4臺stroage 的地址
#部署配置nginx負載均衡:
upstream fastdfs_group_server {
server 192.168.171.137:80;
server 192.168.171.138:80;
server 192.168.171.139:80;
server 192.168.171.140:80;
}
第八步 配置另外4臺storage的nginx添加http訪問的請求路徑攔截
進入安裝目錄
cd /usr/local/nginx_fdfs
添加一個location 對請求進行攔截,配置一個正則規則 攔截fastdfs的檔案路徑,使用fastdfs的nginx模塊轉發請求(修改 conf目錄下nginx.conf 檔案)
#nginx攔截請求路徑:
location ~ /group[1-9]/M0[0-9] {
ngx_fastdfs_module;
}
第九步 分別修改4臺storage服務器的mod_fasfdfs.conf檔案(/etc/fdfs/mod_fastdfs.conf)
#修改基本路徑,并在指定路徑創建對應檔案夾
base_path=/opt/fastdfs/nginx_mod #保存日志目錄
#指定兩臺tracker服務器的ip和埠
tracker_server=192.168.171.135:22122 #tracker服務器的IP地址以及埠號
tracker_server=192.168.171.136:22122
#指定storage服務器的埠號
storage_server_port=23000 #通常情況不需要修改
#指定當前的storage服務器所屬的組名 (當前案例03和04為group1 05和06為group2)
group_name=group1 #當前服務器的group名
#指定url路徑中是否包含組名 (當前案例url包含組名)
url_have_group_name=true #檔案url中是否有group名
store_path_count=1 #存盤路徑個數,需要和store_path個數匹配(一般不用改)
store_path0=/opt/fastdfs/storage/files #存盤路徑
#指定組個數,根據實際配置決定,(當前案例擁有2個組group1和group2)
group_count = 2 #設定組的個數
在末尾增加2個組的具體資訊:
[group1]
group_name=group1
storage_server_port=23000
store_path_count=1
store_path0=/opt/fastdfs/storage/files
[group2]
group_name=group2
storage_server_port=23000
store_path_count=1
store_path0=/opt/fastdfs/storage/files
第一個組的第二個storage按照相同的步驟操作;
另外一個組的兩個storage也按照相同的步驟操作;
#測驗nginx的組態檔是否正確(測驗全部6臺服務器)
/usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf -t
#啟動nginx服務器(全部6臺服務器)
/usr/local/nginx_fdfs/sbin/nginx -c /usr/local/nginx_fdfs/conf/nginx.conf
測驗:使用瀏覽器分別訪問 6臺 服務器中的fastdfs檔案
第十步:部署前端用戶訪問入口服務器,即訪問192.168.230.128上的Nginx,該Nginx負載均衡到后端2個tracker server;
配置nginx.conf檔案
location ~ /group[1-9]/M0[0-9] {
proxy_pass http://fastdfs_group_server;
}
添加一個upstream 執行服務的IP為 2臺tracker 的地址
#部署配置nginx負載均衡:
upstream fastdfs_group_server {
server 192.168.171.135:80;
server 192.168.171.136:80;
}
測驗:使用瀏覽器訪問128(唯一入口的nginx服務器)服務器中的fastdfs檔案
注意:由于之前128的nginx中可能擁有靜態資源攔截會導致訪問不到檔案,這時可以注釋或洗掉這些靜態資源攔截
==============================補充資料============================================
最后,為了讓服務能正常連接tracker,請關閉所有機器的防火墻:
systemctl status firewalld 查看防火墻狀態
systemctl disable firewalld 禁用開機啟動防火墻
systemctl stop firewalld 停止防火墻
systemctl restart network 重啟網路
systemctl start network 啟動網路
systemctl stop network 停止網路
可能安裝的linux(無圖形的)沒有開啟網卡服務,可以修改/etc/sysconfig/network-scripts 下的網卡組態檔設定 ONBOOT=yse
表示開機啟動網卡,然后啟動網路服務即可
Keepalived當主nginx出現故障后會自動切換到備用nginx服務器的一款軟體 通常由運維人員進行使用
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/525855.html
標籤:Java
上一篇:golang中的錯誤處理
