Java实现Fast DFS、服务器、OSS上传功能
支持Fast DFS、服务器、OSS等上传方式
介绍
在实际的业务中,可以根据客户的需求设置不同的文件上传需求,支持普通服务器上传+分布式上传(Fast DFS)+云服务上传OSS(OSS)
软件架构
为了方便演示使用,本项目使用的是前后端不分离的架构
前端:Jquery.uploadFile
后端:SpringBoot
前期准备:FastDFS、OSS(华为)、服务器
实现逻辑
通过 application 配置对上传文件进行一个自定义配置,从而部署在不同客户环境可以自定义选择方式。
优点:
- 一键切换;
- 支持当前主流方式;
缺点:
- 迁移数据难度增加:因为表示FileID在对象存储和服务器上传都是生成的UUID,而FastDFS是返回存取ID,当需要迁移的时候,通过脚本可以快速将FastDFS的数据迁移上云,因为存储ID可以共用。但是对象存储和服务器上传的UUID无法被FastDFS使用,增加迁移成本
核心代码
package com.example.file.util; import com.example.file.common.ResultBean; import com.github.tobato.fastdfs.domain.StorePath; import com.github.tobato.fastdfs.proto.storage.DownloadByteArray; import com.github.tobato.fastdfs.service.FastFileStorageClient; import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; import com.obs.services.model.DeleteObjectRequest; import com.obs.services.model.GetObjectRequest; import com.obs.services.model.ObsObject; import com.obs.services.model.PutObjectResult; import io.micrometer.common.util.StringUtils; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.util.Objects; import java.util.UUID; @Slf4j public class FileUtil { /** * * @param file 文件 * @param uploadFlag 标识 * @param uploadPath 上传路径 * @param endPoint 域名 * @param ak ak * @param sk sk * @param bucketName 桶名字 * @return fileId 用于下载 */ public static ResultBean uploadFile(MultipartFile file, String uploadFlag, String uploadPath, FastFileStorageClient fastFileStorageClient, String endPoint, String ak, String sk, String bucketName) { if (StringUtils.isBlank(uploadFlag)){ ResultBean.error("uploadFlag is null"); } switch (uploadFlag){ case "fastDFS": return uploadFileByFastDFS(file,fastFileStorageClient); case "huaweiOOS": return uploadFileByHuaweiObject(file, endPoint, ak, ak, bucketName); case "server": default: return uploadFileByOrigin(file,uploadPath); }} /** * 上传文件fastDFS * @param file 文件名 * @return */ private static ResultBean uploadFileByFastDFS(MultipartFile file,FastFileStorageClient fastFileStorageClient){ Long size=file.getSize(); String fileName=file.getOriginalFilename(); String extName=fileName.substring(fileName.lastIndexOf(".")+1); InputStream inputStream=null; try { inputStream=file.getInputStream(); //1-上传的文件流 2-文件的大小 3-文件的后缀 4-可以不管他 StorePath storePath=fastFileStorageClient.uploadFile(inputStream,size,extName,null); log.info("[uploadFileByFastDFS][FullPath]"+storePath.getFullPath()); return ResultBean.success(storePath.getPath()); }catch (Exception e){ log.info("[ERROR][uploadFileByFastDFS]"+e.getMessage()); return ResultBean.error(e.getMessage()); }finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 对象存储上传 * @param file 文件名 * @return */ private static ResultBean uploadFileByHuaweiObject(MultipartFile file, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk, String bucketName){ String fileName = file.getOriginalFilename(); fileName = renameToUUID(fileName); InputStream inputStream=null; try { inputStream=file.getInputStream(); // 创建ObsClient实例 ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint); PutObjectResult result = obsClient.putObject(bucketName, fileName, inputStream); obsClient.close(); return ResultBean.success(fileName); }catch (ObsException e){ log.info("[ERROR][uploadFileByHuaweiObject]"+e.getErrorMessage()); return ResultBean.error(e.getErrorMessage()); }catch (Exception e){ log.info("[ERROR][uploadFileByHuaweiObject]"+e.getMessage()); return ResultBean.error(e.getMessage()); }finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 上传文件原本方法 * @param file 文件名 * @return */ private static ResultBean uploadFileByOrigin(MultipartFile file,String uploadPath){ String fileName = file.getOriginalFilename(); fileName = renameToUUID(fileName); File targetFile = new File(uploadPath); if (!targetFile.exists()) { targetFile.mkdirs(); } FileOutputStream out = null; try { out = new FileOutputStream(uploadPath + fileName); out.write(file.getBytes()); } catch (IOException e) { log.info("[ERROR][uploadFileByOrigin]"+e.getMessage()); return ResultBean.error(e.getMessage()); }finally { try { out.flush(); } catch (IOException e) { e.printStackTrace(); } try { out.close(); } catch (IOException e) { e.printStackTrace(); } } return ResultBean.success(fileName); } /** * 下载 * @return */ public static byte[] downloadFile(String fileId,String uploadFlag,String uploadPath ,FastFileStorageClient fastFileStorageClient, String group, String endPoint,String ak,String sk, String bucketName) { byte[] result=null; switch (uploadFlag){ case "fastDFS": result =downloadFileByFastDFS(fileId,fastFileStorageClient,group); break; case "huaweiOOS": result =downloadFileByHuaweiObject(fileId, endPoint, ak, sk, bucketName); break; case "server": default: String path2 = uploadPath + fileId; path2 = path2.replace("//", "/"); result=downloadFileByOrigin(path2); break; } return result; } /** * 下载文件fastDFS * @param fileId 文件名 * @return */ private static byte[] downloadFileByFastDFS(String fileId,FastFileStorageClient fastFileStorageClient, String group){ DownloadByteArray callback=new DownloadByteArray(); byte[] group1s=null; try { group1s = fastFileStorageClient.downloadFile(group, fileId, callback); }catch (Exception e){ log.info("[ERROR][downloadFileByFastDFS]"+e.getMessage()); } return group1s; } /** * 下载文件对象存储 * @param fileId 文件名 * @return */ private static byte[] downloadFileByHuaweiObject(String fileId, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk, String bucketName){ byte[] bytes =null; try { // 创建ObsClient实例 ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint); // 构造GetObjectRequest请求 GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, fileId); // 执行下载操作 ObsObject obsObject = obsClient.getObject(getObjectRequest); bytes = inputStreamToByteArray(obsObject.getObjectContent()); // 关闭OBS客户端 obsClient.close(); return bytes; }catch (ObsException e){ log.info("[ERROR][downloadFileByHuaweiObject]"+e.getErrorMessage()); }catch (Exception e) { log.info("[ERROR][downloadFileByHuaweiObject]"+e.getMessage()); } return bytes; } /** * * @param input * @return * @throws IOException */ private static byte[] inputStreamToByteArray(InputStream input) throws IOException { ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } return output.toByteArray(); } /** * 下载文件 * @param fileId 文件名 * @return */ private static byte[] downloadFileByOrigin(String fileId){ File file =new File(fileId); InputStream inputStream=null; byte[] buff = new byte[1024]; byte[] result=null; BufferedInputStream bis = null; ByteArrayOutputStream os = null; try { os=new ByteArrayOutputStream(); bis = new BufferedInputStream(new FileInputStream(file)); int i = bis.read(buff); while (i != -1) { os.write(buff, 0, buff.length); i = bis.read(buff); } result=os.toByteArray(); os.flush(); } catch (Exception e) { log.info("[ERROR][downloadFile]"+e.getMessage()); }finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /** * 删除文件 * @param fileId 文件ID * @return 删除失败返回-1,否则返回0 */ public static boolean deleteFile(String fileId,String fastDFSFlag,FastFileStorageClient fastFileStorageClient, String group,String uploadPath) { boolean result=false; if (StringUtils.isNotBlank(fastDFSFlag)&& fastDFSFlag.trim().equalsIgnoreCase("true")){ result =deleteFileByFastDFS(fileId,fastFileStorageClient,group); }else { String path2 = uploadPath + fileId; path2 = path2.replace("//", "/"); result=deleteByOrigin(path2); } return result; } private static boolean deleteByOrigin(String fileName) { File file = new File(fileName); // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除 if (file.exists() && file.isFile()) { if (file.delete()) { return true; } else { return false; } } else { return false; } } private static boolean deleteFileByFastDFS(String fileId,FastFileStorageClient fastFileStorageClient, String group) { try { String groupFieId=group+"/"+fileId; StorePath storePath = StorePath.praseFromUrl(groupFieId); fastFileStorageClient.deleteFile(storePath.getGroup(), storePath.getPath()); } catch (Exception e) { log.info("[ERROR][deleteFileByFastDFS]"+e.getMessage()); return false; } return true; } /** * 生成fileId * @param fileName * @return */ private static String renameToUUID(String fileName) { return UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1); } /** * 删除文件对象存储 * @param fileId 文件名 * @return */ private static boolean deleteFileByHuaweiObject(String fileId, String huaweiEndPoint,String huaweiobsAk,String huaweiobsSk, String bucketName){ try { // 创建ObsClient实例 ObsClient obsClient = new ObsClient(huaweiobsAk, huaweiobsSk, huaweiEndPoint); // 构造GetObjectRequest请求 DeleteObjectRequest getObjectRequest = new DeleteObjectRequest(bucketName, fileId); // 执行删除操作 obsClient.deleteObject(getObjectRequest); // 关闭OBS客户端 obsClient.close(); }catch (ObsException e){ log.info("[ERROR][deleteFileByHuaweiObject]"+e.getErrorMessage()); }catch (Exception e) { log.info("[ERROR][downloadFileByHuaweiObject]"+e.getMessage()); } return true; } /** * 文件数据输出(image) * @param fileId * @param bytes * @param res */ public static void fileDataOut(String fileId, byte[] bytes, HttpServletResponse res){ String[] prefixArray = fileId.split("\\."); String prefix=prefixArray[1]; File file =new File(fileId); res.reset(); res.setCharacterEncoding("utf-8"); // res.setHeader("content-type", ""); res.addHeader("Content-Length", "" + bytes.length); if(prefix.equals("svg")) prefix ="svg+xml"; res.setContentType("image/"+prefix); res.setHeader("Accept-Ranges","bytes"); OutputStream os = null; try { // os = res.getOutputStream(); // os.write(bytes); // os.flush(); res.getOutputStream().write(bytes); } catch (IOException e) { System.out.println("not find img.."); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
参考资料
假设个人实战使用可以采用docker快速安装,但是未安装过FastDFS建议普通安装部署,了解一下tracker和storage的使用,以及部署搭建集群。
FastDFS普通安装部署:https://www.cnblogs.com/chenliugou/p/15322389.html
OpenFeign和FastDFS的类冲突:https://www.cnblogs.com/chenliugou/p/18113183
Gitee地址:https://gitee.com/chen-liugou/file/new/master?readme=true
到此这篇关于Java实现Fast DFS、服务器、OSS上传功能的文章就介绍到这了,更多相关java Fast DFS上传内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
java.lang.IncompatibleClassChangeError异常的问题解决
本文主要介绍了java.lang.IncompatibleClassChangeError异常的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2024-06-06Spring、SpringMVC和SpringBoot的区别及说明
这篇文章主要介绍了Spring、SpringMVC和SpringBoot的区别及说明,具有很好的参考价值,希望对大家有所帮助。2022-10-10
最新评论