大文件上传服务-后端V1V2

大文件上传概述:

之前项目做了一个文件上传的功能,最近看到有面试会具体的问这个上传功能的细节,把之前做的项目拿过来总结一下,自己写的一个文件上传服务,如果是单体项目直接就是 file-model,微服务可以给文件单独搞一个服务。

对于大的文件上传由于网络带宽的限制非常的耗时间,可以将文件进行切分,类似于IP数据包重组和分片。

类似于百度网盘一秒上传文件,这个如何实现的呢? 相同的文件上传过一次之后使用了MD5加密的算法,下次就不用等待上传了。

对于海量的文件,如何去存储呢? 这些都是需要去考虑的内容。可以使用轻量级的分布式存储minio来存储文件。复杂一点可以使用 fastDFS 来存储文件。

文件存储 sql 表:

create table file_url_table
(
    id          int auto_increment
        primary key,
    file_name   varchar(255)                        not null,
    file_type   varchar(30)                         not null,
    file_md5    varchar(32)                         not null,
    file_url    varchar(512)                        not null,
    endpoint    varchar(255)                        not null,
    buck_name   varchar(255)                        not null,
    object_name varchar(255)                        not null,
    created_at  timestamp default CURRENT_TIMESTAMP null,
    updated_at  timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP
);

minio分布式文件存储

后端文件的存储使用分布式文件存储系统minio

一个minio的地址包括:

endpoint:节点的信息 http:ip地址+:端口号

buckName: 桶的基础信息

objectName: 文件夹的信息+文件的名称。

http://xxxxx:9000/powerproject/file/2024/12/01/bbb5ba51d7b65cf4495de91ca55bfa23.mp3

项目中使用 minio

导入minio maven依赖:

<dependency>
     <groupId>io.minio</groupId>
     <artifactId>minio</artifactId>
     <version>8.5.7</version>
</dependency>

配置minoConfig,使用Configuration注解,spring在启动的时候会扫描这个类。@bean会创建一个MinioClient,交给Spring容器去管理。


@Configuration

public class MinioConfig {
   
   
      
   @Value("${minio.accessKey}")
    private String accessKey;
    @Value("${minio.secretKey}")
    private String secretKey;
    @Value("${minio.endpoint}")
    private String endPoint;

     
    @Bean
    public MinioClient minioClient() {
   
   
        return MinioClient.builder().endpoint(endPoint)
                .credentials(accessKey, secretKey).build();
    }
}
  • **@Bean** 注解定义了一个 Spring Bean 方法,用来初始化并提供配置好的 MinioClient
  • 通过自动注入,Spring Boot 会将配置文件中的 minio.accessKey, minio.secretKey, minio.endPoint 自动注入到类的字段中,并将配置好的 MinioClient 实例作为 Bean 提供给整个应用使用。
  • spring启动的时候会扫描到configuration这个包。

断点续传:

通常视频文件都比较大,所以对于媒资系统上传文件的需求要满足大文件的上传要求。http协议本身对上传文件大小没有限制,但是客户的网络环境质量、电脑硬件环境等参差不齐,如果一个大文件快上传完了网断了没有上传完成,需要客户重新上传,用户体验非常差,所以对于大文件上传的要求最基本的是断点续传。

什么是断点续传:

引用百度百科:断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载,断点续传可以提高节省操作时间,提高用户体验性

使用的一些技术

因为上传的结构传进来的都是MultipartFile,但是文件合并完成之后是File类型的,需要将File转为MultipartFile。

  //将木桶的文件 转换成 MultipartFile
        MultipartFile multipartFile = new MockMultipartFile(
                "file",                           // 表单中文件参数的名字
                fileName,             // 文件名
                fileType,                // 文件类型
                new FileInputStream(outputFile)   // 文件输入流
        );

MockMultipartFile 的构造函数有四个参数:

  • 第一个参数"file"
    • 这是表单中用于接收文件的字段名。通常是前端表单中的 <input type="file" name="file"> 中的 name 属性值。
    • 例如,在 HTML 表单中,字段可能长这样:
<input type="file" name="file">
- 后端通过 `"file"` 来访问上传的文件。
  • 第二个参数fileName
    • 这是文件的名字,即上传文件时的文件名。它将作为文件在服务器上存储时的名称,或者用作处理文件时的标识符。
    • 例如,fileName 可能是 "document.pdf""image.jpg" 等。
  • 第三个参数fileType
    • 这是文件的 MIME 类型(文件类型)。常见的文件类型如 "application/pdf", "image/jpeg", "text/plain" 等。
    • 在这里,它指定了文件的格式/类型,告诉服务器如何处理该文件。
  • 第四个参数new FileInputStream(outputFile)
    • 这是文件内容的输入流。**FileInputStream**** 用于读取文件内容并将其传递给 **MockMultipartFile**。**
    • outputFile 是一个 File 对象,表示要上传的实际文件。通过 new FileInputStream(outputFile),你可以将文件内容转换为字节流,使得它可以被传递到 MockMultipartFile 中。

MultipartFile 提供了几个常用方法,比如:

  • getName(): 获取文件的字段名。
  • getOriginalFilename(): 获取文件的原始文件名。
  • getBytes(): 获取文件的字节内容。
  • getInputStream(): 获取文件的输入流。
校验MD5的逻辑

对于已经存在的文件,文件的 md5 值都是相同的。文件上传前端解析 md5,查询数据库中是否有数据,如果没有再实现文件上传。

//去数据库中查询这个文件的哈希值是否存在,如果存在就不用上传了,直接拿到这个文件的地址
@GetMapping("/md5")
public AjaxResult getMd5(@RequestParam("md5") String md5) {
   
   
    Map<String, Object> map=fileService.getMd5(md5);
    return AjaxResult.success(map);
}
@SneakyThrows
@Override
public Map<String, Object> getMd5(String md5) {
   
   
// 从数据库查询文件信息
FileEntity file = fileMapper.getMd5(md5);

// 如果文件不存在,直接返回 null
if (file == null) {
   
   
    return null;   
}

// 获取文件相关信息
String bucketName = file.getBuckName();
String objectName = file.getObjectName();
String fileUrl = file.getFileUrl();
String fileType = file.getFileType()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈阿星

您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值