支持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
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企服之家,中国第一个企服评测及商务社交产业平台。 |