java应用整合fastdfs实现文件 上传及下载

java应用整合fastdfs实现文件 上传及下载

对于fastdfs的安装部署请参阅另一篇博文:fastdfs安装篇
本篇主要讲在springboot项目中如何整合fastdfs实现文件上传 下载 及删除,
项目demo gitee 地址:git clone https://gitee.com/JackSong2019/fastdfs_demo.git
整合方式有两种,一种是fastdfs官方提供的 fastdfs-client-java,
另一种是其它开发者基于原作者YuQing与yuqin发布的java客户端的基础上进行了大量的重构的开源项目 fastDFS_Client

一、基于官方提供的fastdfs-client-java方式集成

github地址:https://github.com/happyfish100/fastdfs-client-java

1、引入依赖

注意版本:引入的fastdfs-client-java需在和安装的fastdf server端版本对应,否则上传过程中会出现异常
我使用的fastdfs server 为6.06,引入的依赖为1.30

<dependency>
    <groupId>org.csource</groupId>
    <artifactId>fastdfs-client-java</artifactId>
    <version>1.30-SNAPSHOT</version>
</dependency>

注意:如果通过maven仓库下载失败,解决办法
第一种:使用maven从源码安装

mvn clean install

第二种:使用maven从jar文件安装 注意替换正确的版本号 version

mvn install:install-file -DgroupId=org.csource -DartifactId=fastdfs-client-java -Dversion=${version} -Dpackaging=jar -Dfile=fastdfs-client-java-${version}.jar

在这里插入图片描述

2、配置文件 可以用 .conf配置文件,也可用properties配置文件
2.1 .conf配置文件 、所在目录、加载优先顺序

配置文件名fdfs_client.conf(或使用其它文件名xxx_yyy.conf)

文件所在位置可以是项目classpath(或OS文件系统目录比如/opt/):
/opt/fdfs_client.conf
C:\Users\James\config\fdfs_client.conf

优先按OS文件系统路径读取,没有找到才查找项目classpath,尤其针对linux环境下的相对路径比如:
fdfs_client.conf
config/fdfs_client.conf

配置文件内容

注1:tracker_server指向您自己IP地址和端口,1-n个
注2:除了tracker_server,其它配置项都是可选的

connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = no
http.secret_key = FastDFS1234567890

tracker_server = 10.0.11.247:22122
tracker_server = 10.0.11.248:22122
tracker_server = 10.0.11.249:22122

connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 1000
2.2 .properties 配置文件、所在目录、加载优先顺序

配置文件名 fastdfs-client.properties(或使用其它文件名 xxx-yyy.properties)

文件所在位置可以是项目classpath(或OS文件系统目录比如/opt/):
/opt/fastdfs-client.properties
C:\Users\James\config\fastdfs-client.properties

优先按OS文件系统路径读取,没有找到才查找项目classpath,尤其针对linux环境下的相对路径比如:
fastdfs-client.properties
config/fastdfs-client.properties

注1:properties 配置文件中属性名跟 conf 配置文件不尽相同,并且统一加前缀"fastdfs.",便于整合到用户项目配置文件
注2:fastdfs.tracker_servers 配置项不能重复属性名,多个 tracker_server 用逗号","隔开
注3:除了fastdfs.tracker_servers,其它配置项都是可选的

fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80

fastdfs.tracker_servers = 10.0.11.201:22122,10.0.11.202:22122,10.0.11.203:22122

fastdfs.connection_pool.enabled = true
fastdfs.connection_pool.max_count_per_entry = 500
fastdfs.connection_pool.max_idle_time = 3600
fastdfs.connection_pool.max_wait_time_in_ms = 1000
3、加载配置
3.1 .conf配置文件加载
// 加载原 conf 格式文件配置  不同路径存储获取方式  选择合适的即可
ClientGlobal.init("fdfs_client.conf");
ClientGlobal.init("config/fdfs_client.conf");
ClientGlobal.init("/opt/fdfs_client.conf");
ClientGlobal.init("C:\\Users\\James\\config\\fdfs_client.conf");
3.2 .properties 配置文件加载
// 加载 properties 格式文件配置:
ClientGlobal.initByProperties("fastdfs-client.properties");
ClientGlobal.initByProperties("config/fastdfs-client.properties");
ClientGlobal.initByProperties("/opt/fastdfs-client.properties");
ClientGlobal.initByProperties("C:\\Users\\James\\config\\fastdfs-client.properties");

// 加载 Properties 对象配置:
Properties props = new Properties();
props.put(ClientGlobal.PROP_KEY_TRACKER_SERVERS, "10.0.11.101:22122,10.0.11.102:22122");
ClientGlobal.initByProperties(props);
3.3 字符串方式
// 加载 trackerServers 字符串配置:
String trackerServers = "10.0.11.101:22122,10.0.11.102:22122";
ClientGlobal.initByTrackers(trackerServers);
3.4 加载结果 查看
# 打印配置
System.out.println("ClientGlobal.configInfo(): " + ClientGlobal.configInfo());

# 控制台显示的打印结果
ClientGlobal.configInfo(): {
  g_connect_timeout(ms) = 5000
  g_network_timeout(ms) = 30000
  g_charset = UTF-8
  g_anti_steal_token = false
  g_secret_key = FastDFS1234567890
  g_tracker_http_port = 80
  g_connection_pool_enabled = true
  g_connection_pool_max_count_per_entry = 500
  g_connection_pool_max_idle_time(ms) = 3600000
  g_connection_pool_max_wait_time_in_ms(ms) = 1000
  trackerServers = 10.0.11.101:22122,10.0.11.102:22122
}
4、编写上传 下载 删除相关方法
package com.ydsz.util;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

public class FastdfsJavaClientUtil {

    /**
     * 获取tracker客户端
     * @return
     * @throws Exception
     */
    public static StorageClient initStorageClient() throws Exception {
        // 1、加载配置文件
        ClientGlobal.init("E:\\study\\fastdfs_demo\\src\\main\\resources\\fdfs_client.conf");
        // 2 创建一个trackerClient
        TrackerClient tracker = new TrackerClient();
        // 3 使用TrackerClient对象获取trackerServer对象
        TrackerServer trackerServer = tracker.getTrackerServer();
       // 4、创建一个StorageClient对象
        return new StorageClient(trackerServer);
    }

    /**
     * 关闭tracker
     * @param storageClient
     */
    public static void closeClient(StorageClient storageClient) {
        if(storageClient == null) return;
        try {
            storageClient.close();
        }catch (Exception e){
            e.printStackTrace();
        }catch (Throwable e){
            e.printStackTrace();
        }
    }
    
    /**
     * @param file 上传的文件
     * @throws Exception
     */
    public static String[] upload(MultipartFile file) throws Exception{
        InputStream inputStream = file.getInputStream();
        int length = inputStream.available();
        byte[] bytes = new byte[length];
        inputStream.read(bytes);
        NameValuePair[] metaList = new NameValuePair[1];
        metaList[0] = new NameValuePair("fileName", file.getOriginalFilename());
        StorageClient storageClient = initStorageClient();
        String[] result = storageClient.upload_file(bytes, null, metaList);
        closeClient(storageClient);
        return result;
    }


    /**
     * 下载文件
     * @param groupName storage名
     * @param fileKey   文件key
     * @param localFileName 下载到本地的文件名
     * @throws Exception
     */
    public static void download(String groupName,String fileKey,String localFileName) throws Exception {
        StorageClient storageClient = initStorageClient();
        storageClient.download_file(groupName, fileKey,localFileName);
        closeClient(storageClient);
    }

    /**
     * 下载文件
     * @param groupName storage名
     * @param fileKey   文件key
     * @throws Exception
     */
    public static byte[] download(String groupName,String fileKey) throws Exception {
        StorageClient storageClient = initStorageClient();
        byte[] bytes = storageClient.download_file(groupName, fileKey);
        closeClient(storageClient);
        return bytes;
    }


    /**
     * 删除文件
     * @param groupName  storage名
     * @param fileKey   文件key
     * @throws Exception
     */
    public static void delFile(String groupName,String fileKey) throws Exception {
        StorageClient storageClient = initStorageClient();
        storageClient.delete_file(groupName, fileKey);
        closeClient(storageClient);
    }
}

二、基于fastDFS_Client集成

github地址:https://github.com/tobato/FastDFS_Client
fastDFS_Client 是在原作者YuQing与yuqih发布的java客户端基础上进行了大量重构工作,便于Java工作者学习与阅读。
当前客户端单元测试全部通过,服务端版本是FastDFS_V5.07

主要特性

对关键部分代码加入了单元测试,便于理解与服务端的接口交易,提高接口质量
将以前对byte硬解析风格重构为使用 对象+注解 的形式,尽量增强了代码的可读性
支持对服务端的连接池管理(commons-pool2)
支持上传图片时候检查图片格式,并且自动生成缩略图
在SpringBoot当中自动导入依赖

1.在项目Pom当中加入依赖

Maven依赖为

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

在Maven当中配置依赖以后,SpringBoot项目将会自动导入FastDFS依赖
但注意 如果 是 1.26.4 以前的版本需要下面的方式引入

// 将FastDFS-Client客户端引入本地化项目的方式非常简单,
// 在SpringBoot项目/src/[com.xxx.主目录]/conf当中配置
/**
 * 导入FastDFS-Client组件
 * @author tobato
 *
 */
@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class ComponetImport {
    // 导入依赖组件
}
// 只需要一行注解 @Import(FdfsClientConfig.class)就可以拥有带有连接池的FastDFS Java客户端了
2、application.yml当中配置fdfs相关参数
# ===================================================================
# 分布式文件系统FDFS配置
# ===================================================================
fdfs:
  so-timeout: 1501
  connect-timeout: 601 
  thumb-image:             #缩略图生成参数
    width: 150
    height: 150
  tracker-list:            #TrackerList参数,支持多个
    - 192.168.1.105:22122
    - 192.168.1.106:22122 
  pool:
  #从池中借出的对象的最大数目(配置为-1表示不限制)
  max-total: -1
  #获取连接时的最大等待毫秒数(默认配置为5秒)
  max-wait-millis: 5000
  #每个key最大连接数
  max-total-per-key: 50
  #每个key对应的连接池最大空闲连接数
  max-idle-per-key: 10
  #每个key对应的连接池最小空闲连接数
  min-idle-per-key: 5

其中pool部分为连接池的管理参数
应用启动后拥有两个连接池管理对象:
Tracker连接池(TrackerConnectionManager)
Storage连接池(FdfsConnectionManager)
必要的时候可以注入这两个对象,跟踪打印并分析连接池的情况

3、使用接口服务对Fdfs服务端进行操作
3.1 接口说明

主要接口包括
TrackerClient - TrackerServer接口
GenerateStorageClient - 一般文件存储接口 (StorageServer接口)
FastFileStorageClient - 为方便项目开发集成的简单接口(StorageServer接口)
AppendFileStorageClient - 支持文件续传操作的接口 (StorageServer接口)

3.4 代码示例
package com.ydsz.controller;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.domain.upload.FastFile;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.ydsz.util.FastdfsJavaClientUtil;
import org.apache.commons.lang3.StringUtils;
import org.csource.fastdfs.StorageServer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("/fastdfs")
public class FileClientController {

    @Resource
    FastFileStorageClient fastFileStorageClient;

	// 自己服务器ip+端口
    private String baseUrl ="http://127.0.0.1:80/";

    /**
     * 文件上传
     * @param file
     * @return
     * @throws Exception
     */
    @PostMapping("/upload")
    public String upload(MultipartFile file) throws Exception {
        StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(),
                file.getSize(),
                StringUtils.substringAfterLast(file.getOriginalFilename(), "."),
                null);
        return baseUrl + storePath.getFullPath();
    }

    /**
     * @param groupName
     * @param fileKey
     * @param response
     * @throws Exception
     */
    @PostMapping("/download")
    public void download(String groupName, String fileKey, HttpServletResponse response) throws Exception {
        byte[] download = fastFileStorageClient.downloadFile(groupName, fileKey, new DownloadByteArray());
        // 将download以流的方式返回
        response.getOutputStream().write(download);
    }

    /**
     * 删除文件
     * @param filePath 文件的完整路径
     */
    @PostMapping("/delete")
    public void delFile(String filePath)  {
        fastFileStorageClient.deleteFile(filePath);
    }
}

4、上传文件大小配置 当上传较大文件时 可能会存在异常情况 增加以下配置即可解决
package com.ydsz.config;

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;

import javax.servlet.MultipartConfigElement;

@Configuration
public class FileConfig {

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        //单个文件最大  50MB
        factory.setMaxFileSize(DataSize.ofBytes(50 * 1024 *1024));
        /// 设置总上传数据总大小 200MB
        factory.setMaxRequestSize(DataSize.ofBytes(200 * 1024 *1024));
        return factory.createMultipartConfig();
    }
}

项目demo gitee 地址:git clone https://gitee.com/JackSong2019/fastdfs_demo.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/447402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++第一弹---C++入门(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 【C详解】 C入门 1、C关键字(C98) 2、命名空间 2.1、命名空间定义 2.2、命名空间使用 3、C输入&输出 4、缺省参数 4.1、缺省参数概念 4.2、缺省参…

酷开科技利用自身优势量身定制个性化营销创意

随着人工智能、大数据、物联网、区块链等技术的发展&#xff0c;去中心化、碎片化、社交化、全链条可追踪的趋势将越来越明显。广告主对于投放的每一分钱都会有更高性价比、更精准效果的追求。业精于专成于势&#xff0c;酷开系统专注构建开放统一的超级智能系统生态&#xff0…

【题解】—— LeetCode一周小结10

【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结9 4.用栈实现队列 题目链接&#xff1a;232. 用栈实现队列 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a…

spring boot集成neo4j实现简单的知识图谱

一、neo4j介绍 随着社交、电商、金融、零售、物联网等行业的快速发展&#xff0c;现实社会织起了了一张庞大而复杂的关系网&#xff0c;传统数据库很难处理关系运算。大数据行业需要处理的数据之间的关系随数据量呈几何级数增长&#xff0c;急需一种支持海量复杂数据关系运算的…

每日OJ题_链表⑤_力扣25. K 个一组翻转链表

目录 力扣25. K 个一组翻转链表 解析代码 力扣25. K 个一组翻转链表 25. K 个一组翻转链表 难度 困难 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总…

java集合类常用的方法介绍

在 Java 中&#xff0c;集合&#xff08;Collections&#xff09;是用于存储多个元素的容器。Java Collections Framework 提供了丰富的集合类&#xff0c;用于满足不同的数据存储需求。以下是一些常用的 Java 集合类及其常用方法&#xff0c;以及简单的例子来说明它们的用法。…

AI 对齐是未来十年最重要的科学和社会技术工程 | 新程序员

【导读】人工智能与机器学习技术犹如疾风骤雨般席卷全球&#xff0c;在颠覆传统的同时为人类带来了新一轮的伦理挑战。AI 模型虽能凭借强大的数据处理能力和优化效率在各个行业大放异彩&#xff0c;然而在追求极致准确性的模型行为背后&#xff0c;却存在与其设计初衷产生偏差的…

2024-03-10 c++

&#x1f338; MFC下拉框控件 | Combo Box eg 计算器 1。新建MFC项目&#xff08;基于对话框、静态库&#xff09; 2。添加控件&#xff0c;删除初始的3个多余控件 加3个edit control 加1个combo box&#xff0c;属性sort改为false&#xff0c;data为 ;-;;;% 加1个static text…

【数据结构】红黑树(C++实现)

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.概念 2.性质 3.…

企业微信HOOK协议,新设备二次验证处理

提示设备强制二次验证问题已处理 HOOK&#xff1a;https://www.showdoc.com.cn/1663062930779972/7859611259700402密码&#xff1a;999999999

蓝桥杯练习系统(算法训练)ALGO-979 移动

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 给定一个n长的数列&#xff0c;有m次操作&#xff0c;第i次操作表示将整个数列循环移动mi位&#xff0c;询问每次操作结束后…

前端解决跨域问题( 6种方法 )

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

【MATLAB源码-第160期】基于matlab的胡桃夹子优化算法(NOA)无人机三维路径规划,输出做短路径图和适应度曲线

操作环境&#xff1a; MATLAB 2022a 1、算法描述 胡桃夹子优化算法&#xff08;Nutcracker Optimization Algorithm, NOA&#xff09;是一个灵感来源于胡桃夹子的故事的元启发式优化算法。这个故事中&#xff0c;胡桃夹子是一个能够将坚果壳轻易地破开以获取内部果仁的工具。…

linux系统adb调试工具

adb的全称为Android Debug Bridge&#xff0c;就是起到调试桥的作用。通过adb可以在Eclipse中通过DDMS来调试Android程序&#xff0c;说白了就是调试工具。 adb的工作方式比较特殊&#xff0c;采用监听Socket TCP 5554等端口的方式让IDE和Qemu通讯&#xff0c;默认情况下adb会…

Rust接收命令行参数和新建文件读写和追加操作与IO

接收命令行参数 命令行程序是计算机程序最基础的存在形式&#xff0c;几乎所有的操作系统都支持命令行程序并将可视化程序的运行基于命令行机制。 命令行程序必须能够接收来自命令行环境的参数&#xff0c;这些参数往往在一条命令行的命令之后以空格符分隔。 在很多语言中&a…

145.乐理基础-增三和弦、减三和弦

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;144.根三五音、大三和弦、小三和弦 上一个内容里练习的答案&#xff1a; 增三和弦与减三和弦的结构 增三和弦例子&#xff1a; 下图红框里的乐谱是c、e、升g&#xff0c;这个和弦&#xff0c;c-e是大三度&#xff…

_note_06

1.说一说函数的按地址传递和按值传递&#xff0c;他们的区别是什么&#xff1f; 函数的参数传递方式可以分为按地址传递&#xff08;也称为按引用传递&#xff09;和按值传递两种方式。按值传递是指将实际参数的值复制给形式参数&#xff0c;即在函数调用时&#xff0c;实际参数…

Ps:画笔工具

画笔工具 Brush Tool是 Photoshop 中最常用的工具&#xff0c;可广泛地用于绘画与修饰工作之中。 快捷键&#xff1a;B ◆ ◆ ◆ 常用操作方法与技巧 1、熟练掌握画笔工具的操作对于使用其他工具也非常有益&#xff0c;因为 Photoshop 中许多与笔刷相关的工具有类似的选项和操…

Nestjs与Vue实现多人聊天[简易版]

本项目是一个小demo,帮助各位理清一点开发思路&#xff0c;作为一个小参考&#xff0c;虽然技术栈是nodejs。但是其他语言也是相通的。 准备环境&#xff1a; Nodejs version >18.13.0Vue3Nestjssoket.io 一、初始化 打开一个路径启动cmd窗口&#xff0c;初始化前后端项…