JAVA实现存储服务(微服务间的文件传输)大文件的分片上传

微服务间的文件传输需要解决哪些问题?
1、小文件传输
2、大文件传输
3、用啥协议?http、netty或者其他。
最近设计了一个基于openfeign的文件传输方案:
基于服务的思想,将文件存储模块设计成一个服务模块,任何其他模块想调用它通过
实现了:普通文件的直接传输(小于100M的文件),大文件的分片上传(1G以上的文件)。
消费端:

//@FeignClient(value = "live",url = "http://127.0.0.1:8080",configuration = MultipartSupportConfig.class)
@FeignClient(name = "fileuploadservice",configuration = MultipartSupportConfig.class)
public interface FileUploadService {

    @PostMapping(value =  "/server/up",consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
    String uploadVideo(@RequestPart("file") MultipartFile file);

    @PostMapping(value =  "/server/down")
    feign.Response downVideo(@RequestParam("fileName") String fileName);

    @PostMapping(value =  "/server/uparray",consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
    String uparray(@RequestPart("file") MultipartFile file,@RequestParam String fileInfoDao);

}



服务端:

package com.example.fileserver.file.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.fileserver.file.common.FileInfoDao;
import com.example.fileserver.file.common.util.MD5Util;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

@RestController
@RequestMapping("/server")
public class ServerFileController {

    private int k = 1;

    @RequestMapping(value="/up",method = RequestMethod.POST)
    public String uploadFile(@RequestParam("file") MultipartFile file111){
        k++;
        System.out.println("======");
        String fileName = file111.getOriginalFilename();
        System.out.println("完整文件名 = " + fileName);
        InputStream inputStream = null;
        FileOutputStream fileOut = null;

        fileName = "d:\\serverRec\\"+k+fileName;
        try {
                inputStream = file111.getInputStream();
                fileOut = new FileOutputStream(fileName);//这里可以改路径
                IOUtils.copy(inputStream, fileOut);
                fileOut.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (fileOut != null) {
                    fileOut.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "ok";
    }

    @RequestMapping(value="/uparray",method = RequestMethod.POST)
    public String uparray(@RequestParam("file") MultipartFile file111,@RequestParam("fileInfoDao") String fileInfoDaoStr){
        JSONObject jsonObject = JSONObject.parseObject(fileInfoDaoStr);
        FileInfoDao fileInfoDao = JSONObject.toJavaObject(jsonObject, FileInfoDao.class);
        String fileName = "E:\\temp\\"+fileInfoDao.getFileId()+"\\"+fileInfoDao.getFileName();
        System.out.println("========Im server");
        File file = new File(fileName);
        if(!file.getParentFile().exists()&& !file.isDirectory()){
            System.out.println("文件夹不存在");
            //file.mkdirs();                        //把a.sql也当做文件夹名来创建
            file.getParentFile().mkdirs();       //获取路径的根路径领创建文件,到最后最后一级路径前E:\新建文件夹\20211110\
        }
        System.out.println("文件夹存在");
        try {
            RandomAccessFile out = new RandomAccessFile(new File(fileName+ "_" + fileInfoDao.getFileIndex() + ".tmp"), "rw");
            out.write(file111.getBytes());
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String filePath =  fileName+fileInfoDao.getHouzhui();
        if (fileInfoDao.getFileIndex()==(fileInfoDao.getTotal()-1)){
            //最后一片,合并文件,
            merge(filePath,fileName,fileInfoDao.getTotal(),fileInfoDao);
            //文件MD5值
            String startMd5Code = MD5Util.md5HashCode(fileName+".rar");
            System.out.println("===startMd5Code;"+startMd5Code);
        }
        return "ok";
    }



    @RequestMapping(value="/down",method = RequestMethod.POST)
    public void down(@RequestParam(value = "fileName") String filename) {
        ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
         HttpServletResponse response = attributes.getResponse();
        this.download(filename, response);
    }

    public void download(String filepath, HttpServletResponse response) {
        response.setContentType("application/x-download;charset=" +"utf-8");
        response.addHeader("Content-Disposition","attachment;filename=" + "各个ttt.rar");

        File file = new File("D:\\test\\ttt.rar");
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            ServletOutputStream outputStream = response.getOutputStream();
            IOUtils.copy(inputStream, outputStream);
            outputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        /*OSSObject ossObject;
        try {
            ossObject = ossClient.getObject(fileConfig.getBucketName(), filepath);
        } catch (OSSException | ClientException e) {
            log.error("获取OSS文件连接异常,filePath:[{}]", filepath, e);
            return;
        }

        try (OutputStream outputStream = response.getOutputStream();
             InputStream inputStream = ossObject.getObjectContent()) {
            IOUtils.copy(inputStream, outputStream);
            outputStream.flush();
        } catch (IOException e) {
            log.error("下载文件异常 filepath:[{}]", filepath, e);
        }*/
    }


    /**
     * 文件合并
     * @param file 指定合并文件
     * @param tempFile 分割前的文件名
     * @param tempCount 文件个数
     */
    public  void merge(String file,String tempFile,int tempCount,FileInfoDao fileInfoDao) {
        RandomAccessFile raf = null;
        try {
            //申明随机读取文件RandomAccessFile
            raf = new RandomAccessFile(new File(file), "rw");
            //开始合并文件,对应切片的二进制文件
            byte[] b = new byte[2*1024*1024];
            for (int i = 0; i < tempCount; i++) {
                //读取切片文件
                RandomAccessFile reader = new RandomAccessFile(new File(tempFile + "_" + i + ".tmp"), "r");
                int n = 0;
                //先读后写
                if (i==tempCount-1){
                    while ((n = reader.read(b,0,fileInfoDao.getReadNum())) != -1) {//读
                        raf.write(b, 0,n );//写
                        break;
                    }
                }else{
                    while ((n = reader.read(b)) != -1) {//读
                        raf.write(b, 0, n);//写
                    }
                }
                reader.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                raf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

主要的代码逻辑已经实现了,最近挺忙没有进行整理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值