微服务间的文件传输需要解决哪些问题?
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();
}
}
}
}
主要的代码逻辑已经实现了,最近挺忙没有进行整理。
大文件的分片上传&spm=1001.2101.3001.5002&articleId=127640832&d=1&t=3&u=801e15a0204c4c3d9c996a149031a4f8)
578

被折叠的 条评论
为什么被折叠?



