可以参照下面两篇文章进行搭建
工程结构如下所示
并且创有如下所示的媒资数据库
#微服务配置
spring:
application:
name: media-api
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery:
namespace: ${spring.profiles.active}
group: xuecheng-plus-project
config:
namespace: ${spring.profiles.active}
group: xuecheng-plus-project
file-extension: yaml
refresh-enabled: true
extension-configs:
- data-id: media-service-${spring.profiles.active}.yaml
group: xuecheng-plus-project
refresh: true
shared-configs:
- data-id: swagger-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
- data-id: logging-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
profiles:
active: dev
我们这里的swagger用的下篇网站中的坐标,解释也在下篇文章中
<parent>
<artifactId>xuecheng-plus-media</artifactId>
<groupId>com.xuecheng</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>xuecheng-plus-media-api</artifactId>
<name>xuecheng-plus-media-api</name>
<description>xuecheng-plus-media-api</description>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-media-model</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-media-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--cloud的基础环境包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<!-- Spring Boot 的 Spring Web MVC 集成 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Spring Boot 对 LocalDateTime
boot-starter-web自动引入
-->
<!-- <dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>-->
<!--<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>-->
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Boot 集成 log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- Spring Boot 集成 swagger -->
<!--swagger-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.22</version>
</dependency>
</dependencies>
server:
servlet:
context-path: /media
port: 63050
spring:
application:
name: media-service
cloud:
nacos:
server-addr: 192.168.101.65:8848
discovery:
namespace: ${spring.profiles.active}
group: xuecheng-plus-project
config:
namespace: ${spring.profiles.active}
group: xuecheng-plus-project
file-extension: yaml
refresh-enabled: true
shared-configs:
- data-id: logging-${spring.profiles.active}.yaml
group: xuecheng-plus-common
refresh: true
#profiles默认为dev
profiles:
active: dev
<parent>
<artifactId>xuecheng-plus-media</artifactId>
<groupId>com.xuecheng</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>xuecheng-plus-media-service</artifactId>
<name>xuecheng-plus-media-service</name>
<description>xuecheng-plus-media-service</description>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-media-model</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis plus的依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- Spring Boot 集成 Junit -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 排除 Spring Boot 依赖的日志包冲突 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Boot 集成 log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.101.65:3306/xcplus_media?serverTimezone=UTC&userUnicode=true&useSSL=false&
username: root
password: mysql
cloud:
config:
override-none: true
/**
* <P>
* Mybatis-Plus 配置
* </p>
*/
@Configuration
@MapperScan("com.xuecheng.media.mapper")
public class MybatisPlusConfig {
/**
* 新的分页插件
* 需要设置 MybatisConfiguration#useDeprecatedExecutor = false
* 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
/**
* @description 媒资文件查询请求模型类
*/
@Data
@ToString
public class QueryMediaParamsDto {
@ApiModelProperty("媒资文件名称")
private String filename;
@ApiModelProperty("媒资类型")
private String fileType;
@ApiModelProperty("审核状态")
private String auditStatus;
}
/**
* 媒资信息
*/
@Data
@TableName("media_files")
public class MediaFiles implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
/**
* 机构ID
*/
private Long companyId;
/**
* 机构名称
*/
private String companyName;
/**
* 文件名称
*/
private String filename;
/**
* 文件类型(文档,音频,视频)
*/
private String fileType;
/**
* 标签
*/
private String tags;
/**
* 存储目录
*/
private String bucket;
/**
* 存储路径
*/
private String filePath;
/**
* 文件标识
*/
private String fileId;
/**
* 媒资文件访问地址
*/
private String url;
/**
* 上传人
*/
private String username;
/**
* 上传时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate;
/**
* 修改时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime changeDate;
/**
* 状态,1:未处理,视频处理完成更新为2
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 审核状态
*/
private String auditStatus;
/**
* 审核意见
*/
private String auditMind;
/**
* 文件大小
*/
private Long fileSize;
}
@Data
@ToString
@TableName("media_process")
public class MediaProcess implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 文件标识
*/
private String fileId;
/**
* 文件名称
*/
private String filename;
/**
* 存储源
*/
private String bucket;
private String filePath;
/**
* 状态,1:未处理,视频处理完成更新为2
*/
private String status;
/**
* 上传时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate;
/**
* 完成时间
*/
private LocalDateTime finishDate;
/**
* 媒资文件访问地址
*/
private String url;
/**
* 失败原因
*/
private String errormsg;
/**
* 失败次数
*/
private int failCount;
}
@Data
@TableName("media_process_history")
public class MediaProcessHistory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 文件标识
*/
private String fileId;
/**
* 文件名称
*/
private String filename;
/**
* 存储源
*/
private String bucket;
private String filePath;
/**
* 状态,1:未处理,视频处理完成更新为2
*/
private String status;
/**
* 上传时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createDate;
/**
* 完成时间
*/
private LocalDateTime finishDate;
/**
* 媒资文件访问地址
*/
private String url;
/**
* 失败原因
*/
private String errormsg;
/**
* 失败次数
*/
private int failCount;
}
@Data
@TableName("mq_message")
public class MqMessage implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 消息id
*/
private String id;
/**
* 消息类型代码
*/
private String messageType;
/**
* 关联业务信息
*/
private String businessKey1;
/**
* 关联业务信息
*/
private String businessKey2;
/**
* 关联业务信息
*/
private String businessKey3;
/**
* 消息队列主机
*/
private String mqHost;
/**
* 消息队列端口
*/
private Integer mqPort;
/**
* 消息队列虚拟主机
*/
private String mqVirtualhost;
/**
* 队列名称
*/
private String mqQueue;
/**
* 通知次数
*/
private Integer informNum;
/**
* 处理状态,0:初始,1:成功,2:失败
*/
private Integer state;
/**
* 回复失败时间
*/
private LocalDateTime returnfailureDate;
/**
* 回复成功时间
*/
private LocalDateTime returnsuccessDate;
/**
* 回复失败内容
*/
private String returnfailureMsg;
/**
* 最近通知时间
*/
private LocalDateTime informDate;
}
@Data
@TableName("mq_message_history")
public class MqMessageHistory implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 消息id
*/
private String id;
/**
* 消息类型代码
*/
private String messageType;
/**
* 关联业务信息
*/
private String businessKey1;
/**
* 关联业务信息
*/
private String businessKey2;
/**
* 关联业务信息
*/
private String businessKey3;
/**
* 消息队列主机
*/
private String mqHost;
/**
* 消息队列端口
*/
private Integer mqPort;
/**
* 消息队列虚拟主机
*/
private String mqVirtualhost;
/**
* 队列名称
*/
private String mqQueue;
/**
* 通知次数
*/
private Integer informNum;
/**
* 处理状态,0:初始,1:成功,2:失败
*/
private Integer state;
/**
* 回复失败时间
*/
private LocalDateTime returnfailureDate;
/**
* 回复成功时间
*/
private LocalDateTime returnsuccessDate;
/**
* 回复失败内容
*/
private String returnfailureMsg;
/**
* 最近通知时间
*/
private LocalDateTime informDate;
}
<parent>
<artifactId>xuecheng-plus-parent</artifactId>
<groupId>com.xuecheng</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../xuecheng-plus-parent</relativePath>
</parent>
<artifactId>xuecheng-plus-media</artifactId>
<name>xuecheng-plus-media</name>
<description>xuecheng-plus-media</description>
<packaging>pom</packaging>
<modules>
<module>xuecheng-plus-media-api</module>
<module>xuecheng-plus-media-service</module>
<module>xuecheng-plus-media-model</module>
</modules>
相当的帮!
我们需要一种方案能支持存储大量的视频、图片,所以我们需要一个分布式文件系统
分布式文件系统就是海量用户查阅海量文件的方案
文件系统是负责管理和存储文件的系统软件,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件
文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Fash的固态硬盘)或分区上的文件的方法和数据结构,即在存储设备上组织文件的方法
操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统
文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性
从系统角度来看,文件系统是对文件存储没备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。
具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
常见的文件系统:FAT16/FAT32、NTFS(Windows的文件操作系统)、HFS、UFS、APFS、XFS、Ext4等
比如HDD、SSD、CO ROM是我们的磁盘,应用软件是微信
那我们从磁盘上读取文件需要经历操作系统、文件系统、驱动程序
假如说没有文件系统,我们不可能以一个目录的形式查看磁盘中的文件
总结:文件系统就是方便对磁盘的文件进行管理的一套文件系统
原来我们整个项目是单体架构,内容管理、媒资管理、系统管理都在一个服务内
而现在把内容管理、媒资管理、系统管理都拆分成了不同的微服务,而这些微服务都会独立的进行部署,这种独立部署的方式就叫分布式方式
为什么要将文件系统进行分布式呢?
如果我们想处理大量的视频文件,一台计算机的能力是有限的,所以我们通过网络将若干计算机组织起来共同去存储海量的文件(首先是存储能力提高了),去接收海量用户的请求,这些组织起来的计算机通过网络进行通信
好处
一台计算机的文件系统处理能力扩充到多台计算机同时处理。
一台计算机挂了还有另外副本计算机提供数据。
每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度
远程的计算机里面存了一些文件,客户端可以通过网络访问远程计算机
假如本机有C、D两个驱动器磁盘(没有E盘),客户端通过网络连接访问远程计算机后可以将远程计算机上的文件映射到本地的E盘,访问E盘的文件其实就是相当于访问远程计算机中的文件
远程计算机的文件会映射到本地计算机的一个磁盘驱动器内
特点:
在客户端上映射NFS服务器的驱动器
客户端通过网络访问NFS服务器的硬盘完全透明
架构图
GFS client:客户端
GFS master: master,会将文件信息存储在此处,文件的信息叫做元数据(文件的格式、大小),之后会将文件分成若干块,按照一定的算法存储在不同分块服务器
GFS chunkserver:分块服务器,是有多台的
当客户端去查询文件的时候,master很清楚分块存储在哪些分块服务器里,然后master会将文件信息的分块找到并合并然后返回
与GFS相似
HDFS,是Hadoop Distributed File System的简称,是Hadoop抽象文件系统的一种实现
HDFS是一个高度容错性的系统,适合部署在廉价的机器上。
HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。
HDFS的文件分布在集群机器上,同时提供副本进行容错及可靠性保证。
例如客户端写入读取文件的直接操作都是分布在集群各个机器上的,没有单点性能压力
架构图
Namenode存储文件的原信息,之后会进行分块
客户端查询的时候Namenode会对分块进行组装合并然后返回
比如阿里云对象存储服务
官方网站:https://www.aliyun.com/product/oss
Mybatis 案例 —— 文件上传OSS_mybatis文件上传-CSDN博客
下载地址:https://dl.min.io/server/minio/release/
MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合使用,它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等
特点就是轻量,使用简单,功能强大,支持各种平台,单个文件最大5TB,兼容 Amazon S3接口,提供了 Java、Python、GO等多版本SDK支持
官网:https://min.io
中文:https://www.minio.org.cn/,http://docs.minio.org.cn/docs/
MinIO集群采用去中心化共享架构,每个结点是对等关系,通过Nginx可对MinIO进行负载均衡访问。
什么是去中心化?
在大数据领域,通常的设计理念都是无中心和分布式。
哪一个结点都可以当老大,下面的四个结点都不是主节点
去中心化有什么好处?
容错性更强,避免了单点故障。假如说某个结点挂掉后,不会影响整个集群的访问,并且当挂掉的结点重启后会迅速的把结点上的文件给恢复
一个结点两块硬盘,四个结点八块硬盘
当我们上传文件的时候,会把文件分成若干块
如果是下面这个模式的话是分成4个数据块(文件分为了4份)和4个校验块存(校验块是为了文件丢失时恢复)放在下面的结点上
Minio使用纠删码技术来保护数据,它是一种恢复丢失和损坏数据的数学算法,它将数据分块冗余的分散存储在各各节点的磁盘上,所有的可用磁盘组成一个集合,上图由8块硬盘组成一个集合,当上传一个文件时会通过纠删码算法计算对文件进行分块存储,除了将文件本身分成4个数据块,还会生成4个校验块,数据块和校验块会分散的存储在这8块硬盘上。
使用纠删码的好处是即便丢失一半数量(N/2)的硬盘,仍然可以恢复数据。
比如上边集合中有4个以内的硬盘损害仍可保证数据恢复,不影响上传和下载,如果多于一半的硬盘坏了则无法恢复
minio.exe server D:\zhangjingqi\Note\xuecheng\Note\data1 D:\zhangjingqi\Note\xuecheng\Note\data2 D:\zhangjingqi\Note\xuecheng\Note\data3 D:\zhangjingqi\Note\xuecheng\Note\data4
如果是通过虚拟机启动四个minio,每个虚拟机提供一个minio服务的话,上面的路径就是"http:\\"开头的
运行结果
有用户名和密码,也有访问地址 http://192.168.1.33:9000
创建完成之后是下面这个样子
创建完成之后目录中也有“testbuckets”目录
再查看文件夹
删除节点data1
然后测试一下是否影响读取和写入
再传入文件,也是没什么问题的
然后我们发现又把数据同步到data1了
依然可以稳定执行
删除data1、data2、data3时,便不可以
此时页面就会进不去,更别说传文件了
开发阶段和生产阶段统一使用Docker下的MINIO。
虚拟机中已安装了MinIO的镜像和容器,执行sh /data/soft /restart.sh启动Docker下的MinIO
启动完成登录MinIO查看是否正常。
访问http://192.168.101.65:9000
mediafiles: 普通文件
video:视频文件
MinIO提供多个语言版本SDK的支持,下边找到java版本的文档:
地址:https://docs.min.io/docs/java-client-quickstart-guide.html
最低需求Java 1.8或更高版本
首先要创建一个testbucket
修改访问权限
改成public
如果是private的话,是通过接口下载不到这里面的文件
media-service工程添加此依赖
<!--minio依赖-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.3</version>
</dependency>
<!--http依赖,springboot默认使用的http,发送http请求-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.8.1</version>
</dependency>
其实上传视频也要做一个完整性校验
怎么搞?
上传上去后再下载下载做一个完整性校验
/**
* 测试minio的SDK
*/
@SpringBootTest
public class MinioTest {
MinioClient minioClient =
MinioClient.builder()
//这个地方是运行minio后展示的地址
.endpoint("http://192.168.101.65:9000")
//账号和密码
.credentials("minioadmin", "minioadmin")
.build();
@Test
public void test_upload() {
try {
// 判断桶testbucket是否存在,如果不存在的话就进创建
boolean found =
minioClient.bucketExists(BucketExistsArgs.builder().bucket("testbucket").build());
if (!found) {
// Make a new bucket called 'asiatrip'.
minioClient.makeBucket(MakeBucketArgs.builder().bucket("testbucket").build());
} else {
System.out.println("Bucket 'asiatrip' already exists.");
}
//minioClient.uploadObject上传文件,需要一个UploadObjectArgs类型参数
//上传文件的参数信息: UploadObjectArgs.builder()进行构建
minioClient.uploadObject(
UploadObjectArgs.builder()
//桶,也就是目录
.bucket("testbucket")
//指定本地文件的路径
.filename("E:\\SpringBootApplicationTests.java")
//上传到minio中的对象名,上传的文件存储到哪个对象中
.object("SpringBootApplicationTestsMinIo")
//构建
.build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
minio中确实存在,很棒
@Test
public void delete() {
try {
minioClient.removeObject(
RemoveObjectArgs.builder()
//桶
.bucket("testbucket")
//要删除的对象
.object("SpringBootApplicationTestsMinIo")
.build());
System.out.println("删除成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("删除失败");
}
}
没啦没啦
其实是从minio中下载文件
@Test
public void getFile() {
GetObjectArgs getObjectArgs = GetObjectArgs.builder()
.bucket("testbucket")
.object("test/SpringBootApplicationTestsMinIo")
.build();
try {
//查询远程服务器获取到衣蛾流对象
FilterInputStream inputStream = minioClient.getObject(getObjectArgs);
//输出流,下载到哪里
FileOutputStream outputStream = new FileOutputStream(new File("E:\\TestsMinIo.java"));
//import org.apache.commons.io.IOUtils;
IOUtils.copy(inputStream, outputStream);
//校验文件的完整性,对文件的内容进行md5
//对minio上的文件进行MD5摘要算法,对下载下来的文件进行摘要算法,如果两者MD5一样,说明下载的文件是完整的
//import org.apache.commons.codec.digest.DigestUtils;
//这个参数不要写远程流minioClient.getObject(getObjectArgs),会不稳定或者有问题
//String source_md5 = DigestUtils.md5Hex(inputStream);
FileInputStream fileInputStream = new FileInputStream(new File("E:\\SpringBootApplicationTests.java"));
//我们这个地方是拿到最开始上传到minio的原文件的MD5与从下载下面的文件MD5进行对比
String source_md5 = DigestUtils.md5Hex(fileInputStream);
String local_md5 = DigestUtils.md5Hex(new FileInputStream(new File("E:\\TestsMinIo.java")));
if (source_md5.equals(local_md5)){
System.out.println("下载成功");
}
} catch (Exception e) {
e.printStackTrace();
}
}
//上传到minio中的对象名,上传的文件存储到哪个对象中
//下面这个是直接在桶下存储文件
.object("SpringBootApplicationTestsMinIo")
设置多层目录
将上传的文件放在test目录下
//下面这个是存储在桶/test/目录下
.object("test/SpringBootApplicationTestsMinIo")
很成功
设置媒体文件类型
参数是一个String类型org.springframework.http.MediaType类型,里面有需要媒体文件类型
我们也可以引入一个工具包,根据扩展名取mimetype
com.j256.simplemagic.ContentInfoUtil;包下
<!---->
<dependency>
<groupId>com.j256.simplemagic</groupId>
<artifactId>simplemagic</artifactId>
<version>1.17</version>
</dependency>
假如我们不设置的话,会自动识别
ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".mp4");
//通用mimeType,字节流
String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
if (extensionMatch !=null){
mimeType = extensionMatch.getMimeType();
}
minioClient.uploadObject(
UploadObjectArgs.builder()
//桶,也就是目录
.bucket("testbucket")
//指定本地文件的路径
.filename("E:\\Tests.mp4")
//上传到minio中的对象名,上传的文件存储到哪个对象中
//下面这个是存储在桶/test/目录下
.object("TestsMinIo")
//设置媒体文件类型,可以通过扩展名得到媒体资源类型
.contentType(mimeType)
//构建
.build());