主頁 > 軟體設計 > 分布式檔案系統----FastDFS

分布式檔案系統----FastDFS

2021-08-05 07:17:34 軟體設計

FastDFS

  • 1、分布式檔案系統
    • 1.1 FastDFS簡介
    • 1.2 FastDFS整體架構
    • 1.3 FastDFS的存盤策略
    • 1.4 FastDFS的上傳程序
    • 1.5 FastDFS的檔案同步
    • 1.6 FastDFS的檔案下載
  • 2、FastDFS環境搭建
    • 2.1 FastDFS安裝
      • 2.1.1 **安裝前的準備**
        • (1) 檢查Linux上是否安裝了 gcc、libevent、libevent-devel
        • (2) 如果沒有安裝,則需進行安裝
      • 2.1.2 **安裝 libfastcommon 庫**
        • (1) 將下載好的libfastcommon檔案上傳到Linux(/home/)
        • (2) 解壓下載下來的tar.gz壓縮包到當前目錄
        • (3) 切換到解壓后的libfastcommon目錄
        • (4) 執行make腳本進行編譯
        • (5) 執行make install進行安裝
      • 2.1.3 安裝FastDFS
        • (1) 將下載好的FastDFS檔案上傳到Linux(/home/)
        • (2) 解壓下載下來的tar.gz壓縮包到當前目錄
        • (3) 切換到解壓后FastDFS的目錄
        • (4) 執行make腳本進行編譯
        • (5) 執行make install進行安裝
        • (6) 查看安裝后的效果
          • A、 查看FastDFS相關的可執行程式
          • B、 查看FastDFS的組態檔
        • (7) 另外注意需要把解壓后的fastdfs-5.11/conf目錄下的兩個檔案拷貝到/etc/fdfs/ ,否則后續會有很多奇怪問題不好解決
    • 2.2 FastDFS組態檔詳解
      • 1. 去掉/etc/fdfs/目錄下FastDFS組態檔的后綴名
      • 2. 修改tracker.conf檔案
      • 3. 修改storage.conf檔案
      • 4. 在Linux服務器上創建上面指定的目錄
      • 5. 然后啟動FastDFS
    • 2.3 FastDFS啟動
      • 1. 啟動FastDFS的tracker服務
      • 2. 啟動FastDFS的storage服務
      • 3. 查看啟動行程
      • 4. 查看storage是否已經注冊到了tracker下
      • 5. 首次啟動storage后,會在配置的路徑下創建存盤檔案的目錄
    • 2.4 FastDFS重啟與FastDFS關閉
      • 2.4.1 FastDFS重啟
      • 2.4.2 FastDFS關閉
    • 2.5 FastDFS測驗
      • 2.5.1 測驗檔案上傳
      • 2.5.2 測驗檔案洗掉
  • 3、分布式檔案系統FastDFS的HTTP訪問
    • 3.1 前期準備作業
    • 3.2 安裝Nginx并且添加fastDFS模塊
      • 1. 將Nginx的tar包上傳到Linux上
      • 2. 解壓上傳的Nginx檔案
      • 3. 切換至解壓后的Nginx主目錄,執行配置操作
      • 4. 執行命令進行編譯
      • 5. 執行命令進行安裝
      • 6. 以上安裝Nginx的FastDFS擴展模塊注意事項
      • 7. FastDFS擴展模塊執行流程
    • 3.3 FastDFS的Nginx訪問配置
      • 1. 修改mod_fastdfs.conf組態檔
      • 2. 在/opt/fastdfs/目錄下創建nginx_mod目錄
      • 3. 配置Nginx的組態檔
    • 3.4 FastDFS的Nginx訪問啟動與測驗
      • 1. 啟動帶有Fastdfs模塊的Nginx
      • 2. 重啟或啟動FastDFS服務行程
      • 3. 上傳一個檔案進行測驗驗證
      • 4. 在瀏覽器訪問上傳的檔案
      • 5. 擴展
  • 4、FastDFS分布式檔案系統Java客戶端
    • 4.1 FastDFS檔案系統的Java客戶端
      • 1. 下載官方的源代碼
      • 2. 解壓
      • 3. 采用maven命令編譯成jar安裝到本地maven庫
      • 4. 在Java程式中使用它提供的API來訪問FastDFS檔案系統
    • 4.2 FastDFS檔案上傳功能實作
      • 4.2.1 **需求**
      • 4.2.2 實作步驟
    • 4.3 FastDFS檔案上傳功能封裝
      • 4.3.1 需求
      • 4.3.2 實作步驟
  • 5、FastDFS在web專案中的應用
    • 1. 資料庫環境搭建
    • ⒉ 開發環境搭建
  • 6、FastDFS分布式檔案系統集群
    • 6.1 架構圖
    • 6.2 環境搭建步驟
      • 1. 安裝6個迷你版的Linux
      • 2. 在Xshell中創建6個連接,分別連向不同的Linux
      • 3. 為迷你版的Linux安裝常用工具庫
      • 4. 按照課件上安裝FastDFS的步驟在6個服務器節點安裝FastDFS
      • 5. 配置兩個tracker server服務器
      • 6. 配置四個storage server服務器
      • 7. 部署Http訪問FastDFS上的檔案

1、分布式檔案系統

1.1 FastDFS簡介

  • 分布式檔案系統 (Distributed File System) 是一個軟體/軟體服務器,這個軟體可以用來管理檔案,但這個軟體所管理的檔案通常不是在一個服務器節點上,而是在多個服務器節點上,這些服務器節點通過網路相連構成一個龐大的檔案存盤服務器集群,這些服務器都用于存盤檔案資源,通過分布式檔案系統來管理這些服務器上的檔案,

  • FastDFS 是一個開源的高性能分布式檔案系統(DFS), 它的主要功能包括:檔案存盤,檔案同步和檔案訪問,以及高容量和負載平衡,主要解決了海量資料存盤問題,特別適合以中小檔案(建議范圍:4KB < file_size <500MB)為載體的在線服務,

  • FastDFS是一個開源的輕量級分布式檔案系統,為互聯網應用量身定做,簡單、靈活、高效,采用C語言開發,由阿里巴巴開發并開源,

  • FastDFS對檔案進行管理,功能包括:檔案存盤、檔案同步、檔案訪問(檔案上傳、檔案下載、檔案洗掉)等,解決了大容量檔案存盤的問題,特別適合以檔案為載體的在線服務,如相冊網站、檔案網站、圖片網站、視頻網站等等,

  • FastDFS充分考慮了冗余備份、線性擴容等機制,并注重高可用、高性能等指標,使用FastDFS很容易搭建一套高性能的檔案服務器集群提供檔案上傳、下載等服務,

  • FastDFS 系統有三個角色:跟蹤服務器(Tracker Server)、存盤服務器(Storage Server)和客戶端(Client),

    Tracker Server:跟蹤服務器,主要做調度作業,起到均衡的作用;負責管理所有的 storage server和 group,每個 storage 在啟動后會連接 Tracker,告知自己所屬 group 等資訊,并保持周期性心跳,

    Storage Server:存盤服務器,主要提供容量和備份服務;以 group 為單位,每個 group 內可以有多臺 storage server,資料互為備份,

    Client:客戶端,上傳下載資料的服務器,也就是我們自己的專案所部署在的服務器,

在這里插入圖片描述

  • 常見的分布式檔案系統有:FastDFS、GFS、HDFS、Lustre 、Ceph 、GridFS 、mogileFS、TFS等,
    在這里插入圖片描述
    在這里插入圖片描述
    在這里插入圖片描述

1.2 FastDFS整體架構

FastDFS代碼托管在github上:https://github.com/happyfish100/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)都保存到存盤服務器磁盤上,完成檔案管理的所有功能:檔案存盤、檔案同步和提供檔案訪問等,

1.3 FastDFS的存盤策略

  • 為了支持大容量,存盤節點(服務器)采用了分卷(或分組)的組織方式,存盤系統由一個或多個卷組成,卷與卷之間的檔案是相互獨立的,所有卷的檔案容量累加就是整個存盤系統中的檔案容量,一個卷可以由一臺或多臺存盤服務器組成,一個卷下的存盤服務器中的檔案都是相同的,卷中的多臺存盤服務器起到了冗余備份和負載均衡的作用,

  • 在卷中增加服務器時,同步已有的檔案由系統自動完成,同步完成后,系統自動將新增服務器切換到線上提供服務,當存盤空間不足或即將耗盡時,可以動態添加卷,只需要增加一臺或多臺服務器,并將它們配置為一個新的卷,這樣就擴大了存盤系統的容量,

1.4 FastDFS的上傳程序

  • FastDFS向使用者提供基本檔案訪問介面,比如upload、download、append、delete等,以客戶端庫的方式提供給用戶使用,

  • Storage Server會定期的向Tracker Server發送自己的存盤資訊,當Tracker Server Cluster中的Tracker Server不止一個時,各個Tracker之間的關系是對等的,所以客戶端上傳時可以選擇任意一個Tracker,

  • 當Tracker收到客戶端上傳檔案的請求時,會為該檔案分配一個可以存盤檔案的group,當選定了group后就要決定給客戶端分配group中的哪一個storage server,當分配好storage server后,客戶端向storage發送寫檔案請求,storage將會為檔案分配一個資料存盤目錄,然后為檔案分配一個fileid,最后根據以上的資訊生成檔案名存盤檔案,
    在這里插入圖片描述

1.5 FastDFS的檔案同步

  • 寫檔案時,客戶端將檔案寫至group內一個storage server即認為寫檔案成功,storage server寫完檔案后,會由后臺執行緒將檔案同步至同group內其他的storage server,

  • 每個storage寫檔案后,同時會寫一份binlog,binlog里不包含檔案資料,只包含檔案名等元資訊,這份binlog用于后臺同步,storage會記錄向group內其他storage同步的進度,以便重啟后能接上次的進度繼續同步;進度以時間戳的方式進行記錄,所以最好能保證集群內所有server的時鐘保持同步,

  • storage的同步進度會作為元資料的一部分匯報到tracker上,tracke在選擇讀storage的時候會以同步進度作為參考,

1.6 FastDFS的檔案下載

  • 客戶端uploadfile成功后,會拿到一個storage生成的檔案名,接下來客戶端根據這個檔案名即可訪問到該檔案,

在這里插入圖片描述

  • 跟upload file一樣,在downloadfile時客戶端可以選擇任意tracker server,tracker發送download請求給某個tracker,必須帶上檔案名資訊,tracke從檔案名中決議出檔案的group、大小、創建時間等資訊,然后為該請求選擇一個storage用來服務讀請求,

2、FastDFS環境搭建

2.1 FastDFS安裝

2.1.1 安裝前的準備

(1) 檢查Linux上是否安裝了 gcc、libevent、libevent-devel

yum list installed | grep gcc

yum list installed | grep libevent

yum list installed | grep libevent-devel

(2) 如果沒有安裝,則需進行安裝

yum install gcc libevent libevent-devel –y

2.1.2 安裝 libfastcommon 庫

  • libfastcommon 庫是 FastDFS 檔案系統運行需要的公共 C 語言函式庫

注意:目前最新版本的v1.0.39和最新版的FastDFS5.11不兼容,所有我們這里使用的版本是v1.0.36 下載地址:https://github.com/happyfish100

(1) 將下載好的libfastcommon檔案上傳到Linux(/home/)

(2) 解壓下載下來的tar.gz壓縮包到當前目錄

tar -zxvf libfastcommon-1.0.36.tar.gz

(3) 切換到解壓后的libfastcommon目錄

cd libfastcommon-1.0.36

(4) 執行make腳本進行編譯

./make.sh

在這里插入圖片描述
注意: make編譯的時候如果報錯,需解決錯誤后再次進行make,通常發生錯誤是由于Linux缺少某些依賴庫導致,根據錯誤提示解決錯誤

(5) 執行make install進行安裝

./make.sh install

在這里插入圖片描述

2.1.3 安裝FastDFS

  • FastDFS沒有Windows版本,不能在Windows下使用,

  • FastDFS需要安裝部署在Linux環境下,我們這里使用的是fastdfs-5.11版本(201901)

  • 下載地址:https://github.com/happyfish100/fastdfs/archive/V5.11.tar.gz

(1) 將下載好的FastDFS檔案上傳到Linux(/home/)

(2) 解壓下載下來的tar.gz壓縮包到當前目錄

tar -zxvf fastdfs-5.11.tar.gz

(3) 切換到解壓后FastDFS的目錄

cd fastdfs-5.11

(4) 執行make腳本進行編譯

./make.sh

(5) 執行make install進行安裝

./make.sh install

在這里插入圖片描述

  • 所有編譯出來的檔案存放在/usr/bin目錄下

  • 所有組態檔存放在/etc/fdfs目錄下

(6) 查看安裝后的效果

A、 查看FastDFS相關的可執行程式
ll /usr/bin/fdfs*

在這里插入圖片描述

  • /usr/bin是Linux的環境變數,可通過echo $PATH查看
B、 查看FastDFS的組態檔
ll /etc/fdfs/

在這里插入圖片描述

(7) 另外注意需要把解壓后的fastdfs-5.11/conf目錄下的兩個檔案拷貝到/etc/fdfs/ ,否則后續會有很多奇怪問題不好解決

cp http.conf /etc/fdfs/

cp mime.types /etc/fdfs/

在這里插入圖片描述

2.2 FastDFS組態檔詳解

1. 去掉/etc/fdfs/目錄下FastDFS組態檔的后綴名

在這里插入圖片描述

2. 修改tracker.conf檔案

  • 默認指向的FastDFS作者余慶的目錄,因為在我們的機器上不存在,所有手動改一下
base_path=/opt/fastdfs/tracker #配置tracker存盤資料的目錄

在這里插入圖片描述

3. 修改storage.conf檔案

base_path=/opt/fastdfs/storage #storage存盤資料目錄

store_path0=/opt/fastdfs/storage/files #真正存放檔案的目錄

tracker_server=192.168.235.128:22122 #注冊當前存盤節點的跟蹤器地址

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

4. 在Linux服務器上創建上面指定的目錄

/opt/fastdfs/tracker

/opt/fastdfs/storage

/opt/fastdfs/storage/files

在這里插入圖片描述

5. 然后啟動FastDFS

2.3 FastDFS啟動

FastDFS服務啟動需要啟動兩個腳本:

1. 啟動FastDFS的tracker服務

在任意目錄下執行:fdfs_trackerd /etc/fdfs/tracker.conf
在這里插入圖片描述

2. 啟動FastDFS的storage服務

在任意目錄下執行:fdfs_storaged /etc/fdfs/storage.conf
在這里插入圖片描述

3. 查看啟動行程

在這里插入圖片描述
有啟動的執行命令即為啟動成功

4. 查看storage是否已經注冊到了tracker下

fdfs_monitor /etc/fdfs/storage.conf
在這里插入圖片描述

5. 首次啟動storage后,會在配置的路徑下創建存盤檔案的目錄

在這里插入圖片描述

2.4 FastDFS重啟與FastDFS關閉

2.4.1 FastDFS重啟

  • 重啟tracker
fdfs_trackerd /etc/fdfs/tracker.conf restart

在這里插入圖片描述

  • 重啟storage
fdfs_storaged /etc/fdfs/storage.conf restart

在這里插入圖片描述

2.4.2 FastDFS關閉

  • 關閉tracker執行命令
    在任意目錄下執行:fdfs_trackerd /etc/fdfs/tracker.conf stop
    在這里插入圖片描述
  • 關閉storage執行命令
    在任意目錄下執行:fdfs_storaged /etc/fdfs/storage.conf stop
    在這里插入圖片描述
    或者kill關閉fastdfs,但不建議在線上使用 kill -9 強制關閉,因為可能會導致檔案資訊不同步問題,

2.5 FastDFS測驗

FastDFS安裝完成之后,可以使用fdfs_test腳本測驗檔案上傳,

測驗之前,需要修改client.conf組態檔,修改兩個配置

base_path=/opt/fastdfs/client

tracker_server=192.168.179.128:22122

在這里插入圖片描述
在這里插入圖片描述

/opt/fastdfs/目錄下創建client
在這里插入圖片描述

2.5.1 測驗檔案上傳

  • 準備需要上傳的檔案
    在這里插入圖片描述
  • 執行上傳命令fdfs_test /etc/fdfs/client.conf upload /root/aa.txt
    在這里插入圖片描述
  • 切換到存盤目錄查看檔案上傳情況
    在這里插入圖片描述

FastDFS生成的檔案目錄結構及名稱示例
在這里插入圖片描述

2.5.2 測驗檔案洗掉

fdfs_delete_file /etc/fdfs/client.conf group1/要洗掉的檔案路徑

在這里插入圖片描述

注意
● 沒有搭建集群默認只有一個組group1

● 后綴名包含-m的為屬性檔案(meta)

● 在Linux中并沒有磁盤一說,是虛擬的

3、分布式檔案系統FastDFS的HTTP訪問

概述

  • 在檔案上傳的時候,上傳成功的資訊中有提示我們可以通過某個路徑去訪問上傳的檔案,但是我們直接訪問這個路徑,卻不可以,那么已經上傳到FastDFS檔案系統中的檔案,我們如何在瀏覽器中訪問呢?

  • FastDFS提供了一個Nginx擴展模塊,利用該模塊,我們可以通過Nginx訪問已經上傳到FastDFS上的檔案

3.1 前期準備作業

  1. 將Fastdfs的Nginx擴展模塊源代碼上傳到Linux上

  2. 解壓下載下來的fastdfs-nginx-module-master.zip 檔案

unzip fastdfs-nginx-module-master.zip

在這里插入圖片描述

3.2 安裝Nginx并且添加fastDFS模塊

因為這個模塊必須在Nginx的安裝的程序中才能添加,所有我們需要重新安裝一個nginx,為了和原來已安裝的Nginx進行區分,我們把新安裝的Nginx取名為nginx_fdfs

1. 將Nginx的tar包上傳到Linux上

2. 解壓上傳的Nginx檔案

在這里插入圖片描述

3. 切換至解壓后的Nginx主目錄,執行配置操作

cd nginx-1.14.2

./configure --prefix=/usr/local/nginx_fdfs --add-

module=/home/soft/fastdfs-nginx-module-master/src

? prefix是指定nginx安裝路徑

? add-module指定fastDFS的nginx模塊的源代碼路徑
在這里插入圖片描述

# 常見報錯問題
①/home/dfs/fastdfs-nginx-module-master/src/common.c:351:32: error: request for member ‘path’ in something not a structure or union
     g_fdfs_store_paths.paths[i].path);

解決方案:
原因:軟體不匹配!

# wget https://sourceforge.net/projects/fastdfs/files/FastDFS%20Nginx%20Module%20Source%20Code/fastdfs-nginx-module_v1.16.tar.gz
# tar -zxvf fastdfs-nginx-module_v1.16.tar.gz	


②/home/dfs/fastdfs-nginx-module/src/common.c:21:25: fatal error: fdfs_define.h: No such file or directory
 #include "fdfs_define.h"
 
解決方案:
原因:編譯安裝nginx的fastdfs插件的頭檔案沒有找到,由于編譯nginx時候系統會到/usr/local /include

編譯安裝fastdfs-nginx-module時則默認保存在了/usr/include目錄,
修復:ln -s /usr/include/fast* /usr/local/include/

③ fatal error: common_define.h: No such file or directory
解決方案:
原因:在安裝FastDFS的時候,其中的函式宣告、宏定義、函式原型被指到了 “ /usr/include/fastdfs /usr/include/fastcommon ” 目錄下

vi /home/dfs/fastdfs-nginx-module/src/config

ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/"
 
》》》
 
CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"

4. 執行命令進行編譯

make

5. 執行命令進行安裝

make install

6. 以上安裝Nginx的FastDFS擴展模塊注意事項

我們知道,Nginx的安裝需要Linux安裝相關的幾個庫,否則編譯會出現錯誤,這幾個庫分別是:

? gcc編譯器是否安裝

檢查是否安裝:yum list installed | grep gcc

執行安裝:yum install gcc -y

? openssl庫是否安裝

檢查是否安裝:yum list installed | grep openssl

執行安裝:yum install openssl openssl-devel -y

? pcre庫是否安裝

檢查是否安裝:yum list installed | grep pcre

執行安裝:yum install pcre pcre-devel -y

? zlib庫是否安裝

檢查是否安裝:yum list installed | grep zlib

執行安裝:yum install zlib zlib-devel -y

yum install gcc openssl openssl-devel pcre pcre-devel zlib zlib-devel –y

7. FastDFS擴展模塊執行流程

在這里插入圖片描述
在這里插入圖片描述

3.3 FastDFS的Nginx訪問配置

將/home/soft/fastdfs-nginx-module-master/src(自己實際存放Nginx擴展模塊的目錄)目錄下的mod_fastdfs.conf檔案拷貝到 /etc/fdfs/目錄下,這樣才能正常啟動Nginx

cp /home/soft/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/

在這里插入圖片描述

1. 修改mod_fastdfs.conf組態檔

base_path=/opt/fastdfs/nginx_mod

tracker_server=192.168.235.128:22122

url_have_group_name = true

store_path0=/opt/fastdfs/storage/files

2. 在/opt/fastdfs/目錄下創建nginx_mod目錄

在這里插入圖片描述

3. 配置Nginx的組態檔

#攔截請求路徑中包含 /group[1-9]/M0[0-9] 的請求,用 fastdfs的Nginx 模塊進行轉發
location ~ /group[1-9]/M0[0-9] {	
     ngx_fastdfs_module;  
}

在這里插入圖片描述
ngx_fastdfs_module; #這個指令不是Nginx本身提供的,是擴展模塊提供的,根據這個指令找到FastDFS提供的Nginx模塊組態檔,然后找到Tracker,最終找到Stroager,

3.4 FastDFS的Nginx訪問啟動與測驗

1. 啟動帶有Fastdfs模塊的Nginx

在這里插入圖片描述

2. 重啟或啟動FastDFS服務行程

fdfs_trackerd /etc/fdfs/tracker.conf restart

fdfs_storaged /etc/fdfs/storage.conf restart

在這里插入圖片描述

3. 上傳一個檔案進行測驗驗證

fdfs_test /etc/fdfs/client.conf upload /root/aa.txt

在這里插入圖片描述

4. 在瀏覽器訪問上傳的檔案

當遇到400錯誤,檢查配置/etc/fdfs/mod_fastdfs.conf

url_have_group_name=true

該配置表示訪問路徑中是否需要帶有group1,改為true表示路徑中需要有group1

5. 擴展

模擬大型網站用戶頭像的處理方式,上傳一張圖片,然后自己寫一個html頁面,src指向上傳的圖片,

4、FastDFS分布式檔案系統Java客戶端

在實際專案開發中,FastDFS提供的主要功能

● upload:上傳檔案

● download:下載檔案

● delete:洗掉檔案

4.1 FastDFS檔案系統的Java客戶端

FastDFS檔案系統Java客戶端是指采用Java語言撰寫的一套程式,專門用來訪問fastDFS檔案系統,其實就是一個jar包,

注意:大家如果能連上 mvnrepository上搜索到的用友云提供的fastdfs-client,那大家就下載那個jar包使用,如果連不上,這個jar包需要我們自己來打,

1. 下載官方的源代碼

從https://codeload.github.com/happyfish100/fastdfs-client-java/zip/master上下載FastDFS源代碼到本地

2. 解壓

3. 采用maven命令編譯成jar安裝到本地maven庫

mvn clean install

在這里插入圖片描述

4. 在Java程式中使用它提供的API來訪問FastDFS檔案系統

4.2 FastDFS檔案上傳功能實作

4.2.1 需求

使用Java客戶端,編程操作fastDFS分布式檔案系統,上傳本地檔案到FastDFS服務器上,

4.2.2 實作步驟

  1. 使用IDEA創建普通的maven專案,不需要使用
    在這里插入圖片描述
  2. 在pom.xml檔案中添加我們打包好的FastDFS本地倉庫的jar包(FastDFS的java客戶端依賴)
    在這里插入圖片描述
<!--加入FastDFS的java客戶端依賴-->
<dependencies>
    <dependency>
        <groupId>org.csource</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27-SNAPSHOT</version>
    </dependency>
</dependencies>
  1. 拷貝源代碼包中的fdfs_client.conf檔案到resources目錄下,在里面主要配置tracker地址
tracker_server = 192.168.235.128:22122
  1. 撰寫代碼,進行上傳測驗
    在com.bjpowernode.fastdfs包下創建FastDFS類,在其中撰寫上傳代碼
package com.bjpowernode.fastdfs;
import org.csource.common.MyException;
import org.csource.fastdfs.*;
import java.io.IOException;
public class FastDFS {
    public static void main(String[] args) {
        fileUpload();
    }
    //上傳檔案的方法
    public static void fileUpload(){
        TrackerServer trackerServer = null;
        StorageServer storageServer = null;
        try {
            //1.加載組態檔,默認去classpath下加載
            ClientGlobal.init("fdfs_client.conf");
            //2.創建TrackerClient物件
            TrackerClient trackerClient = new TrackerClient();
            //3.創建TrackerServer物件
            trackerServer = trackerClient.getConnection();
            //4.創建StorageServler物件
            storageServer = trackerClient.getStoreStorage(trackerServer);
            //5.創建StorageClient物件,這個物件完成對檔案的操作
            StorageClient storageClient = new StorageClient(trackerServer,storageServer);
            //6.上傳檔案  第一個引數:本地檔案路徑 第二個引數:上傳檔案的后綴 第三個引數:檔案資訊
            String [] uploadArray = storageClient.upload_file("D:/aa.txt","txt",null);
            for (String str:uploadArray) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        } finally {
            if(storageServer != null){
                try {
                    storageServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(trackerServer != null){
                try {
                    trackerServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. 運行程式,在Linux上,FastDFS存盤目錄下查看上傳檔案內容
    在這里插入圖片描述
    在這里插入圖片描述

4.3 FastDFS檔案上傳功能封裝

4.3.1 需求

因為使用FastDFS進行檔案操作代碼大多都是通用的,所以我們這里在FastDFS類中將通用的功能進行封裝,并提供上傳、下載、洗掉檔案的方法,

注意:這里只是簡單的封裝,如果多執行緒會有問題

4.3.2 實作步驟

  1. 抽取獲取StorageClient的方法
public static StorageClient getStorageClient() throws IOException, MyException {
    //1.加載組態檔,默認去classpath下加載
    ClientGlobal.init("fdfs_client.conf");
    //2.創建TrackerClient物件
    TrackerClient trackerClient = new TrackerClient();
    //3.創建TrackerServer物件
    trackerServer = trackerClient.getConnection();
    //4.創建StorageServler物件
    storageServer = trackerClient.getStoreStorage(trackerServer);
    //5.創建StorageClient物件,這個物件完成對檔案的操作
    StorageClient storageClient = new StorageClient(trackerServer,storageServer);
    return storageClient;
}
  1. 定義兩個全域變數
private static TrackerServer trackerServer = null;
private static StorageServer storageServer = null;
  1. 抽取關閉資源的方法
public static void closeFastDFS() {
    if (storageServer != null) {
        try {
            storageServer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    if (trackerServer != null) {
        try {
            trackerServer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 改造檔案上傳的方法
public static void fileUpload(){
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.上傳檔案  第一個引數:本地檔案路徑 第二個引數:上傳檔案的后綴 第三個引數:檔案資訊
        String [] uploadArray = storageClient.upload_file("D:/aa.txt","txt",null);
        for (String str:uploadArray) {
            System.out.println(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
}
  1. 下載檔案的方法
/下載檔案的方法
public static void fileDownload(){
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.下載檔案 回傳0表示成功,其它均表示失敗
        int num = storageClient.download_file("group1",
                "M00/00/00/wKjrgFxOqueAAPWKAAAAKAM14xY563.txt","E:/bb.txt");
        System.out.println(num);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
}
  1. 洗掉檔案的方法
/洗掉檔案的方法
public static void fileDelete(){
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.洗掉檔案 回傳0表示成功,其它均表示失敗
        int num = storageClient.delete_file("group1",
                "M00/00/00/wKjrgFxOqueAAPWKAAAAKAM14xY563.txt");
        System.out.println(num);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
}
  1. 主方法呼叫不同的方法進行測驗

5、FastDFS在web專案中的應用

需求

對P2P專案合同進行管理,在WEB專案中實作對檔案的上傳下載和洗掉操作,

名詞解釋
● 有一些債權:投資人有該債務的權利

注:通常隱含的意思就是:一筆借款常被稱為一個債權,

● 一個債權會有一個合同

● 合同是pdf檔案

● 債權是債務的對應詞,但是在P2P專案中,我們管理的債權,以及合同一般指的是借款人的資訊,所以在我們下面創建的creditor_info表中存的是借款人資訊

目標
● 實作對pdf檔案上傳、下載、洗掉

● 熟練一下Springboot+thymeleaf

案例實作步驟

1. 資料庫環境搭建

① 創建資料庫fastdfs
② 在該庫下創建creditor_info表

CREATE TABLE `creditor_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`realName` varchar(35) DEFAULT NULL COMMENT '債權借款人姓名',
`idCard` 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 '債權借款人借款金額',
`groupName` varchar(10) DEFAULT NULL COMMENT '債權合同所在組',
`remoteFilePath` varchar(150) DEFAULT NULL COMMENT '債權合同所在路徑',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

⒉ 開發環境搭建

① 創建SpringBoot專案10-fastdfs-web,添加Web和Thymeleaf依賴
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
② 在pom.xml檔案中添加Mybatis依賴及MySQL依賴

<!-- 加載mybatis整合springboot -->
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <!--在springboot的父工程中沒有指定版本,我們需要手動指定-->
   <version>1.3.2</version>
</dependency>
<!-- MySQL的jdbc驅動包 -->
<dependency>
   <groupId>mysql</groupId>
   <!--在springboot的父工程中指定了版本,我們就不需要手動指定了-->
   <artifactId>mysql-connector-java</artifactId>
</dependency>

③ 在pom.xml檔案中添加resources,指定編譯的位置

<resources>
   <resource>
      <directory>src/main/java</directory>
      <includes>
         <include>**/*.xml</include>
      </includes>
   </resource>
   <resource>
      <directory>src/main/resources</directory>
      <includes>
         <include>**/*.*</include>
      </includes>
   </resource>
   <!--如果存在jsp,需要指定jsp檔案編譯的位置-->
</resources>

④ 在SpringBoot主組態檔application.properties中添加資料庫配置資訊

#資料庫的連接配置資訊
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.235.128:3306/fastdfs?useUnicode=true&characterEncoding=utf8&useSSL=false

⑤ 使用Mybatis反向工程,生成物體類及mapper映射(參照SpringBoot附錄教程)
A、在pom.xml檔案中添加反向工程插件

<!--mybatis代碼自動生成插件-->
<plugin>
   <groupId>org.mybatis.generator</groupId>
   <artifactId>mybatis-generator-maven-plugin</artifactId>
   <version>1.3.7</version>
   <configuration>
      <!--組態檔的位置-->
      <configurationFile>GeneratorMapper.xml</configurationFile>
      <verbose>true</verbose>
      <overwrite>true</overwrite>
   </configuration>
</plugin>

B、 從03-springboot-web中復制GeneratorMapper.xml到當前專案下

在這里插入圖片描述
C、 修改GeneratorMapper.xml組態檔內容

<?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:/repository/mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar"/>
    <!-- 配置table表資訊內容體,targetRuntime指定采用MyBatis3的版本 -->
    <context id="tables" targetRuntime="MyBatis3">
        <!-- 抑制生成注釋,由于生成的注釋都是英文的,可以不讓它生成 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 配置資料庫連接資訊 注意:使用高版本的驅動 url后面應該加屬性nullCatalogMeansCurrent=true,否則生成有問題 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://192.168.235.128:3306/fastdfs?nullCatalogMeansCurrent=true"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!-- 生成model類,targetPackage指定model類的包名, targetProject指定生成的model放在eclipse的哪個工程下面-->
        <javaModelGenerator targetPackage="com.bjpowernode.fastdfs.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>
        <!-- 生成MyBatis的Mapper.xml檔案,targetPackage指定mapper.xml檔案的包名, targetProject指定生成的mapper.xml放在eclipse的哪個工程下面 -->
        <sqlMapGenerator targetPackage="com.bjpowernode.fastdfs.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成MyBatis的Mapper介面類檔案,targetPackage指定Mapper介面類的包名, targetProject指定生成的Mapper介面放在eclipse的哪個工程下面 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.bjpowernode.fastdfs.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 資料庫表名及對應的Java模型類名 -->
        <table tableName="creditor_info"
               domainObjectName="CreditorInfo"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>

D、雙擊生成
在這里插入圖片描述
⑥ 創建相關的包和類

在com.bjpowernode.fast包下創建controller ,service 包,及其子包impl

創建CreditorInfoController類

創建CreditorInfoService介面

創建CreditorInfoServiceImpl實作類
在這里插入圖片描述
3. 功能實作-展示所有債權資訊
① 在CreditorInfoController類中創建index方法,將CreditorInfoService注入到controller中

@Controller
public class CreditorInfoController {
    @Autowired
    private CreditorInfoService creditorInfoService;

    @GetMapping("/fastdfs/index")
    public String index(Model model){
        List<CreditorInfo> creditorInfoList = creditorInfoService.getAllCreditorInfo();
        model.addAttribute("creditorInfoList",creditorInfoList);
        //模板頁面,不是jsp
        return "index";
    }
}

② 在CreditorInfoService中提供getAllCreditorInfo方法

public interface CreditorInfoService {
    /**
     * 獲取所有債權資訊
     * @return
     */
    List<CreditorInfo> getAllCreditorInfo();
}

③ 在CreditorInfoServiceImpl中對getAllCreditorInfo方法進行實作

@Service
public class CreditorInfoServiceImpl implements CreditorInfoService {
    @Autowired
    private CreditorInfoMapper creditorInfoMapper;
    @Override
    public List<CreditorInfo> getAllCreditorInfo() {
        return creditorInfoMapper.selectAllCreditorInfo();
    }
}

④ 因為是SpringBoot專案,所以需要在Mapper介面上加一個Mapper注解

@Mapper
public interface CreditorInfoMapper {}

⑤ 在CreditorInfoMapper類中添加selectAllCreditorInfo方法

List<CreditorInfo> selectAllCreditorInfo();

⑥ 在IDEA中安裝free Mybatis插件

該插件可以通過點擊Mapper介面中的方法,進入到.xml檔案

A、 SettingsàpluginsàBrowse repositories

在這里插入圖片描述
B、 在插件庫中搜索,free mybatis安裝
在這里插入圖片描述
C、 插件安裝完畢,需要重啟IDEA

⑦ 在CreditorInfoMapper.xml檔案中添加SQL陳述句

<select id="selectAllCreditorInfo" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from creditor_info
</select>

⑧ 展示頁面的設計

A、 在專案的templates目錄下創建index.html
在這里插入圖片描述
B、 百度搜索bootstrap表格,挑選自己喜歡風格的表格,將代碼拷貝到index.html中

我這里使用的是http://www.bjpowernode.com/try/try.php?

filename=bootstrap3-table-striped表格進行改寫

C、 在html標簽上加上Thymeleaf的命名空間

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

D、 修改index.html內容

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <title>債權合同管理</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap-3.3.7.min.css}">
    <script th:src="@{/js/jquery-2.1.1.min.js}"></script>
    <script th:src="@{/js/bootstrap-3.3.7.min.js}"></script>
</head>
<body>
<table class="table table-striped">
    <caption>債權合同資訊串列</caption>
    <thead>
    <tr>
        <th>序號</th>
        <th>債權借款人姓名</th>
        <th>債權借款人身份證</th>
        <th>債權借款人住址</th>
        <th>債權借款人手機號</th>
        <th>債權借款人性別</th>
        <th>債權借款人借款金額</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="creditorInfo:${creditorInfoList}">
        <td th:text="${creditorInfoStat.count}"></td>
        <td th:text="${creditorInfo.realname}"></td>
        <td th:text="${creditorInfo.idcard}"></td>
	<td th:text="${creditorInfo.address}"></td>
        <td th:text="${creditorInfo.phone}"></td>
        <td th:text="${creditorInfo.sex == 1 ?'':''}"></td>
        <td th:text="${creditorInfo.money}"></td>
    </tr>
    </tbody>
</table>
</body>
</html>

注意:我們從網路上拷貝過來的內容css,js等是聯網獲取的,我們這里可以從04-FastDFS\resources獲取,并放在專案的static的相關目錄下,在頁面上參考
⑨ 向資料庫中加幾條資料
在這里插入圖片描述
⑩ 啟動專案,訪問http://localhost:8080/fastdfs/index 查看效果
在這里插入圖片描述
? 調整頁面樣式

<body style="margin: 50px">
  1. 功能實作-為某一個債權合同上傳檔案

① 在index.html中添加操作列

<th>合同管理</th>

<td>
    <!--為哪個合同上傳,需要將合同的id傳遞過去-->
    <a th:href="@{'/fastdfs/toUpload?id=' + ${creditorInfo.id}}">上傳</a>
    下載
    洗掉
</td>

② 在CreditorController中添加跳轉到上傳頁面的方法

@GetMapping("/fastdfs/toUpload")
public String toUpload(Model model, @RequestParam("id") Integer id){
    model.addAttribute("id",id);
    return "upload";
}

③ 在templates下創建upload.html頁面

在網上搜索bootstrap表單,并對其內容進行修改,我這里使用的是

http://www.bjpowernode.com/try/try2.php?filename=bootstrap3-form-inline

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <title>債權合同上傳</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap-3.3.7.min.css}">
    <script th:src="@{/js/jquery-2.1.1.min.js}"></script>
    <script th:src="@{/js/bootstrap-3.3.7.min.js}"></script>
</head>
<body>
    <form th:action="@{/fastdfs/upload}" class="form-inline" role="form" method="post" enctype="multipart/form-data">
        <div class="form-group">
            <label class="sr-only" for="fileName">檔案輸入</label>
            <input type="file" id="fileName" name="fileName">
        </div>
        <input type="hidden" name="id" th:value="${id}">
        <button type="submit" class="btn btn-default">提交</button>
    </form>
</body>
</html>

注意

● 檔案上傳必須是post請求

● enctype必須為multipart/form-data

● 合同的id通過隱藏域傳遞

④ 在pom.xml檔案中加入FastDFS客戶端的jar包依賴

<!--加入FastDFS的java客戶端依賴-->
<dependency>
   <groupId>org.csource</groupId>
   <artifactId>fastdfs-client-java</artifactId>
   <version>1.27-SNAPSHOT</version>
</dependency>

⑤ 將FastDFS客戶端的組態檔fast_client.conf拷貝到resources目錄下
在這里插入圖片描述
⑥ 將原來我們封裝的FastDFS類拷貝到fastdfs包下,修改其中的file_upload方法,定義一些引數

去掉主方法,新的fileUpload寫法如下:

/上傳檔案的方法
public static String[] fileUpload(byte[] fileBytes,String fileExt){
    String [] uploadArray = null;
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.上傳檔案  第一個引數:本地檔案路徑 第二個引數:上傳檔案的后綴 第三個引數:檔案資訊
        uploadArray = storageClient.upload_file(fileBytes,fileExt,null);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
    return uploadArray;
}

⑦ 在CreditorController中添加處理上傳檔案的方法

@PostMapping("/fastdfs/upload")
public @ResponseBody String upload(@RequestParam("id") Integer id, @RequestParam("fileName") MultipartFile file){
    //原來檔案上傳是將檔案寫到本地或者遠程服務器的某個目錄下
    //現在的檔案上傳是將檔案上傳到fastdfs檔案服務器上
    //1表示上傳失敗  0表示成功
    int result = 1;
    //abc.txt -->txt
    String fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf(".") + 1);
    try {
        String[] uploadArray = FastDFS.fileUpload(file.getBytes(),fileExt);
        if(uploadArray != null && uploadArray.length ==2){
            //檔案上傳到fastDFS成功  ,將合同檔案路徑更新到債權記錄中
            CreditorInfo creditorInfo = new CreditorInfo();
            creditorInfo.setId(id);
            creditorInfo.setGroupname(uploadArray[0]);
            creditorInfo.setRemotefilepath(uploadArray[1]);
            int updateRow = creditorService.updateCreditorInfo(creditorInfo);
            //資料庫更新成功
            if(updateRow > 0){
                result = 0;
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return "<script>window.parent.uploadOK('"+result+"')</script>";
}

⑧ 在CreditorInfoService中添加updateCreditorInfo方法

/**
 * 更新債權資訊
 * @param creditorInfo
 * @return
 */
int updateCreditorInfo(CreditorInfo creditorInfo);

⑨ 在CreditorInfoServiceImpl中添加updateCreditorInfo方法實作

@Override
public int updateCreditorInfo(CreditorInfo creditorInfo) {
    return creditorInfoMapper.updateByPrimaryKeySelective(creditorInfo);
}

⑩ 在upload.html做一個類似ajax的頁面不重繪效果

● 在upload.html頁面中加一個iframe

● upload.html頁面中的form中的target設定為iframe的name

● 在iframe的父頁面中,寫一個函式,處理上傳結果

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <title>債權合同上傳</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap-3.3.7.min.css}">
    <script th:src="@{/js/jquery-2.1.1.min.js}"></script>
    <script th:src="@{/js/bootstrap-3.3.7.min.js}"></script>
</head>
<body>
    <form th:action="@{/fastdfs/upload}" class="form-inline" role="form" method="post" target="uploadFrame" enctype="multipart/form-data">
        <div class="form-group">
            <label class="sr-only" for="fileName">檔案輸入</label>
            <input type="file" id="fileName" name="fileName">
        </div>
        <input type="hidden" id="id" name="id" th:value="${id}">
        <button type="submit" class="btn btn-default">提交</button>
    </form>
    <iframe name="uploadFrame" style="display: none;"></iframe>
    <script type="text/javascript" th:inline="javascript">
        function uploadOK(result){
            if(result == 0){
                //檔案上傳成功
                alert("檔案上傳成功");
                var contextPath = [[${#request.getContextPath()}]];
                window.location.href = contextPath + "/fastdfs/index";
            }else{
                alert("檔案上傳失敗");
            }
        }
    </script>
</body>
</html>

? 如果上傳檔案超出了1M,需要在application.properties中配置SpringBoot上傳檔案的最大限制

#SpringBoot上傳檔案的最大限制
spring.servlet.multipart.max-file-size=10MB

注意:如果提示找不到tracker_server,看看是否編譯到target中

  1. 功能實作-下載某一個債權合同
    ① 修改index.html頁面,下載加連接,并做判斷
<td>
    <span th:if="${creditorInfo.getGroupname() ne null && creditorInfo.remotefilepath ne null}">
        <a th:href="@{'/fastdfs/download?id=' + ${creditorInfo.id}}">下載</a>
        洗掉
    </span>
    <span th:unless="${creditorInfo.getGroupname() ne null && creditorInfo.remotefilepath ne null}">
        <!--為哪個合同上傳,需要將合同的id傳遞過去-->
        <a th:href="@{'/fastdfs/toUpload?id=' + ${creditorInfo.id}}">上傳</a>
    </span>
</td>

② 在CreditorController中,完成下載的請求

● ResponseEntity通常用于回傳檔案流

● @ResponseBody可以直接回傳Json結果,

● @ResponseEntity不僅可以回傳json結果,還可以定義回傳的HttpHeaders和HttpStatus

● ResponseEntity的優先級高于@ResponseBody,在不是ResponseEntity的情況下才去檢查有沒有@ResponseBody注解,如果回應型別是ResponseEntity可以不寫@ResponseBody注解,寫了也沒有關系,

@GetMapping("/fastdfs/download")
public ResponseEntity<byte[]> download(@RequestParam("id") Integer id){
    //根據債權id獲取 債權物件
    CreditorInfo creditorInfo = creditorInfoService.getCreditorInfoById(id);
    String extName = creditorInfo.getRemotefilepath().substring(creditorInfo.getRemotefilepath().indexOf("."));
    byte [] fileBytes = FastDFS.fileDownload(creditorInfo.getGroupname(),creditorInfo.getRemotefilepath());


    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);//流型別
    httpHeaders.setContentDispositionFormData("attachment",System.currentTimeMillis() + extName);

    ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(fileBytes,httpHeaders, HttpStatus.OK);
    return responseEntity;
}

③ 在CreditorService介面中添加getCreditorInfoById的方法

/**
 * 根據合同id獲取債權資訊
 * @param id
 * @return
 */
CreditorInfo getCreditorInfoById(Integer id);

④ 在CreditorServiceImpl中添加getCreditorInfoById方法的實作

@Override
public CreditorInfo getCreditorInfoById(Integer id) {
    return creditorInfoMapper.selectByPrimaryKey(id);
}

⑤ 修改FastDFS類中fileDown方法的實作,傳遞引數

//下載檔案的方法
public static byte[] fileDownload(String group,String remoteFile){
    byte[] fileBytes = null;
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.下載檔案 回傳0表示成功,其它均表示失敗
        fileBytes = storageClient.download_file(group,remoteFile);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
    return fileBytes;
}

⑥ 瀏覽器訪問下載測驗效果

  1. 功能實作-洗掉某一個債權合同,使用ajax實作異步洗掉
    ① 在index.html頁面為洗掉加超鏈接
<span th:if="${creditorInfo.getGroupname() ne null && creditorInfo.remotefilepath ne null}">
    <a th:href="@{'/fastdfs/download?id=' + ${creditorInfo.id}}">下載</a>
    <a th:href="@{'javascript:deleteFile('+ ${creditorInfo.id} +')'}">洗掉</a>
</span>

② 在index.html頁面提供js方法,并發送ajax請求,對回應結果進行處理

<script type="text/javascript" th:inline="javascript">
    function deleteFile(id){
        //獲取專案的背景關系根
        var contextPath = [[${#request.getContextPath()}]];
        $.ajax({
            url:contextPath +"/fastdfs/fileDelete",
            type:"post",
            data:{
                "id":id
            },
            success:function(responseMsg){
                if(responseMsg==0){
                    alert("洗掉成功");
			window.location.reload();
                }else{
                    alert("洗掉失敗");
                }
            }
        });
    }
</script>

③ 在CreditorController中處理洗掉請求

注意:洗掉FastDFS和清除資料庫,所以我們將這些業務都放在service中進行事務的處理

@RequestMapping("/fastdfs/fileDelete")
public @ResponseBody String fileDelete(@RequestParam("id") Integer id){
    int result = 1;
    try {
        result = creditorService.deleteContract(id);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return String.valueOf(result);
}

④ 在CreditorService介面中加洗掉合同的方法deleteContract

因為目前提供的方法,如果group和remoteFilePath為空就不更新,所以我們需要自己提供

/**
 * 洗掉合同
 * @param id
 * @return
 */
int deleteContract(Integer id);

⑤ 在CreditorServiceImpl類中對deleteContract方法進行實作

@Override
@Transactional //加上該注解控制事務
public int deleteContract(Integer id) {
    // 1 洗掉失敗;0 洗掉成功
    int result = 1;
    //根據債權id獲取債權資訊
    CreditorInfo creditorInfo = creditorInfoMapper.selectByPrimaryKey(id);
    /**
     * 注意:事務控制的資料庫,所以我們先對資料庫進行更新,在操作FastDFS
     * 如果操作FastDFS失敗了,那么對資料庫的操作回滾
     */
    //更新資料庫債權表的合同路徑及組
    int updateRow = creditorInfoMapper.updateConstractById(id);
    if(updateRow > 0){
        //如果資料庫更新成功,那么洗掉FastDFS上的檔案
        int num = FastDFS.fileDelete(creditorInfo.getGroupname(),creditorInfo.getRemotefilepath());
        if(num == 0){
            //如果洗掉成功,那么將整個操作結果設定為0,表示成功
            result = 0;
        }else{
            //如果洗掉FastDFS上的檔案失敗,我們拋出一個運行例外,回滾事務
            throw new RuntimeException("FastDFS檔案洗掉失敗");
        }
    }

    return result;
}

⑥ 在CreditorMapper類中添加更新的方法

/**
 * 根據債權的id,將組和合同路徑更新為null
 * @param id
 * @return
 */
int updateConstractById(Integer id);

⑦ 在CreditorMapper.xml中添加更新的方法

<update id="updateConstractById" parameterType="java.lang.Integer">
  update creditor_info
  set 
  groupName = NULL ,
  remoteFilePath = NULL 
  where id = #{id,jdbcType=INTEGER}
</update>

⑧ 修改FastDFS類中的fileDelete方法,提供引數

//洗掉檔案的方法
public static int fileDelete(String group ,String remoteFile){
    int num = 1;
    try {
        //1. 獲取StorageClient物件
        StorageClient storageClient = getStorageClient();
        //2.洗掉檔案 回傳0表示成功,其它均表示失敗
        num = storageClient.delete_file(group,remoteFile);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (MyException e) {
        e.printStackTrace();
    } finally {
        closeFastDFS();
    }
    return num; 
}

⑨ 在Application類上開啟事務支持

@SpringBootApplication
@EnableTransactionManagement
public class Application {
   public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
   }
}
  1. 功能實作-彈層組建layer的使用(簡單介紹)

官網:https://www.layui.com

2018開源軟體排行比較靠前

6、FastDFS分布式檔案系統集群

6.1 架構圖

在這里插入圖片描述
● 如果你公司剛好用這個,那你就會搭建集群

● 涉及到多個Linux,你可以更進一步熟悉一下Linux

● 提升自己駕馭復雜環境的能力

6.2 環境搭建步驟

建一個FastDFS分布式檔案系統集群,推薦至少部署6個服務器節點,

1. 安裝6個迷你版的Linux

迷你版Linux沒有圖形界面,占用磁盤及資源小,企業里面使用的Linux都是沒有圖形界面的Linux,在安裝的時候,最少要給每一個虛擬機分配3.5G的記憶體空間,我這里分配5G,記憶體我這里分配的是512M

① 打開Vmware,點擊創建新的虛擬機
② 選擇典型安裝
③ 選擇安裝Linux迷你版安裝檔案位置
④ 指定虛擬機名稱及安裝位置
⑤ 為虛擬機分配磁盤空間
⑥ 為虛擬機分配記憶體
我是8G記憶體,每個虛擬機分配512M,因為是迷你版,所以記憶體消耗不會太大
⑦ 開啟此虛擬機
⑧ 開始安裝
⑨ 選擇語言為English
⑩ 打開網路連接(重要)
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
這個選項點進去完成一下就好,其它配置都可以默認,但是網路一定要打開,否則虛擬機之間無法通訊
? 設定root用戶密碼為123456

在這里插入圖片描述

? 安裝完畢后,重啟安裝的CentOS系統

2. 在Xshell中創建6個連接,分別連向不同的Linux

在這里插入圖片描述

3. 為迷你版的Linux安裝常用工具庫

由于迷你版Linux缺少一些常用的工具庫,操作起來不方便,推薦安裝如下的工具庫:

? 安裝lrzsz, yum install lrzsz -y

? 安裝wget, yum install wget -y

? 安裝vim, yum install vim -y

? 安裝unzip,yum install unzip -y

? 安裝ifconfig,yum install net-tools -y

yum install lrzsz wget vim unzip net-tools –y

打開撰寫欄,方便批量執行命令
在這里插入圖片描述

4. 按照課件上安裝FastDFS的步驟在6個服務器節點安裝FastDFS

5. 配置兩個tracker server服務器

為了方便操作,我們再啟動一次Xshell,一個Xshell操作Tracker,另一個操作Storage,將Tracker和Storage分開

? 把/etc/fdfs目錄下的組態檔.sample后綴都去掉

? 修改兩個tracker服務器的組態檔:

tracker.conf: 修改一個地方:

base_path=/opt/fastdfs/tracker #設定tracker的資料檔案和日志目錄(需預先創建)

? 創建存放資料的目錄

6. 配置四個storage server服務器

每兩個storage server為一組,共兩個組(group1 和 group2),一個組內有兩個storage server

① 修改第一組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.235.129:22122 #tracker服務器的IP地址和埠號,配2個tracker_server=192.168.235.130:22122

② 第一個組的第二個storage按照相同的步驟操作

或者將第一組的組態檔下載到桌面上,然后上傳覆寫第一組的第二個storage

③ 第二組的兩個storage也按照相同的步驟操作;唯一的區別是group_name=group2

可以在桌面上對第一個組的storage檔案進行修改,將組名修改為group2,然后上傳覆寫

至此,一個FastDFS的分布式檔案系統集群就搭建好了,

④ 注意:組態檔中不要出現中文,另外別忘了創建組態檔中指定的目錄

⑤ 啟動兩個tracker,再啟動四個storage

⑥ 關閉6個Linux防火墻,通過09-fastdfs-java的代碼進行測驗

修改組態檔為兩個tracker

測驗負載均衡:tracker.conf檔案 (修改 store_lookup=0 表示輪訓策略)

7. 部署Http訪問FastDFS上的檔案

① 先完成4個storage server的Nginx訪問

這4個Nginx需要去fastDFS找對應的檔案,所以需要安裝FastDFS的Nginx擴展模塊

A、 配置帶有FastDFS擴展模塊的Nginx

在四個storage server上安裝Nginx,并且加入FastDFS擴展模塊;

修改兩組4個storage的nginx擴展模塊組態檔 mod_fastdfs.conf

base_path=/opt/fastdfs/nginx_mod #保存日志目錄(需提前創建)
tracker_server=192.168.230.129:22122  #tracker服務器的IP地址以及埠號
tracker_server=192.168.230.130:22122
group_name=group1  #當前服務器的group名,第二組應配置為group2
url_have_group_name=true     #檔案url中是否有group名
store_path_count=1           #存盤路徑個數,需要和store_path個數匹配(一般不用改)
store_path0=/opt/fastdfs/storage/files    #存盤路徑
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

B、 第一組的第二臺和上面的配置一樣

C、 第二組的兩臺只需要把group_name=group2即可

D、 至此,mod_fastdfs.conf就配置好了,

② 配置兩組4個storage的nginx攔截請求路徑:

location ~ /group[1-9]/M0[0-9] {   
    ngx_fastdfs_module;
}

至此4個storage服務器上的Nginx就搭建配置OK了

然后可以進行測驗:

重啟storage,啟動Nginx

http://192.168.119.128:80/group1/M00/00/00/wKh3jVx6FUCARyK2AAAANaS4cxw338.txt

http://192.168.92.132:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

http://192.168.92.133:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

http://192.168.92.134:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

注意:每一臺都可以訪問到,就算是當前組中沒有改檔案,因為向瀏覽器中發送請求的時候

交給Nginx進行location匹配

匹配上之后呼叫FastDFS的擴展模塊

擴展模塊會讀取擴展模塊組態檔mod_fast.conf

通過擴展模塊組態檔,找到對應的Tracker,從而找到對應的檔案

③ 在兩個tracker server安裝Nginx

這兩個Nginx只需要做負載均衡,不要找檔案,所以不需要安裝擴展模塊

④ 配置兩個tracker server服務器上的Nginx訪問

部署配置nginx負載均衡:
upstream fastdfs_storage_server {  
    server 192.168.92.131:80;  
    server 192.168.92.132:80;
    server 192.168.92.133:80;  
    server 192.168.92.134:80;  
}
#nginx攔截請求路徑:
location ~ /group[1-9]/M0[0-9] {   
    proxy_pass http://fastdfs_storage_server; 
}

至此,兩個tracker服務器的Nginx就搭建配置OK了,

啟動兩個tracker服務器的Nginx進行測驗,

http://192.168.92.129:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

http://192.168.92.130:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

⑤ 部署前端用戶訪問入口服務器,該Nginx負載均衡到后端2個tracker server

這個Nginx也只需要做負載均衡,不要找檔案,所以不需要安裝擴展模塊,可以對Windows上的的Nginx進行配置

部署配置nginx負載均衡:

upstream fastdfs_tracker_server {  
    server 192.168.92.129:80;  
    server 192.168.92.130:80;  
}
#nginx攔截請求路徑:
location ~ /group[1-9]/M0[0-9] {   
    proxy_pass http://fastdfs_tracker_server; 
}

訪問:http://127.0.0.1:80/group1/M00/00/00/wKhchFv7xQeAQbrBAAAALDPVPvc081.txt

至此,一個三層結構的Nginx訪問架構就搭建配置OK了,為了保證高可用性,一般在入口出,會添加一個備用Nginx上,中間通過一個keepAlive軟體連接,

最后,為了讓服務能正常連接tracker,請關閉所有機器的防火墻:

systemctl status firewalld

systemctl disable firewalld

systemctl stop firewalld

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/291826.html

標籤:其他

上一篇:SpringCloud系列教程(二)之Nacos

下一篇:nginx利用keepalived實作高可用的配置

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more