一、搭建FastDFS服务
搭建参考以下文章:
第一篇:FastDFS详细介绍 https://blog.csdn.net/m0_37797991/article/details/73381648
第二篇:FastDFS搭建 https://blog.csdn.net/m0_37797991/article/details/73381739
第三篇:FastDFS整合Nginx https://blog.csdn.net/m0_37797991/article/details/73385161
第四篇:FastDFS整合SpringMvc实现上传 https://blog.csdn.net/m0_37797991/article/details/73394873
因为现在最流行的是springboot,所以我们在这次的例子中采用springboot来整合FastDFS
常用命令:
上传文件:/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /www/wwwroot/image/1.jpg
启动storage_nginx:/usr/local/nginx2/sbin/nginx
启动tracker_nginx:/usr/local/nginx/sbin/nginx
启动tracker:service fdfs_trackerd start(创建软连接后)
启动storage:service fdfs_storaged start(创建软连接后:ln -s /usr/bin/fdfs_storaged /usr/local/bin)
查看storage是否注册到了tracker中:/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
二、具体的代码
配置:
#fastdfs配置
fdfs.connect-timeout=600
fdfs.so-timeout=1500
fdfs.trackerList[0]=60.205.229.111:22122
fdfs.thumbImage.height=150
fdfs.thumbImage.width=150
spring.jmx.enabled=false
fdfs.pool.max-total=200
配置类:
package com.zym.fdfs.config;
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;
@Configuration
@Import(FdfsClientConfig.class)//导入client
@EnableMBeanExport(registration= RegistrationPolicy.IGNORE_EXISTING)
public class FastClient {//类名无特定限制
}
工具类:
package com.zym.fdfs.util;
import cn.hutool.core.codec.Base64;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadFileStream;
import com.github.tobato.fastdfs.domain.upload.FastFile;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class FastFileUtil {
@Autowired
private FastFileStorageClient fastFileStorageClient;
/**
* 定义GB的计算常量
*/
private static final int GB = 1024 * 1024 * 1024;
/**
* 定义MB的计算常量
*/
private static final int MB = 1024 * 1024;
/**
* 定义KB的计算常量
*/
private static final int KB = 1024;
/**
* 格式化小数
*/
private static final DecimalFormat DF = new DecimalFormat("0.00");
/**
* MultipartFile转FastFile
*/
public static FastFile toFastFile(MultipartFile multipartFile, FileGroup fileGroup) {
// 获取文件名
FastFile file = null;
try {
// MultipartFile to FastFile
file = new FastFile.Builder()
.withFile(multipartFile.getInputStream()
,multipartFile.getSize()
,multipartFile.getOriginalFilename())
.toGroup(fileGroup.getGroup())
.build();
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
public StorePath uploadFastFile(MultipartFile multipartFile, FileGroup fileGroup){
FastFile file = null;
StorePath storePath = null;
try {
// MultipartFile to FastFile
file = new FastFile.Builder()
.withFile(multipartFile.getInputStream()
,multipartFile.getSize()
,getExtensionName(multipartFile.getOriginalFilename()))
.toGroup(fileGroup.getGroup())
.build();
storePath = fastFileStorageClient.uploadFile(file);
} catch (IOException e) {
e.printStackTrace();
}
return storePath;
}
/**
* 获取文件扩展名,不带 .
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot >-1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* Java文件操作 获取不带扩展名的文件名
*/
public static String getFileNameNoEx(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot >-1) && (dot < (filename.length()))) {
return filename.substring(0, dot);
}
}
return filename;
}
/**
* 文件大小转换
*/
public static String getSize(long size){
String resultSize;
if (size / GB >= 1) {
//如果当前Byte的值大于等于1GB
resultSize = DF.format(size / (float) GB) + "GB ";
} else if (size / MB >= 1) {
//如果当前Byte的值大于等于1MB
resultSize = DF.format(size / (float) MB) + "MB ";
} else if (size / KB >= 1) {
//如果当前Byte的值大于等于1KB
resultSize = DF.format(size / (float) KB) + "KB ";
} else {
resultSize = size + "B ";
}
return resultSize;
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String name = getFileNameNoEx(file.getOriginalFilename());
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = "-" + format.format(date);
try {
String fileName = name + nowStr + "." + suffix;
String path = filePath + fileName;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String fileToBase64(File file) throws Exception {
FileInputStream inputFile = new FileInputStream(file);
String base64;
byte[] buffer = new byte[(int)file.length()];
inputFile.read(buffer);
inputFile.close();
base64= Base64.encode(buffer);
return base64.replaceAll("[\\s*\t\n\r]", "");
}
public static String getFileType(String type) {
String documents = "txt doc pdf ppt pps xlsx xls docx";
String music = "mp3 wav wma mpa ram ra aac aif m4a";
String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
if(image.contains(type)){
return "图片";
} else if(documents.contains(type)){
return "文档";
} else if(music.contains(type)){
return "音乐";
} else if(video.contains(type)){
return "视频";
} else {
return "其他";
}
}
public static String getFileTypeByMimeType(String type) {
String mimeType = new MimetypesFileTypeMap().getContentType("." + type);
return mimeType.split("/")[0];
}
public static void checkSize(long maxSize, long size) throws Exception {
// 1M
int len = 1024 * 1024;
if(size > (maxSize * len)){
throw new Exception("文件超出规定大小");
}
}
private static String getMd5(byte[] bytes) {
// 16进制字符
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(bytes);
byte[] md = mdTemp.digest();
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
// 移位 输出字符串
for (byte byte0 : md) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 下载文件
* @param request /
* @param response /
* @param path /
*/
public void downloadFile(HttpServletRequest request, HttpServletResponse response, String path){
response.setHeader("Content-Disposition", "attachment; filename="+getFileName(path));
response.setCharacterEncoding(request.getCharacterEncoding());
response.setContentType("application/octet-stream");
DownloadFileStream downloadCallback = null;
try {
downloadCallback = new DownloadFileStream(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
StorePath storePath = StorePath.parseFromUrl(path);
fastFileStorageClient.downloadFile(storePath.getGroup(),storePath.getPath(),downloadCallback);
try {
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
}
// 删除文件
public void deleteFile(String path){
fastFileStorageClient.deleteFile(path);
}
/**
* 文件路径获取文件名
*/
public static String getFileName(String filePath) {
if ((filePath != null) && (filePath.length() > 0)) {
int dot = filePath.lastIndexOf('/');
if ((dot >-1) && (dot < (filePath.length() - 1))) {
return filePath.substring(dot + 1);
}
}
return filePath;
}
}
controller:
package com.zym.fdfs.controller;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.zym.fdfs.util.FastFileUtil;
import com.zym.fdfs.util.FileGroup;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@Api(tags = "FastDFS测试")
@RestController
@RequestMapping("/api/fastdfs")
public class FileController {
@Autowired
private FastFileUtil fastFileUtil;
@ResponseBody
@ApiOperation(value = "上传文件",httpMethod = "POST")
@PostMapping("/upload")
public String uploadFile(@ApiParam("文件") MultipartFile file) throws IOException {
StorePath storePath = fastFileUtil.uploadFastFile(file,FileGroup.AVATAR);
return "文件上传成功,存储地址为:"+storePath.getFullPath();
}
}
启动项目进行测试:
用swagger模拟上传文件,上传该图片:
用服务器的ip加上该地址去查看图片:
至此,简单的FastDFS与springboot的整合就完成了
源码地址:https://gitee.com/zym213/springboot_fastdfs.git