杰瑞科技汇

fastdfs java api

Of course! Here is a comprehensive guide to using the Java API for FastDFS, covering the concepts, setup, code examples, and best practices.

fastdfs java api-图1
(图片来源网络,侵删)

What is FastDFS?

FastDFS is an open-source, high-performance, lightweight, and distributed file storage system. It's designed to handle a massive number of files, such as those used in websites, apps, and large-scale systems.

Key Features:

  • Lightweight: Small codebase, low resource consumption.
  • High Performance: Uses a simple communication protocol (TCP) and binary data for high-speed transfers.
  • Distributed Architecture: Consists of two main roles:
    • Tracker Server (Tracker): Acts as a load balancer and scheduler. It manages the storage nodes (groups) and directs client requests to the appropriate Storage Server.
    • Storage Server (Storage): Actually stores the files. Files are organized into groups, and each Storage Server in a group stores the same files for redundancy.
  • Easy Integration: Provides simple APIs for various languages, including Java.

Java API Library: fastdfs-client-java

The most popular and widely used Java client library for FastDFS is fastdfs-client-java, originally developed by tobegit. It's the de-facto standard for Java integration.

You can find it on Maven Central.

fastdfs java api-图2
(图片来源网络,侵删)

Setup and Configuration

Step 1: Add Dependency

Add the fastdfs-client-java dependency to your pom.xml:

<dependency>
    <groupId>org.csource</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.27.0.0</version> <!-- Check for the latest version -->
</dependency>

Step 2: Prepare the FastDFS Configuration File

The Java client needs a configuration file to know how to connect to the Tracker Server. Create a file named fdfs_client.conf in your project's classpath (e.g., src/main/resources).

fdfs_client.conf content:

# The connect timeout for tracker server in seconds, default value is 30s
connect_timeout_in_second = 10
# The network timeout for tracker and storage server in seconds, default value is 30s
network_timeout_in_second = 30
# The charset for file name, default value is UTF-8
charset = UTF-8
# The tracker server address, format: IP:PORT
# You can specify multiple trackers for high availability, separated by a space or newline
tracker_server = 192.168.1.10:22122
# tracker_server = 192.168.1.11:22122 # For HA

Core Java Code Examples

First, you need a ClientGlobal instance that is initialized with your configuration file. This is a heavy object and should be initialized only once when your application starts.

fastdfs java api-图3
(图片来源网络,侵删)
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import java.io.File;
import java.io.IOException;
public class FastDFSExample {
    public static void main(String[] args) {
        try {
            // 1. Initialize the client
            String trackerConfig = "fdfs_client.conf";
            ClientGlobal.init(trackerConfig);
            System.out.println("ClientGlobal initialized successfully.");
            // 2. Create a TrackerClient
            TrackerClient trackerClient = new TrackerClient();
            // 3. Create a TrackerServer connection
            TrackerServer trackerServer = trackerClient.getConnection();
            // 4. Create a StorageServer (can be null, the client will find it automatically)
            StorageServer storageServer = null;
            // 5. Create a StorageClient
            // This client is used for all file operations (upload, download, delete)
            StorageClient storageClient = new StorageClient(trackerServer, storageServer);
            // --- Upload Example ---
            uploadFile(storageClient);
            // --- Download Example ---
            downloadFile(storageClient);
            // --- Delete Example ---
            deleteFile(storageClient);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // ... other methods will be defined below ...
}

A. Upload a File

Uploading is the most common operation. You get a file ID (like group/M00/00/00/xxx.ext) back, which you can store in your database.

public static void uploadFile(StorageClient storageClient) throws IOException, MyException {
    System.out.println("\n--- Uploading File ---");
    // File path to upload
    String localFile = "path/to/your/local/file.txt";
    // Metadata (optional)
    NameValuePair[] metaList = new NameValuePair[2];
    metaList[0] = new NameValuePair("author", "John Doe");
    metaList[1] = new NameValuePair("description", "A test file for FastDFS");
    // Upload the file
    // The uploadFile method returns an array of two strings:
    // [0] = group name (e.g., "group1")
    // [1] = file remote name (e.g., "M00/00/00/wKjRhF0x0zGAaXvSAAAAADuP6lU123.txt")
    String[] fileIds = storageClient.upload_file(localFile, "txt", metaList);
    if (fileIds == null) {
        System.err.println("File upload failed!");
        return;
    }
    String groupName = fileIds[0];
    String remoteFileName = fileIds[1];
    String fileId = groupName + "/" + remoteFileName;
    System.out.println("File uploaded successfully!");
    System.out.println("Group: " + groupName);
    System.out.println("Remote File Name: " + remoteFileName);
    System.out.println("Full File ID: " + fileId);
}

B. Download a File

To download, you need the group name and remote file name that you got from the upload.

public static void downloadFile(StorageClient storageClient) throws IOException, MyException {
    System.out.println("\n--- Downloading File ---");
    // Use the group and remote file name from the upload example
    String groupName = "group1"; 
    String remoteFileName = "M00/00/00/wKjRhF0x0zGAaXvSAAAAADuP6lU123.txt";
    // Local path to save the downloaded file
    String localSavePath = "path/to/your/downloaded/file_downloaded.txt";
    // Download the file
    int result = storageClient.download_file(groupName, remoteFileName, localSavePath);
    if (result == 0) {
        System.out.println("File downloaded successfully to: " + localSavePath);
    } else {
        System.err.println("File download failed with code: " + result);
    }
}

C. Delete a File

Deleting also requires the group name and remote file name.

public static void deleteFile(StorageClient storageClient) throws IOException, MyException {
    System.out.println("\n--- Deleting File ---");
    // Use the group and remote file name from the upload example
    String groupName = "group1";
    String remoteFileName = "M00/00/00/wKjRhF0x0zGAaXvSAAAAADuP6lU123.txt";
    // Delete the file
    int result = storageClient.delete_file(groupName, remoteFileName);
    if (result == 0) {
        System.out.println("File deleted successfully.");
    } else {
        System.err.println("File deletion failed with code: " + result);
    }
}

Best Practices and Important Considerations

Connection Pooling (CRITICAL)

Creating TrackerServer and StorageClient objects involves establishing network connections. Doing this for every single file operation is extremely inefficient and will quickly exhaust system resources.

Solution: Use a connection pool. The fastdfs-client-java library provides a simple FastDfsConnectionPool.

How to implement a pool:

import org.csource.fastdfs.TrackerServer;
import org.csource.fastdfs.Pool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class FastDfsConnectionPool {
    private BlockingQueue<TrackerServer> pool;
    public FastDfsConnectionPool(int poolSize) {
        this.pool = new ArrayBlockingQueue<>(poolSize);
        // Initialize the pool with connections
        for (int i = 0; i < poolSize; i++) {
            try {
                TrackerClient trackerClient = new TrackerClient();
                TrackerServer trackerServer = trackerClient.getConnection();
                this.pool.put(trackerServer);
            } catch (Exception e) {
                // Handle exception
                e.printStackTrace();
            }
        }
    }
    public TrackerServer borrowObject() throws InterruptedException {
        return this.pool.take();
    }
    public void returnObject(TrackerServer trackerServer) {
        if (trackerServer != null) {
            this.pool.offer(trackerServer);
        }
    }
}

Refactored Usage with a Pool:

// In your application startup class
FastDfsConnectionPool pool = new FastDfsConnectionPool(10); // Pool of 10 connections
// When you need a client
TrackerServer trackerServer = pool.borrowObject();
StorageClient storageClient = new StorageClient(trackerServer, null);
try {
    // Use the client for upload/download/delete
    uploadFile(storageClient);
} finally {
    // IMPORTANT: Always return the connection to the pool
    pool.returnObject(trackerServer);
}

Storing File IDs

The file ID returned by FastDFS (e.g., group1/M00/00/00/xxx.ext) is the key to retrieving your file. You must store this ID in your database (e.g., in a files table) and associate it with your application's data (e.g., a user's avatar, a product image).

Configuration Management

Hardcoding paths like fdfs_client.conf is bad practice. Load it from a configurable location, such as:

  • An environment variable.
  • A configuration server (like Spring Cloud Config).
  • Your application's application.properties/application.yml file.

Error Handling

Always handle IOException and MyException. Check the return codes of methods like download_file and delete_file to ensure the operation was successful.


Modern Integration: Spring Boot Example

Here's how you might integrate this into a Spring Boot application.

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.csource</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>1.27.0.0</version>
    </dependency>
</dependencies>

application.properties

# FastDFS Config
fastdfs.tracker-server=192.168.1.10:22122
fastdfs.connect-timeout=10
fastdfs.network-timeout=30
fastdfs.charset=UTF-8
fastdfs.pool-size=20

FastDFSConfig.java

import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.TrackerClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
@Configuration
@EnableConfigurationProperties(FastDFSProperties.class)
public class FastDFSConfig {
    private final FastDFSProperties properties;
    public FastDFSConfig(FastDFSProperties properties) {
        this.properties = properties;
    }
    @PostConstruct
    public void init() throws IOException {
        // Manually load properties and initialize ClientGlobal
        // A more robust way is to create a conf file on the fly or use a custom ConfigParser
        System.setProperty("fastdfs.connect_timeout_in_second", String.valueOf(properties.getConnectTimeout()));
        System.setProperty("fastdfs.network_timeout_in_second", String.valueOf(properties.getNetworkTimeout()));
        System.setProperty("fastdfs.charset", properties.getCharset());
        ClientGlobal.init(properties.getTrackerServer());
    }
    @Bean
    public TrackerClient trackerClient() {
        return new TrackerClient();
    }
}

FastDFSProperties.java (for @EnableConfigurationProperties)

import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "fastdfs")
public class FastDFSProperties {
    private String trackerServer;
    private int connectTimeout = 10;
    private int networkTimeout = 30;
    private String charset = "UTF-8";
    private int poolSize = 20;
    // Getters and Setters
    public String getTrackerServer() { return trackerServer; }
    public void setTrackerServer(String trackerServer) { this.trackerServer = trackerServer; }
    public int getConnectTimeout() { return connectTimeout; }
    public void setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; }
    public int getNetworkTimeout() { return networkTimeout; }
    public void setNetworkTimeout(int networkTimeout) { this.networkTimeout = networkTimeout; }
    public String getCharset() { return charset; }
    public void setCharset(String charset) { this.charset = charset; }
    public int getPoolSize() { return poolSize; }
    public void setPoolSize(int poolSize) { this.poolSize = poolSize; }
}

FastDFSUploadService.java

import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@Service
public class FastDFSUploadService {
    private final TrackerClient trackerClient;
    private final FastDfsConnectionPool pool; // Your custom connection pool bean
    public FastDFSUploadService(TrackerClient trackerClient, FastDfsConnectionPool pool) {
        this.trackerClient = trackerClient;
        this.pool = pool;
    }
    public String uploadFile(MultipartFile file) throws IOException {
        String fileId = null;
        TrackerServer trackerServer = null;
        try {
            trackerServer = pool.borrowObject();
            StorageClient storageClient = new StorageClient(trackerServer, null);
            byte[] fileBytes = file.getBytes();
            String originalFilename = file.getOriginalFilename();
            String fileExtName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            String[] ids = storageClient.upload_file(fileBytes, fileExtName, null);
            if (ids != null) {
                fileId = ids[0] + "/" + ids[1];
            }
        } catch (Exception e) {
            throw new IOException("Failed to upload file to FastDFS", e);
        } finally {
            if (trackerServer != null) {
                pool.returnObject(trackerServer);
            }
        }
        return fileId;
    }
}

This guide provides a solid foundation for working with FastDFS in a Java application. Remember to prioritize connection pooling for any production-level system.

分享:
扫描分享到社交APP
上一篇
下一篇