SpringBoot整合FastDFS笔记
FastDFS是国人余庆开发的一个的分布式存储系统,github地址是https://github.com/happyfish100/fastdfs
FastDFS的特性:
1、分组存储,灵活简洁、对等结构,不存在单点
2、 文件ID由FastDFS生成,作为文件访问凭证。FastDFS不需要传统的name server
3、和流行的web server无缝衔接,FastDFS已提供apache和nginx扩展模块
4、大、中、小文件均可以很好支持,支持海量小文件存储
5、 支持多块磁盘,支持单盘数据恢复
6、 支持相同文件内容只保存一份,节省存储空间
7、 存储服务器上可以保存文件附加属性
8、 下载文件支持多线程方式,支持断点续传
FastDFS部署教程可以参考
https://www.jb51.net/article/251253.htm
springboot整合fastDFS的物料准备:
1.java项目配置fastdfs
2.定义工具类
3.测试使用效果
java项目配置fastdfs
引入fastdfs-client相关依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.8</version>
</dependency>
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.7</version>
</dependency>
配置项目yml文件
fdfs:
so-timeout: 5000 # 读取时间
connect-timeout: 5000 #连接超时
# 生成缩略图参数
thumb-image:
width: 50
height: 50
# 支持配置多个存储节点
tracker-list:
- 10.1.5.212:22122
启动类配置
package com.example.demo;
import com.github.tobato.fastdfs.FdfsClientConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@Import({FdfsClientConfig.class,cn.hutool.extra.spring.SpringUtil.class})
@MapperScan(basePackages = {"com.example.demo.orm.dao"})
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
定义fdfs工具类
package com.example.demo.util;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.StrUtil;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.charset.StandardCharsets;
@Component
@Slf4j
public class FdfsTools {
@Autowired
private FastFileStorageClient fastFileStorageClient;
/**
* 文件上传, byte 流类型
*
* @param bytes 文件字节
* @param fileSize 文件大小
* @param extension 文件扩展名
* @return fastDfs路径
*/
public String uploadFile(byte[] bytes, long fileSize, String extension) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
StorePath storePath = fastFileStorageClient.uploadFile(
byteArrayInputStream,
fileSize,
extension,
null);
return storePath.getFullPath();
}
/**
* MultipartFile类型的文件上传ַ
*
* @param file
* @return
* @throws IOException
*/
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = fastFileStorageClient.uploadFile(
file.getInputStream(),
file.getSize(),
FileNameUtil.getSuffix(file.getOriginalFilename()),
null);
return storePath.getFullPath();
}
/**
* 普通文件上传
*
* @param file
* @return
* @throws IOException
*/
public String uploadFile(File file) throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream(file);
StorePath path = fastFileStorageClient.uploadFile(
inputStream,
file.length(),
FileNameUtil.getSuffix(file),
null);
return path.getFullPath();
}
public String createFileAndUpload(String sourceFilePath) throws Exception {
File file = new File(sourceFilePath);
return uploadFile(file);
}
/**
* 带输入流形式的文件上传
*
* @param inputStream
* @param size
* @param fileName
* @return
*/
public String uploadFile(InputStream inputStream, long size, String fileName) {
StorePath path = fastFileStorageClient.uploadFile(inputStream, size, fileName, null);
return path.getFullPath();
}
/**
* 将一段文本文件写到fastdfs的服务器上
*
* @param content
* @param fileExtension
* @return
*/
public String uploadFile(String content, String fileExtension) {
byte[] buff = content.getBytes(StandardCharsets.UTF_8);
ByteArrayInputStream stream = new ByteArrayInputStream(buff);
StorePath path = fastFileStorageClient.uploadFile(stream, buff.length, fileExtension, null);
return path.getFullPath();
}
/**
* 下载文件
*
* @param fileUrl 文件URL
* @return 文件字节
*/
public byte[] downloadFile(String fileUrl) {
String group = fileUrl.substring(0, fileUrl.indexOf("/"));
String path = fileUrl.substring(fileUrl.indexOf("/") + 1);
DownloadByteArray downloadByteArray = new DownloadByteArray();
log.info("fdfs下载文件的group:{}",group);
log.info("fdfs下载文件的path:{}",path);
return fastFileStorageClient.downloadFile(group, path, downloadByteArray);
}
public void deleteFile(String fileUrl) {
if (StrUtil.isBlank(fileUrl)) {
return;
}
try {
StorePath storePath = StorePath.parseFromUrl(fileUrl);
fastFileStorageClient.deleteFile(storePath.getGroup(), storePath.getPath());
} catch (Exception e) {
log.error("", e);
}
}
}
测试使用效果
package com.example.demo;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import com.example.demo.util.FdfsTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
public class FdfsTestController {
@Autowired
private FdfsTools fdfsTools;
/**
* 下载fastdfs里的文件
* http://localhost:8621/mybatis/download?fullPath=group1/M00/64/AF/CgEF1GSSpkGACiJlAAvqH-Poukk892.jpg
* @param fullPath
* @param response
* @throws IOException
*/
@GetMapping("/download")
public void download(@RequestParam String fullPath, HttpServletResponse response) throws IOException {
byte[] bytes = fdfsTools.downloadFile(fullPath);
String name = FileNameUtil.getName(fullPath);
System.out.println(name);
response.setHeader("Content-Disposition",
"attachment;filename=" + new String(name.getBytes(), StandardCharsets.ISO_8859_1));
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
ServletOutputStream ops = response.getOutputStream();
IoUtil.copy(inputStream, ops);
IoUtil.closeIfPosible(inputStream);
IoUtil.closeIfPosible(ops);
}
/**
* 前端单文件上传 form-data形式参数, 传1个 MultipartFile类型,参数名file
* @param multipartFile
* @return
* @throws IOException
*/
@PostMapping("/uploadOne")
public String upload(@RequestPart("file") MultipartFile multipartFile) throws IOException {
System.out.println(multipartFile.getOriginalFilename());
String s = fdfsTools.uploadFile(multipartFile);
return "fullPath=" + s;
}
/**
* 前端多文件上传 form-data形式参数 传多个MultipartFile类型,参数名随意
* @param request
* @return
* @throws IOException
*/
@PostMapping("/uploadBatch")
public List<String> uploadBatch(MultipartHttpServletRequest request) throws IOException {
List<String> result = new ArrayList<>();
Map<String, MultipartFile> fileMap = request.getFileMap();
for (MultipartFile multipartFile : fileMap.values()) {
if (!multipartFile.isEmpty()){
System.err.println(multipartFile.getOriginalFilename());
String s = fdfsTools.uploadFile(multipartFile);
result.add("fullPath=" +s);
}
}
return result;
}
/**
* 将一段文本文件写到fastdfs的服务器上
* @param content
* @return fullPath=group1/M00/64/AF/CgEF1GSSqdGAHrO4AAAAD0mMR3c910.txt
*/
@PostMapping("/saveTxtToFdfs")
public String saveTxtToFdfs(@RequestParam String content){
String s = fdfsTools.uploadFile(content, "txt");
return "fullPath=" +s;
}
/**
* 删除FastDfs上的文件
* http://localhost:8621/mybatis/delFile?fullPath=group1/M00/64/AF/CgEF1GSSpnKAY3CiAAvea9v85c0615.jpg
* @param fullPath
* @return
*/
@DeleteMapping("/delFile")
public String deleteFastDfsFile(@RequestParam String fullPath){
fdfsTools.deleteFile(fullPath);
return "ok!";
}
}
测试上传单个文件
测试上传多个文件
测试删除FastDFS里已上传的文件