Java实现Fast DFS、服务器、OSS上传

金歌  金牌会员 | 2024-5-16 17:01:08 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 928|帖子 928|积分 2784

支持Fast DFS、服务器、OSS等上传方式
先容

在实际的业务中,可以根据客户的需求设置差别的文件上传需求,支持普通服务器上传+分布式上传(Fast DFS)+云服务上传OSS(OSS)
软件架构

为了方便演示使用,本项目使用的是前后端不分离的架构
前端:Jquery.uploadFile
后端:SpringBoot
前期准备:FastDFS、OSS(华为)、服务器
实现逻辑

通过 application 配置对上传文件举行一个自定义配置,从而摆设在差别客户环境可以自定义选择方式。
优点:

  • 一键切换;
  • 支持当前主流方式;
缺点:

  • 迁移数据难度增长:因为体现FileID在对象存储和服务器上传都是天生的UUID,而FastDFS是返回存取ID,当需要迁移的时间,通过脚本可以快速将FastDFS的数据迁移上云,因为存储ID可以共用。但是对象存储和服务器上传的UUID无法被FastDFS使用,增长迁移成本
核心代码
  1. package com.example.file.util;
  2. import com.example.file.common.ResultBean;
  3. import com.github.tobato.fastdfs.domain.StorePath;
  4. import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;
  5. import com.github.tobato.fastdfs.service.FastFileStorageClient;
  6. import com.obs.services.ObsClient;
  7. import com.obs.services.exception.ObsException;
  8. import com.obs.services.model.DeleteObjectRequest;
  9. import com.obs.services.model.GetObjectRequest;
  10. import com.obs.services.model.ObsObject;
  11. import com.obs.services.model.PutObjectResult;
  12. import io.micrometer.common.util.StringUtils;
  13. import jakarta.servlet.http.HttpServletResponse;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.mock.web.MockMultipartFile;
  16. import org.springframework.web.multipart.MultipartFile;
  17. import java.io.*;
  18. import java.util.Objects;
  19. import java.util.UUID;
  20. @Slf4j
  21. public class FileUtil {
  22.     /**
  23.      *
  24.      * @param file 文件
  25.      * @param uploadFlag 标识
  26.      * @param uploadPath 上传路径
  27.      * @param endPoint 域名
  28.      * @param ak    ak
  29.      * @param sk sk
  30.      * @param bucketName 桶名字
  31.      * @return fileId 用于下载
  32.      */
  33.     public static ResultBean uploadFile(MultipartFile file, String uploadFlag, String uploadPath,
  34.                                         FastFileStorageClient fastFileStorageClient,
  35.                                         String endPoint, String ak, String sk,
  36.                                         String bucketName) {
  37.         if (StringUtils.isBlank(uploadFlag)){
  38.             ResultBean.error("uploadFlag is null");
  39.         }
  40.         switch (uploadFlag){
  41.             case "fastDFS":
  42.                 return uploadFileByFastDFS(file,fastFileStorageClient);
  43.             case "huaweiOOS":
  44.                 return uploadFileByHuaweiObject(file, endPoint, ak, ak, bucketName);
  45.             case "server":
  46.             default:
  47.                 return uploadFileByOrigin(file,uploadPath);
  48.         }}
  49.     /**
  50.      * 上传文件fastDFS
  51.      * @param file 文件名
  52.      * @return
  53.      */
  54.     private static ResultBean uploadFileByFastDFS(MultipartFile file,FastFileStorageClient fastFileStorageClient){
  55.         Long size=file.getSize();
  56.         String fileName=file.getOriginalFilename();
  57.         String extName=fileName.substring(fileName.lastIndexOf(".")+1);
  58.         InputStream inputStream=null;
  59.         try {
  60.             inputStream=file.getInputStream();
  61.             //1-上传的文件流 2-文件的大小 3-文件的后缀 4-可以不管他
  62.             StorePath storePath=fastFileStorageClient.uploadFile(inputStream,size,extName,null);
  63.             log.info("[uploadFileByFastDFS][FullPath]"+storePath.getFullPath());
  64.             return ResultBean.success(storePath.getPath());
  65.         }catch (Exception e){
  66.             log.info("[ERROR][uploadFileByFastDFS]"+e.getMessage());
  67.             return ResultBean.error(e.getMessage());
  68.         }finally {
  69.             if (inputStream != null) {
  70.                 try {
  71.                     inputStream.close();
  72.                 } catch (IOException e) {
  73.                     e.printStackTrace();
  74.                 }
  75.             }
  76.         }
  77.     }
  78.     /**
  79.      * 对象存储上传
  80.      * @param file 文件名
  81.      * @return
  82.      */
  83.     private static ResultBean uploadFileByHuaweiObject(MultipartFile file, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk,
  84.                                                    String bucketName){
  85.         String fileName = file.getOriginalFilename();
  86.         fileName = renameToUUID(fileName);
  87.         InputStream inputStream=null;
  88.         try {
  89.             inputStream=file.getInputStream();
  90.             // 创建ObsClient实例
  91.             ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint);
  92.             PutObjectResult result = obsClient.putObject(bucketName, fileName, inputStream);
  93.             obsClient.close();
  94.             return ResultBean.success(fileName);
  95.         }catch (ObsException e){
  96.             log.info("[ERROR][uploadFileByHuaweiObject]"+e.getErrorMessage());
  97.             return ResultBean.error(e.getErrorMessage());
  98.         }catch (Exception e){
  99.             log.info("[ERROR][uploadFileByHuaweiObject]"+e.getMessage());
  100.             return ResultBean.error(e.getMessage());
  101.         }finally {
  102.             if (inputStream != null) {
  103.                 try {
  104.                     inputStream.close();
  105.                 } catch (IOException e) {
  106.                     e.printStackTrace();
  107.                 }
  108.             }
  109.         }
  110.     }
  111.     /**
  112.      * 上传文件原本方法
  113.      * @param file 文件名
  114.      * @return
  115.      */
  116.     private static ResultBean uploadFileByOrigin(MultipartFile file,String uploadPath){
  117.         String fileName = file.getOriginalFilename();
  118.         fileName = renameToUUID(fileName);
  119.         File targetFile = new File(uploadPath);
  120.         if (!targetFile.exists()) {
  121.             targetFile.mkdirs();
  122.         }
  123.         FileOutputStream out = null;
  124.         try {
  125.             out = new FileOutputStream(uploadPath + fileName);
  126.             out.write(file.getBytes());
  127.         } catch (IOException e) {
  128.             log.info("[ERROR][uploadFileByOrigin]"+e.getMessage());
  129.             return ResultBean.error(e.getMessage());
  130.         }finally {
  131.             try {
  132.                 out.flush();
  133.             } catch (IOException e) {
  134.                 e.printStackTrace();
  135.             }
  136.             try {
  137.                 out.close();
  138.             } catch (IOException e) {
  139.                 e.printStackTrace();
  140.             }
  141.         }
  142.         return ResultBean.success(fileName);
  143.     }
  144.     /**
  145.      * 下载
  146.      * @return
  147.      */
  148.     public static byte[] downloadFile(String fileId,String uploadFlag,String uploadPath
  149.             ,FastFileStorageClient fastFileStorageClient, String group,
  150.                                       String endPoint,String ak,String sk,
  151.                                       String bucketName) {
  152.         byte[] result=null;
  153.         switch (uploadFlag){
  154.             case "fastDFS":
  155.                 result =downloadFileByFastDFS(fileId,fastFileStorageClient,group);
  156.                 break;
  157.             case "huaweiOOS":
  158.                 result =downloadFileByHuaweiObject(fileId, endPoint, ak, sk, bucketName);
  159.                 break;
  160.             case "server":
  161.             default:
  162.                 String path2 = uploadPath + fileId;
  163.                 path2 = path2.replace("//", "/");
  164.                 result=downloadFileByOrigin(path2);
  165.                 break;
  166.         }
  167.         return result;
  168.     }
  169.     /**
  170.      * 下载文件fastDFS
  171.      * @param fileId 文件名
  172.      * @return
  173.      */
  174.     private static byte[] downloadFileByFastDFS(String fileId,FastFileStorageClient fastFileStorageClient,
  175.                                                 String group){
  176.         DownloadByteArray callback=new DownloadByteArray();
  177.         byte[] group1s=null;
  178.         try {
  179.             group1s = fastFileStorageClient.downloadFile(group, fileId, callback);
  180.         }catch (Exception e){
  181.             log.info("[ERROR][downloadFileByFastDFS]"+e.getMessage());
  182.         }
  183.         return group1s;
  184.     }
  185.     /**
  186.      * 下载文件对象存储
  187.      * @param fileId 文件名
  188.      * @return
  189.      */
  190.     private static byte[] downloadFileByHuaweiObject(String fileId, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk,
  191.                                                      String bucketName){
  192.         byte[] bytes =null;
  193.         try {
  194.             // 创建ObsClient实例
  195.             ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint);
  196.             // 构造GetObjectRequest请求
  197.             GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, fileId);
  198.             // 执行下载操作
  199.             ObsObject obsObject = obsClient.getObject(getObjectRequest);
  200.             bytes = inputStreamToByteArray(obsObject.getObjectContent());
  201.             // 关闭OBS客户端
  202.             obsClient.close();
  203.             return bytes;
  204.         }catch (ObsException e){
  205.             log.info("[ERROR][downloadFileByHuaweiObject]"+e.getErrorMessage());
  206.         }catch (Exception e) {
  207.             log.info("[ERROR][downloadFileByHuaweiObject]"+e.getMessage());
  208.         }
  209.         return bytes;
  210.     }
  211.     /**
  212.      *
  213.      * @param input
  214.      * @return
  215.      * @throws IOException
  216.      */
  217.     private static byte[] inputStreamToByteArray(InputStream input) throws IOException {
  218.         ByteArrayOutputStream output = new ByteArrayOutputStream();
  219.         byte[] buffer = new byte[4096];
  220.         int n = 0;
  221.         while (-1 != (n = input.read(buffer))) {
  222.             output.write(buffer, 0, n);
  223.         }
  224.         return output.toByteArray();
  225.     }
  226.     /**
  227.      * 下载文件
  228.      * @param fileId 文件名
  229.      * @return
  230.      */
  231.     private static byte[] downloadFileByOrigin(String fileId){
  232.         File file  =new File(fileId);
  233.         InputStream inputStream=null;
  234.         byte[] buff = new byte[1024];
  235.         byte[] result=null;
  236.         BufferedInputStream bis = null;
  237.         ByteArrayOutputStream os = null;
  238.         try {
  239.             os=new ByteArrayOutputStream();
  240.             bis = new BufferedInputStream(new FileInputStream(file));
  241.             int i = bis.read(buff);
  242.             while (i != -1) {
  243.                 os.write(buff, 0, buff.length);
  244.                 i = bis.read(buff);
  245.             }
  246.             result=os.toByteArray();
  247.             os.flush();
  248.         } catch (Exception e) {
  249.             log.info("[ERROR][downloadFile]"+e.getMessage());
  250.         }finally {
  251.             if (inputStream != null) {
  252.                 try {
  253.                     inputStream.close();
  254.                 } catch (IOException e) {
  255.                     e.printStackTrace();
  256.                 }
  257.             }
  258.         }
  259.         return result;
  260.     }
  261.     /**
  262.      * 删除文件
  263.      * @param fileId 文件ID
  264.      * @return 删除失败返回-1,否则返回0
  265.      */
  266.     public static boolean deleteFile(String fileId,String fastDFSFlag,FastFileStorageClient fastFileStorageClient,
  267.                                      String group,String uploadPath) {
  268.         boolean result=false;
  269.         if (StringUtils.isNotBlank(fastDFSFlag)&&
  270.                 fastDFSFlag.trim().equalsIgnoreCase("true")){
  271.             result =deleteFileByFastDFS(fileId,fastFileStorageClient,group);
  272.         }else {
  273.             String path2 = uploadPath + fileId;
  274.             path2 = path2.replace("//", "/");
  275.             result=deleteByOrigin(path2);
  276.         }
  277.         return result;
  278.     }
  279.     private static boolean deleteByOrigin(String fileName) {
  280.         File file = new File(fileName);
  281.         // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
  282.         if (file.exists() && file.isFile()) {
  283.             if (file.delete()) {
  284.                 return true;
  285.             } else {
  286.                 return false;
  287.             }
  288.         } else {
  289.             return false;
  290.         }
  291.     }
  292.     private static boolean deleteFileByFastDFS(String fileId,FastFileStorageClient fastFileStorageClient,
  293.                                                String group) {
  294.         try {
  295.             String groupFieId=group+"/"+fileId;
  296.             StorePath storePath = StorePath.praseFromUrl(groupFieId);
  297.             fastFileStorageClient.deleteFile(storePath.getGroup(), storePath.getPath());
  298.         } catch (Exception e) {
  299.             log.info("[ERROR][deleteFileByFastDFS]"+e.getMessage());
  300.             return false;
  301.         }
  302.         return true;
  303.     }
  304.     /**
  305.      * 生成fileId
  306.      * @param fileName
  307.      * @return
  308.      */
  309.     private static String renameToUUID(String fileName) {
  310.         return UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
  311.     }
  312.     /**
  313.      * 删除文件对象存储
  314.      * @param fileId 文件名
  315.      * @return
  316.      */
  317.     private static boolean deleteFileByHuaweiObject(String fileId, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk,
  318.                                                     String bucketName){
  319.         try {
  320.             // 创建ObsClient实例
  321.             ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint);
  322.             // 构造GetObjectRequest请求
  323.             DeleteObjectRequest getObjectRequest = new DeleteObjectRequest(bucketName, fileId);
  324.             // 执行删除操作
  325.             obsClient.deleteObject(getObjectRequest);
  326.             // 关闭OBS客户端
  327.             obsClient.close();
  328.         }catch (ObsException e){
  329.             log.info("[ERROR][deleteFileByHuaweiObject]"+e.getErrorMessage());
  330.         }catch (Exception e) {
  331.             log.info("[ERROR][downloadFileByHuaweiObject]"+e.getMessage());
  332.         }
  333.         return true;
  334.     }
  335.     /**
  336.      * 文件数据输出(image)
  337.      * @param fileId
  338.      * @param bytes
  339.      * @param res
  340.      */
  341.     public static void fileDataOut(String fileId, byte[] bytes, HttpServletResponse res){
  342.         String[] prefixArray = fileId.split("\\.");
  343.         String prefix=prefixArray[1];
  344.         File file  =new File(fileId);
  345.         res.reset();
  346.         res.setCharacterEncoding("utf-8");
  347. //        res.setHeader("content-type", "");
  348.         res.addHeader("Content-Length", "" + bytes.length);
  349.         if(prefix.equals("svg"))
  350.             prefix ="svg+xml";
  351.         res.setContentType("image/"+prefix);
  352.         res.setHeader("Accept-Ranges","bytes");
  353.         OutputStream os = null;
  354.         try {
  355. //            os = res.getOutputStream();
  356. //            os.write(bytes);
  357. //            os.flush();
  358.             res.getOutputStream().write(bytes);
  359.         } catch (IOException e) {
  360.             System.out.println("not find img..");
  361.         } finally {
  362.             if (os != null) {
  363.                 try {
  364.                     os.close();
  365.                 } catch (IOException e) {
  366.                     e.printStackTrace();
  367.                 }
  368.             }
  369.         }
  370.     }
  371. }
复制代码
参考资料

假设个人实战使用可以采用docker快速安装,但是未安装过FastDFS建议普通安装摆设,了解一下tracker和storage的使用,以及摆设搭建集群。
FastDFS普通安装摆设:https://www.cnblogs.com/chenliugou/p/15322389.html
FasdDFS docker安装摆设:https://blog.csdn.net/weixin_44621343/article/details/117825755?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-117825755-blog-127896984.235v43pc_blog_bottom_relevance_base6&spm=1001.2101.3001.4242.1&utm_relevant_index=3
OpenFeign和FastDFS的类冲突:https://www.cnblogs.com/chenliugou/p/18113183
Gitee地址:https://gitee.com/chen-liugou/file/new/master?readme=true

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表