一、搭建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=600fdfs.so-timeout=1500fdfs.trackerList[0]=60.205.229.111:22122fdfs.thumbImage.height=150fdfs.thumbImage.width=150spring.jmx.enabled=falsefdfs.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;@Componentpublic class FastFileUtil {@Autowiredprivate 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 FastFilefile = 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 FastFilefile = 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的值大于等于1GBresultSize = DF.format(size / (float) GB) + "GB ";} else if (size / MB >= 1) {//如果当前Byte的值大于等于1MBresultSize = DF.format(size / (float) MB) + "MB ";} else if (size / KB >= 1) {//如果当前Byte的值大于等于1KBresultSize = 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 {// 1Mint 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 {@Autowiredprivate 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
