FASTDFS輕量級(jí)分布式文件系統(tǒng)快速上手(提供工具欄全套代碼配置)

百度百科介紹
FastDFS是一個(gè)C語言編寫的開源的輕量級(jí)分布式文件系統(tǒng),它對(duì)文件進(jìn)行管理费就,功能包括:文件存儲(chǔ)祝辣、文件同步褐捻、文件訪問(文件上傳媒役、文件下載)等观堂,解決了大容量存儲(chǔ)和負(fù)載均衡(https://baike.baidu.com/item/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1/932451)的問題惩猫。特別適合以文件為載體的在線服務(wù)霉颠,如相冊網(wǎng)站查牌、視頻網(wǎng)站等等事期。

FastDFS為互聯(lián)網(wǎng)量身定制,充分考慮了冗余備份纸颜、負(fù)載均衡兽泣、線性擴(kuò)容等機(jī)制,并注重高可用胁孙、高性能等指標(biāo)唠倦,使用FastDFS很容易搭建一套高性能文件服務(wù)器集群提供文件上傳、下載等服務(wù)涮较。

一 FastDFS介紹

FastDFS架構(gòu)包括Tracker server和Storage server稠鼻。
客戶端請(qǐng)求Tracker server進(jìn)行文件上傳、下載狂票,通過Tracker server調(diào)度最終由Storage server完成文件上傳和下載候齿。

  • Tracker server作用是負(fù)載均衡和調(diào)度,通過Tracker server在文件上傳時(shí)可以根據(jù)一些策略找到Storage server提供文件上傳服務(wù)』哦ⅲ可以將tracker稱為追蹤服務(wù)器或調(diào)度服務(wù)器周霉。

  • storage server作用是文件存儲(chǔ),客戶端上傳的文件最終存儲(chǔ)在Storage 服務(wù)器上

storageserver沒有實(shí)現(xiàn)自己的文件系統(tǒng)而是利用操作系統(tǒng)的文件系統(tǒng)來管理文件润匙。可以將storage稱為存儲(chǔ)服務(wù)器诗眨。

FASTDFS系統(tǒng)架構(gòu)圖

FASTDFS服務(wù)端兩個(gè)角色:

Tracker:管理集群,tracker也可以實(shí)現(xiàn)集群孕讳。每個(gè)tracker節(jié)點(diǎn)地位平等.收集Storage集群的狀態(tài)匠楚。
Storage:實(shí)際保存文件 storage分為多個(gè)組,每個(gè)組之間保存的文件是不同的厂财。每個(gè)組內(nèi)部可以有多個(gè)成員芋簿,組成員內(nèi)部保存的內(nèi)容是一致的組成員的地位是一致的璃饱,沒有主從的概念与斤。

ps這里說一下,做上傳時(shí)候我們有時(shí)候會(huì)需要做一些格式轉(zhuǎn)化可能遇到MockMultipartFile和我們springboot2.x的版本不兼容問題
Configuration property name 'fdfs.thumbImage' is not valid:


    Invalid characters: 'I'
    Bean: pictureController

    Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter


Action:
Modify 'fdfs.thumbImage' so that it conforms to the canonical names requirements.

這里我推薦springboot2.0以上用戶可以使用解決

       <dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
            <version>1.26.1-RELEASE</version>
        </dependency>

關(guān)于FASTDFS的使用

這里背景是我的cenos ip為http://192.168.25.133/,不到測試不開,咱也不怕你攻擊

糧草未到兵馬先行,先說一下準(zhǔn)備工作

applicatio.properties
#臨時(shí)文件保存目錄
hcat.tmpdir=D:/temp


#整合FASTDFS
fdfs.soTimeout=1501
fdfs.connectTimeout=601 
#縮略圖生成參數(shù)
fdfs.thumbImage.width=150
fdfs.thumbImage.height=150
#TrackerList參數(shù),支持多個(gè)
fdfs.trackerList[0]=192.168.25.133:22122

#HTTP URL
fdfs.httpurl=http://192.168.25.133/

pom maven配置

 <!--整合FastDFS-->
        <dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
            <version>1.26.1-RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>

1.ComponetImport

package com.zyh.future.util;

import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;

/**
 * 導(dǎo)入FastDFS-Client組件
 *
 * @author tobato
 *
 */
@Configuration
@Import(FdfsClientConfig.class)
// 解決jmx重復(fù)注冊bean的問題
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class ComponetImport {
}
2.FastDFSClient
package com.zyh.future.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;

import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

@Component
public class FastDFSClient {

    @Autowired
    private FastFileStorageClient storageClient;

//  @Autowired
//  private AppConfig appConfig; // 項(xiàng)目參數(shù)配置

    /**
     * 上傳文件
     * 
     * @param file
     *            文件對(duì)象
     * @return 文件訪問地址
     * @throws IOException
     */
    public String uploadFile(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(),
                FilenameUtils.getExtension(file.getOriginalFilename()), null);

        return storePath.getGroup() + "/" + storePath.getPath();
    }

    public String uploadFile(File file) throws IOException {
        StorePath storePath = storageClient.uploadFile(new FileInputStream(file), FileUtils.sizeOf(file),
                FilenameUtils.getExtension(file.getName()), null);

        return storePath.getGroup() + "/" + storePath.getPath();
    }
    
    public String uploadFile2(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(),
                FilenameUtils.getExtension(file.getOriginalFilename()), null);

        return storePath.getGroup() + "/" + storePath.getPath();
    }
    
    public String uploadQRCode(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(),
                "png", null);
        
        return storePath.getGroup() + "/" + storePath.getPath();
    }
    
    public String uploadFace(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(),
                "png", null);
        
        return storePath.getGroup() + "/" + storePath.getPath();
    }
    
    public String uploadBase64(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadImageAndCrtThumbImage(file.getInputStream(), file.getSize(),
                "png", null);
        
        return storePath.getGroup() + "/" + storePath.getPath();
    }
    
    /**
     * 將一段字符串生成一個(gè)文件上傳
     * 
     * @param content
     *            文件內(nèi)容
     * @param fileExtension
     * @return
     */
    public String uploadFile(String content, String fileExtension) {
        byte[] buff = content.getBytes(Charset.forName("UTF-8"));
        ByteArrayInputStream stream = new ByteArrayInputStream(buff);
        StorePath storePath = storageClient.uploadFile(stream, buff.length, fileExtension, null);
        return storePath.getGroup() + "/" + storePath.getPath();
    }

    // 封裝圖片完整URL地址
//  private String getResAccessUrl(StorePath storePath) {
//      String fileUrl = AppConstants.HTTP_PRODOCOL + appConfig.getResHost() + ":" + appConfig.getFdfsStoragePort()
//              + "/" + storePath.getFullPath();
//      return fileUrl;
//  }

    /**
     * 刪除文件
     * 
     * @param fileUrl
     *            文件訪問地址
     * @return
     */
    public void deleteFile(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            return;
        }
        try {
            StorePath storePath = StorePath.praseFromUrl(fileUrl);
            storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
        } catch (FdfsUnsupportStorePathException e) {
            e.getMessage();
        }
    }
}

3.FileUtils

package com.zyh.future.util;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;

@Service
public class FileUtils {
    /**
     * 根據(jù)url拿取file
     * 
     * @param url
     * @param suffix
     *            文件后綴名
     */
    public static File createFileByUrl(String url, String suffix) {
        byte[] byteFile = getImageFromNetByUrl(url);
        if (byteFile != null) {
            File file = getFileFromBytes(byteFile, suffix);
            return file;
        } else {
            return null;
        }
    }

    /**
     * 根據(jù)地址獲得數(shù)據(jù)的字節(jié)流
     * 
     * @param strUrl
     *            網(wǎng)絡(luò)連接地址
     * @return
     */
    private static byte[] getImageFromNetByUrl(String strUrl) {
        try {
            URL url = new URL(strUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inStream = conn.getInputStream();// 通過輸入流獲取圖片數(shù)據(jù)
            byte[] btImg = readInputStream(inStream);// 得到圖片的二進(jìn)制數(shù)據(jù)
            return btImg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 從輸入流中獲取數(shù)據(jù)
     * 
     * @param inStream
     *            輸入流
     * @return
     * @throws Exception
     */
    private static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }

    // 創(chuàng)建臨時(shí)文件
    private static File getFileFromBytes(byte[] b, String suffix) {
        BufferedOutputStream stream = null;
        File file = null;
        try {
            file = File.createTempFile("pattern", "." + suffix);
            System.out.println("臨時(shí)文件位置:" + file.getCanonicalPath());
            FileOutputStream fstream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fstream);
            stream.write(b);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

    public static MultipartFile createImg(String url) {
        try {
            // File轉(zhuǎn)換成MutipartFile
            File file = FileUtils.createFileByUrl(url, "jpg");
            FileInputStream inputStream = new FileInputStream(file);
            MultipartFile multipartFile = new MockMultipartFile(file.getName(), inputStream);
            return multipartFile;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static MultipartFile fileToMultipart(String filePath) {
        try {
            // File轉(zhuǎn)換成MutipartFile
            File file = new File(filePath);
            FileInputStream inputStream = new FileInputStream(file);
            MultipartFile multipartFile = new MockMultipartFile(file.getName(), "png", "image/png", inputStream);
            return multipartFile;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        // WebFileUtils.createFileByUrl("http://122.152.205.72:88/group1/M00/00/01/CpoxxFr7oIaAZ0rOAAC0d3GKDio580.png",
        // "png");
        // WebFileUtils.createImg("http://122.152.205.72:88/group1/M00/00/01/CpoxxFr7oIaAZ0rOAAC0d3GKDio580.png");
    }

    public static boolean base64ToFile(String filePath, String base64Data)  throws Exception {
        String dataPrix = "";
        String data = "";
        
        if(base64Data == null || "".equals(base64Data)){
            return false;
        }else{
            String [] d = base64Data.split("base64,");
            if(d != null && d.length == 2){
                dataPrix = d[0];
                data = d[1];
            }else{
                return false;
            }
        }

        // 因?yàn)锽ASE64Decoder的jar問題,此處使用spring框架提供的工具包
        byte[] bs = Base64Utils.decodeFromString(data);
        // 使用apache提供的工具類操作流
        org.apache.commons.io.FileUtils.writeByteArrayToFile(new File(filePath), bs);
        
        return true;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荚恶,一起剝皮案震驚了整個(gè)濱河市撩穿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谒撼,老刑警劉巖食寡,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異廓潜,居然都是意外死亡抵皱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門辩蛋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呻畸,“玉大人,你說我怎么就攤上這事悼院∩宋” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵据途,是天一觀的道長钮呀。 經(jīng)常有香客問我,道長昨凡,這世上最難降的妖魔是什么爽醋? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮便脊,結(jié)果婚禮上蚂四,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好遂赠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布久妆。 她就那樣靜靜地躺著,像睡著了一般跷睦。 火紅的嫁衣襯著肌膚如雪筷弦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天抑诸,我揣著相機(jī)與錄音烂琴,去河邊找鬼。 笑死蜕乡,一個(gè)胖子當(dāng)著我的面吹牛奸绷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播层玲,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼号醉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辛块?” 一聲冷哼從身側(cè)響起畔派,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎润绵,沒想到半個(gè)月后线椰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡授药,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年士嚎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呜魄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悔叽。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爵嗅,靈堂內(nèi)的尸體忽然破棺而出娇澎,到底是詐尸還是另有隱情,我是刑警寧澤睹晒,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布趟庄,位于F島的核電站,受9級(jí)特大地震影響伪很,放射性物質(zhì)發(fā)生泄漏戚啥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一锉试、第九天 我趴在偏房一處隱蔽的房頂上張望猫十。 院中可真熱鬧,春花似錦、人聲如沸拖云。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宙项。三九已至乏苦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尤筐,已是汗流浹背汇荐。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叔磷,地道東北人拢驾。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像改基,于是被迫代替她去往敵國和親繁疤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容