4.2 媒资管理模块 - 项目搭建、minio文件系统

news2024/9/25 19:21:50

文章目录

  • 一、搭建媒资服务工程
    • 1.1 media-api 工程
      • 1.1.1 bootstrap.yaml
      • 1.1.2 Maven
      • 1.1.3 Nacos
    • 1.2 media-service 工程
      • 1.2.1 bootstrap.yaml
      • 1.2.2 Maven
      • 1.2.3 Nacos
      • 1.2.4 分页插件
    • 1.3 media-model 工程
      • 1.3.1 QueryMediaParamsDto
      • 1.3.2 MediaFiles
      • 1.3.3 MediaProcess
      • 1.3.4 MediaProcessHistory
      • 1.3.5 MqMessage
      • 1.3.6 MqMessageHistory
    • 1.4 xuecheng-plus-media
      • 1.4.1 Maven
    • 1.5 启动工程
  • 二、分布式文件系统
    • 2.1 文件系统介绍
    • 2.2 分布式文件系统介绍
      • 2.2.1 NFS 网络文件系统
      • 2.2.2 GFS 可扩展分布式文件系统
      • 2.2.3 HDFS
      • 2.2.4 云计算厂家
  • 三、MinIo文件系统
    • 3.1 介绍
    • 3.2 使用
    • 3.3 Docker环境测试
    • 3.4 SDK
      • 3.4.1 Maven版本
      • 3.4.2 上传文件
      • 3.4.3 删除文件
      • 3.4.4 查询文件
      • 3.4.5 设置多层目录
      • 3.4.6 设置媒体文件类型

一、搭建媒资服务工程

可以参照下面两篇文章进行搭建

3.1 内容管理模块 - 工程搭建、课程查询、配置Swagger、数据字典-CSDN博客

4.1 媒资管理模块 - Nacos与Gateway搭建-CSDN博客

工程结构如下所示

image-20231219000227543

image-20231219000742157

并且创有如下所示的媒资数据库

image-20231218235909056

1.1 media-api 工程

1.1.1 bootstrap.yaml

#微服务配置
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

1.1.2 Maven

我们这里的swagger用的下篇网站中的坐标,解释也在下篇文章中

3.1 内容管理模块 - 工程搭建、课程查询、配置Swagger、数据字典-CSDN博客

<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>

1.1.3 Nacos

server:
  servlet:
    context-path: /media
  port: 63050

1.2 media-service 工程

1.2.1 bootstrap.yaml

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

1.2.2 Maven

<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>

1.2.3 Nacos

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

1.2.4 分页插件

/**
 * <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;
    }
}

1.3 media-model 工程

image-20231219001323313

1.3.1 QueryMediaParamsDto

/**
 * @description 媒资文件查询请求模型类
 */
@Data
@ToString
public class QueryMediaParamsDto {

    @ApiModelProperty("媒资文件名称")
    private String filename;
    @ApiModelProperty("媒资类型")
    private String fileType;
    @ApiModelProperty("审核状态")
    private String auditStatus;
}

1.3.2 MediaFiles

/**
 * 媒资信息
 */
@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;

}

1.3.3 MediaProcess

@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;

}

1.3.4 MediaProcessHistory

@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;

}

1.3.5 MqMessage

@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;

}

1.3.6 MqMessageHistory

@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;

}

1.4 xuecheng-plus-media

1.4.1 Maven

<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>

1.5 启动工程

image-20231219002708605

相当的帮!

二、分布式文件系统

我们需要一种方案能支持存储大量的视频、图片,所以我们需要一个分布式文件系统

分布式文件系统就是海量用户查阅海量文件的方案

2.1 文件系统介绍

文件系统是负责管理和存储文件的系统软件,操作系统通过文件系统提供的接口去存取文件,用户通过操作系统访问磁盘上的文件

文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Fash的固态硬盘)或分区上的文件的方法和数据结构,即在存储设备上组织文件的方法

操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统

文件系统由三部分组成:文件系统的接口,对对象操纵和管理的软件集合,对象及属性

从系统角度来看,文件系统是对文件存储没备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。

具体地说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等

常见的文件系统:FAT16/FAT32、NTFS(Windows的文件操作系统)、HFS、UFS、APFS、XFS、Ext4等
image-20231219004234030

比如HDD、SSD、CO ROM是我们的磁盘,应用软件是微信

那我们从磁盘上读取文件需要经历操作系统、文件系统、驱动程序

假如说没有文件系统,我们不可能以一个目录的形式查看磁盘中的文件

image-20231219004040628

总结:文件系统就是方便对磁盘的文件进行管理的一套文件系统

2.2 分布式文件系统介绍

原来我们整个项目是单体架构,内容管理、媒资管理、系统管理都在一个服务内

而现在把内容管理、媒资管理、系统管理都拆分成了不同的微服务,而这些微服务都会独立的进行部署,这种独立部署的方式就叫分布式方式

为什么要将文件系统进行分布式呢

如果我们想处理大量的视频文件,一台计算机的能力是有限的,所以我们通过网络将若干计算机组织起来共同去存储海量的文件(首先是存储能力提高了),去接收海量用户的请求,这些组织起来的计算机通过网络进行通信

image-20231219005130687

好处

  • 一台计算机的文件系统处理能力扩充到多台计算机同时处理。

  • 一台计算机挂了还有另外副本计算机提供数据。

  • 每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度

2.2.1 NFS 网络文件系统

image-20231219010046527

远程的计算机里面存了一些文件,客户端可以通过网络访问远程计算机

假如本机有C、D两个驱动器磁盘(没有E盘),客户端通过网络连接访问远程计算机后可以将远程计算机上的文件映射到本地的E盘,访问E盘的文件其实就是相当于访问远程计算机中的文件

远程计算机的文件会映射到本地计算机的一个磁盘驱动器内

image-20231219010108595

特点

  • 在客户端上映射NFS服务器的驱动器

  • 客户端通过网络访问NFS服务器的硬盘完全透明

2.2.2 GFS 可扩展分布式文件系统

架构图

image-20231219010741753

image-20231219010752287

GFS client:客户端

GFS master: master,会将文件信息存储在此处,文件的信息叫做元数据(文件的格式、大小),之后会将文件分成若干块,按照一定的算法存储在不同分块服务器

GFS chunkserver:分块服务器,是有多台的

当客户端去查询文件的时候,master很清楚分块存储在哪些分块服务器里,然后master会将文件信息的分块找到并合并然后返回

2.2.3 HDFS

与GFS相似

HDFS,是Hadoop Distributed File System的简称,是Hadoop抽象文件系统的一种实现

HDFS是一个高度容错性的系统,适合部署在廉价的机器上。

HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。

HDFS的文件分布在集群机器上,同时提供副本进行容错及可靠性保证。

例如客户端写入读取文件的直接操作都是分布在集群各个机器上的,没有单点性能压力

架构图

image-20231219011355751

Namenode存储文件的原信息,之后会进行分块

客户端查询的时候Namenode会对分块进行组装合并然后返回

2.2.4 云计算厂家

比如阿里云对象存储服务

官方网站:https://www.aliyun.com/product/oss

Mybatis 案例 —— 文件上传OSS_mybatis文件上传-CSDN博客

三、MinIo文件系统

下载地址:https://dl.min.io/server/minio/release/

3.1 介绍

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个校验块存(校验块是为了文件丢失时恢复)放在下面的结点上

image-20231220221809461

Minio使用纠删码技术来保护数据,它是一种恢复丢失和损坏数据的数学算法,它将数据分块冗余的分散存储在各各节点的磁盘上,所有的可用磁盘组成一个集合,上图由8块硬盘组成一个集合,当上传一个文件时会通过纠删码算法计算对文件进行分块存储,除了将文件本身分成4个数据块,还会生成4个校验块,数据块和校验块会分散的存储在这8块硬盘上。

使用纠删码的好处是即便丢失一半数量(N/2)的硬盘,仍然可以恢复数据

比如上边集合中有4个以内的硬盘损害仍可保证数据恢复,不影响上传和下载,如果多于一半的硬盘坏了则无法恢复

3.2 使用

  • 准备4个数据结点

image-20231220223537246

  • 在下载的minio.exe文件下运行MinIo
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

image-20231220223827756

  • 登录

image-20231220224352370

  • 创建一个Buckets,可以理解为创建一个目录

image-20231220224500053

image-20231220224554800

创建完成之后是下面这个样子

image-20231220224617748

创建完成之后目录中也有“testbuckets”目录

image-20231220224712237

  • 传输文件

image-20231220224916404

再查看文件夹

image-20231220225017288

image-20231220224959278

image-20231220225139094

image-20231220225150119

  • 删除节点data1

    然后测试一下是否影响读取和写入

image-20231220225306520

再传入文件,也是没什么问题的

image-20231220225350888

然后我们发现又把数据同步到data1了

image-20231220225521912

  • 删除data1和data2

依然可以稳定执行

  • 删除data1、data2、data3时,便不可以

    此时页面就会进不去,更别说传文件了

3.3 Docker环境测试

开发阶段和生产阶段统一使用Docker下的MINIO。

虚拟机中已安装了MinIO的镜像和容器,执行sh /data/soft /restart.sh启动Docker下的MinIO

启动完成登录MinIO查看是否正常。

访问http://192.168.101.65:9000

mediafiles: 普通文件

video:视频文件

image-20231220230355449

3.4 SDK

MinIO提供多个语言版本SDK的支持,下边找到java版本的文档:

地址:https://docs.min.io/docs/java-client-quickstart-guide.html

最低需求Java 1.8或更高版本

首先要创建一个testbucket

image-20231220233911630

修改访问权限

image-20231220234002955

改成public

如果是private的话,是通过接口下载不到这里面的文件

image-20231220234121726

3.4.1 Maven版本

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>

3.4.2 上传文件

其实上传视频也要做一个完整性校验

怎么搞?

上传上去后再下载下载做一个完整性校验

/**
 * 测试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中确实存在,很棒

image-20231220235545191

3.4.3 删除文件

    @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("删除失败");
        }
    }

没啦没啦

image-20231221000119833

3.4.4 查询文件

其实是从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();
        }
    }

image-20231221004917576

image-20231221004926790

3.4.5 设置多层目录

//上传到minio中的对象名,上传的文件存储到哪个对象中
//下面这个是直接在桶下存储文件
.object("SpringBootApplicationTestsMinIo")

设置多层目录

将上传的文件放在test目录下

//下面这个是存储在桶/test/目录下
.object("test/SpringBootApplicationTestsMinIo")

很成功

image-20231221000508368

3.4.6 设置媒体文件类型

设置媒体文件类型

参数是一个String类型org.springframework.http.MediaType类型,里面有需要媒体文件类型

image-20231221001210373

我们也可以引入一个工具包,根据扩展名取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());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1334594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySql的mvcc原理

目录 一、什么是mvcc? 二、什么是当前读,快照读? 当前读 快照读 三、mvcc实现原理 版本链 undo日志 Undo log 的用途 Read View(读视图) Read View几个属性 五、RR、RC级别下生成时机 一、什么是mvcc? mvcc全称Multi-Version Concurrency Control&#xff0c;即…

教你如何开发并运营小程序商城或APP商城!

随着线下租金、仓储等成本的攀升&#xff0c;商家们面临着越来越大的压力。为了降低成本、提高效率&#xff0c;越来越多的商家开始转型做电商&#xff0c;甚至直接开发自己的电商商城小程序或APP。那么&#xff0c;商城小程序或APP该如何开发呢&#xff1f;又该如何运营呢&…

线上展览馆可以展示哪些内容,线上展览馆如何搭建

引言&#xff1a; 随着互联网的普及和科技的发展&#xff0c;线上展览馆逐渐成为一种新兴的展示平台&#xff0c;吸引了众多企业和商家入驻。那么线上展览馆可以展示哪些内容&#xff0c;如何搭建一个独具特色的线上展览馆&#xff0c;助力您的品牌脱颖而出&#xff1f; 一、线…

深入了解 Git 分支合并冲突解决步骤

目录 前言1 检测合并冲突2 手动解决冲突2.1 打开冲突文件2.2 手动解决冲突 3 标记解决后的文件4 完成合并5 提交合并后的内容6 验证合并结语 前言 在协作开发中&#xff0c;当不同分支对同一文件的相同位置进行修改时&#xff0c;往往会出现合并冲突。这些冲突需要开发者手动介…

2024最经典的软件测试面试题【含答案】

说起软件测试近几年的发展&#xff0c;其实已悄无声息地发生了巨大的变化。前几年随着互联网行业的迅猛发展&#xff0c;软件测试人才稀缺&#xff0c;低门槛高薪资促使大批毕业生和转行人员一窝蜂地涌入。而现在&#xff0c;软件测试发展太快&#xff0c;纵观各大招聘网站&…

【网安 | 网络协议】ARP协议(地址解析协议)

前言 在使用nmap时可以使用-PR指令&#xff0c;通过发送ARP请求包进行主机存活探测。 那么这一过程的原理是什么呢&#xff1f; 在了解什么是ARP协议后&#xff0c;问题就迎刃而解了。 概念 地址解析协议&#xff0c;即ARP&#xff08;Address Resolution Protocol&#xf…

SpringCloudAlibaba Seata在Openfeign跨节点环境出现全局事务Xid失效原因底层探究

原创/朱季谦 曾经在SpringCloudAlibaba的Seata分布式事务搭建过程中&#xff0c;跨节点通过openfeign调用不同服务时&#xff0c;发现全局事务XID在当前节点也就是TM处&#xff0c;是正常能通过RootContext.getXID()获取到分布式全局事务XID的&#xff0c;但在下游节点就出现获…

猫头虎分享2023年12月17日博客之星候选--领域赛道博主文章数据

猫头虎分享2023年12月17日博客之星候选–领域赛道博主文章数据 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开…

C# float/double 减 float/double 等 (X.xxxxxxxxxxxxxE-07)(黑盒测试)

问题 因为没有深究原理&#xff0c;所有只进行了“黑盒测试” 黑盒测试结论&#xff1a; 问题操作结论float/double运算进过一系列的运算后大概率 &#xff01; 0.0 &#xff0c; 而是等于0.00000000000xxxx等于X.xxxxxxxx一串数字的时候不影响下一步继续使用当需要显示fl…

HTML5之 夜景放烟花

参考网址 https://blog.csdn.net/Gou_Hailong/article/details/122269931 https://blog.csdn.net/u013343616/article/details/122233674 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transi…

js原生深拷贝方法:structuredClone() 告别自写时代

自2022年3月起&#xff0c;该功能适用于最新的设备和浏览器版本。此功能可能无法在较旧的设备或浏览器中工作。 例子 // Create an object with a value and a circular reference to itself. const original { name: "MDN" }; original.itself original;// Clone…

尺寸公差分析与尺寸链计算软件-DTAS3D到底能给我们带来哪些价值?

【技能】DTAS3D能给我们带来哪些价值&#xff1f; DTAS3D是一款高度集成的公差分析软件&#xff0c;旨在为产品开发团队提供准确的建议&#xff0c;从而放心地将设计发布给制造部门。下面是DTAS3D的关键价值和应用: 1.与三维CAD无缝集成: DTAS3D与三维CAD软件 (CATIA、NX、Cr…

IntelliJ IDEA 2023.3 安装教程

引言 IntelliJ IDEA&#xff0c;通常简称为 IDEA&#xff0c;是由 JetBrains 开发的一款强大的集成开发环境&#xff0c;专为提升开发者的生产力而设计。它支持多种编程语言&#xff0c;包括 Java、Kotlin、Scala 和其他 JVM 语言&#xff0c;同时也为前端开发和移动应用开发提…

Linux——Redis入门

1.Redis的基本概念 Redis 是一个开源&#xff08;BSD许可)的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构&#xff0c;如字符串(strings)&#xff0c;散列(hashes)&#xff0c;列表(lists)&#xff0c;集…

松柏之志,下聚百川-松下中国阿里云大数据实践

作者&#xff1a;南宫兰 松下信息系统&#xff08;上海&#xff09;有限公司 数据分析部部长 松下集团在中国及东北亚地区拥有有64家法人公司&#xff0c;员工人数约4万人&#xff0c;业务范围涉及研究开发&#xff0c;养老、铸件、汽车、车载、能源、电池等多个方面&#xff…

【Python】进程和多进程的使用

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、进程1.概念理解2.进程的启动3.python进程 二、多进程 前言 进程是指计算机中正在运行的程序实例。 进程可以是操作系统分配的&#…

2023年小型计算机视觉总结

在过去的十年中&#xff0c;出现了许多涉及计算机视觉(CV)的项目&#xff0c;无论是小型的概念验证项目还是更大规模的生产应用。应用计算机视觉的方法是相当标准化的: 1、定义问题(分类、检测、跟踪、分割)、输入数据(图片的大小和类型、视野)和类别(正是我们想要的) 2、注释…

【性能测试】真实企业,性能测试流程总结分析(一)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试什么时候…

JuiceSSH结合内网穿透实现公网远程访问本地Linux虚拟机

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …

dev express 列头筛选

设置这三个属性。 AllowAutoFiter:&#xff1a;获取或设置是否可以使用自动筛选行筛选列的值AllowFiter&#xff1a;获取或设置网格视图中的筛选按钮(布局视图中的字段选按钮)是否显示在列标题中ImmediteUpdateAutoFiter&#xff1a; 获取或设置是否在最终用户修改自动筛选行单…