Backend Development 10 min read

Step-by-Step Guide to Deploy FastDFS with Docker and Integrate It into a Spring Boot Application

This tutorial explains how to install Docker, pull and run a FastDFS Docker image, verify the service, add the fastdfs-client dependency to a Spring Boot project, configure the client, implement a utility class for file operations, and test the integration with sample code.

Top Architect
Top Architect
Top Architect
Step-by-Step Guide to Deploy FastDFS with Docker and Integrate It into a Spring Boot Application

The article begins by describing the difficulties of setting up FastDFS from source and suggests using a pre‑built Docker image to simplify the process.

1. Install Docker

yum install -y docker-io #安装docker

service docker start #启动docker

docker -v  # 查看docker版本

2. Pull the FastDFS image

docker pull qbanxiaoli/fastdfs

3. Run the FastDFS container

docker run -d --restart=always --privileged=true --net=host --name=fastdfs -e IP=192.168.127.131 -e WEB_PORT=80 -v ${HOME}/fastdfs:/var/local/fdfs qbanxiaoli/fastdfs

After the container starts, the article shows how to enter the container and test the service:

docker exec -it fastdfs /bin/bash

echo "Hello FastDFS!" >index.html

fdfs_test /etc/fdfs/client.conf upload index.html

If the upload returns a URL, the FastDFS instance is considered successfully deployed.

4. Add the FastDFS client dependency to a Spring Boot project

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

Enable the configuration in the Spring Boot main class:

@Import(FdfsClientConfig.class)
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)

5. Implement a FastDFSClient utility class

package com.yd.client.common;

import com.github.tobato.fastdfs.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

@Component
public class FastDFSClient {
    private static Logger log = LoggerFactory.getLogger(FastDFSClient.class);
    private static FastFileStorageClient fastFileStorageClient;
    private static FdfsWebServer fdfsWebServer;

    @Autowired
    public void setFastDFSClient(FastFileStorageClient fastFileStorageClient, FdfsWebServer fdfsWebServer) {
        FastDFSClient.fastFileStorageClient = fastFileStorageClient;
        FastDFSClient.fdfsWebServer = fdfsWebServer;
    }

    /**
     * @param multipartFile 文件对象
     * @return 返回文件地址
     */
    public static String uploadFile(MultipartFile multipartFile) {
        try {
            StorePath storePath = fastFileStorageClient.uploadFile(
                multipartFile.getInputStream(),
                multipartFile.getSize(),
                FilenameUtils.getExtension(multipartFile.getOriginalFilename()),
                null);
            return storePath.getFullPath();
        } catch (IOException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    /**
     * @param multipartFile 图片对象
     * @return 返回图片地址
     */
    public static String uploadImageAndCrtThumbImage(MultipartFile multipartFile) {
        try {
            StorePath storePath = fastFileStorageClient.uploadImageAndCrtThumbImage(
                multipartFile.getInputStream(),
                multipartFile.getSize(),
                FilenameUtils.getExtension(multipartFile.getOriginalFilename()),
                null);
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public static String uploadFile(File file) {
        try {
            FileInputStream inputStream = new FileInputStream(file);
            StorePath storePath = fastFileStorageClient.uploadFile(
                inputStream,
                file.length(),
                FilenameUtils.getExtension(file.getName()),
                null);
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public static String uploadImageAndCrtThumbImage(File file) {
        try {
            FileInputStream inputStream = new FileInputStream(file);
            StorePath storePath = fastFileStorageClient.uploadImageAndCrtThumbImage(
                inputStream,
                file.length(),
                FilenameUtils.getExtension(file.getName()),
                null);
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public static String uploadFile(byte[] bytes, String fileExtension) {
        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
        StorePath storePath = fastFileStorageClient.uploadFile(stream, bytes.length, fileExtension, null);
        return storePath.getFullPath();
    }

    public static boolean downloadFile(String fileUrl, File file) {
        try {
            StorePath storePath = StorePath.praseFromUrl(fileUrl);
            byte[] bytes = fastFileStorageClient.downloadFile(
                storePath.getGroup(),
                storePath.getPath(),
                new DownloadByteArray());
            FileOutputStream stream = new FileOutputStream(file);
            stream.write(bytes);
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    public static boolean deleteFile(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            return false;
        }
        try {
            StorePath storePath = StorePath.praseFromUrl(fileUrl);
            fastFileStorageClient.deleteFile(storePath.getGroup(), storePath.getPath());
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    // 封装文件完整URL地址
    public static String getResAccessUrl(String path) {
        String url = fdfsWebServer.getWebServerUrl() + path;
        log.info("上传文件地址为:\n" + url);
        return url;
    }
}

6. Configure FastDFS in application.yml

# 分布式文件系统fastdfs配置
fdfs:
  # socket连接超时时长
  soTimeout: 1500
  # 连接tracker服务器超时时长
  connectTimeout: 600
  pool:
    # 从池中借出的对象的最大数目
    max-total: 153
    # 获取连接时的最大等待毫秒数
    max-wait-millis: 102
  # 缩略图生成参数,可选
  thumbImage:
    width: 150
    height: 150
  # tracker服务器列表
  trackerList:
    - 192.168.127.131:22122
  # storage服务器访问地址
  web-server-url: http://192.168.127.131/
  spring:
    http:
      multipart:
        max-file-size: 100MB  # 最大支持文件大小
        max-request-size: 100MB  # 最大支持请求大小

7. Write a simple JUnit test class to verify upload and delete operations

@RunWith(SpringRunner.class)
@SpringBootTest
public class FileClientApplicationTests {

    @Test
    public void Upload() {
        String fileUrl = this.getClass().getResource("/test.jpg").getPath();
        File file = new File(fileUrl);
        String str = FastDFSClient.uploadFile(file);
        FastDFSClient.getResAccessUrl(str);
    }

    @Test
    public void Delete() {
        FastDFSClient.deleteFile("group1/M00/00/00/rBEAClu8OiSAFbN_AAbhXQnXzvw031.jpg");
    }
}

Running the test class shows the uploaded file URL, which can be accessed directly via a browser, confirming that FastDFS has been successfully integrated with the Spring Boot application.

BackendJavaDockerSpring Bootdistributed-filesystemfastdfsfile storage
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.