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

文章目录

  • 一、搭建媒资服务工程
    • 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());

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySql的mvcc原理

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

为什么我的网络这么卡卡卡卡卡?(网络调试篇)

前言 最近小白迷上了打游戏。 有没有一起上王者的小伙伴&#xff1f; 有没有一起吃鸡的小伙伴&#xff1f; 欧耶&#xff0c; 咱们组队 送人头去吧 为了不让对方太菜&#xff0c; 送人头是与对方最高的敬意。 闲话说到这&#xff0c;本文就结束了。 感谢观看&#xff5e;…

常用组件的一些数据指标

QPS metrics 机制&#xff0c;利用 AtomicLong 算出核心接口每分钟调用多少次&#xff08;除以 60 就是高峰期每秒访问次数&#xff09;以及每天被调用总次数 TP99 100ms , 99%的接口耗时在 100ms以内&#xff0c;1%的接口耗时在100ms以上 TP95 100ms , 95%的接口耗时在 1…

CUMT--Java复习--网络编程

目录 一、Java网络API 1、InetAddress类 2、URL类 3、URLConnection类 4、URLDecoder类和URLEncoder类 二、基于TCP的网络编程 1、Socket类 2、ServerSocket类 三、网络通信过程 一、Java网络API Java中有关网络方面的功能都定义在java.net中。 1、InetAddress类 Jav…

AP有信号,但没有注册到AC上的排查

1、有wifi信号收到&#xff0c;并且可以连接&#xff0c;但A P没有获取到地址。 1.AP没有获取到地址&#xff0c;那么就一定没办法找到AC到地址进行注册。 2、交换侧现象&#xff1a; dis poe power 查看端口供电情况。 3、有供电&#xff0c;但没有UP。 4、判断为配…

如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问

作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家如何使用Jellyfin结合内网穿透搭建私人影音平台远程可访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; 前言…

设计模式--桥接模式

实验9&#xff1a;桥接模式 本次实验属于模仿型实验&#xff0c;通过本次实验学生将掌握以下内容&#xff1a; 1、理解桥接模式的动机&#xff0c;掌握该模式的结构&#xff1b; 2、能够利用桥接模式解决实际问题。 [实验任务]&#xff1a;两个维度的桥接模式 用桥接模式…

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

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

Ubuntu系统如何安装SVN服务端并通过客户端无公网ip实现远程访问?

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

Houdini 20版本 功能概述

SideFX 发布了 Houdini 20 预览版&#xff0c;这是其用于视觉特效、游戏开发和动态图形的程序 3D 软件的下一个主要版本&#xff0c;Houdini 20.0 对软件的主要工具集进行了更新&#xff0c;特别是角色装备和动画、模拟工具以及 Karma 渲染器。 Houdini 20新功能亮点 渲染 视频…

玩转大数据22:常见的关联规则挖掘算法

引言 关联规则挖掘是数据挖掘中的一种重要技术&#xff0c;主要用于发现数据集中项之间的有趣关系。关联规则挖掘在许多领域都有广泛的应用&#xff0c;如市场篮子分析、推荐系统等。常见的关联规则挖掘算法包括Apriori算法和FP-Growth算法。 一、Apriori算法 关联规则挖掘是…

制作一个可以离线安装的Visual Studio安装包

须知 前提条件&#xff0c;需要电脑可以正常上网且网速还行&#xff0c;硬盘可以空间容量足够大&#xff0c;怎么判断容量够用&#xff1f;由组件数量的多少来决定。Visual Studio 频道和发布节奏 https://learn.microsoft.com/zh-cn/visualstudio/productinfo/release-rhythm…

Linux上iPortal 配置80端口的http

作者&#xff1a;yx 文章目录 前言方法一、配置使用外置ES1、关闭启用 iPortal 内置的 ES2、修改80端口3、启动外置ES4、启动iPortal5、结果验证 方法二、更改 Linux 系统配置1. 安装 Authbind2. 启用端口的读取和执行权限3. 在 Apache Tomcat 上启用 Authbind4. 重启iPortal5.…

Mysql高级函数——GROUP_CONCAT

Mysql高级函数——GROUP_CONCAT 前言仰天大笑出门去&#xff0c;我辈岂是蓬蒿人 前言 大概内容&#xff1a; 在MySQL中&#xff0c;可以使用GROUP_CONCAT函数来实现将多个数据拼接为一个字符串的功能。GROUP_CONCAT函数接受一个参数&#xff0c;用于指定要拼接的数据列&#x…

【Unity3D日常BUG】Unity3D中编辑完代码后卡在Reload Scripts Assemblies界面的解决方案

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 首先&#xff0c;说明一下&#xff0c;每个人对于BUG的定义不一…

【多线程及高并发 二】线程基础及线程中断同步

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是若明天不见&#xff0c;BAT的Java高级开发工程师&#xff0c;CSDN博客专家&#xff0c;后端领域优质创作者 &#x1f4d5;系列专栏&#xff1a;多线程及高并发系列 &#x1f4d5;其他专栏&#xff1a;微服务框架系列、…

SpringCloud和Dubbo有哪些区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; Spring ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 介绍 Spring Cloud&#xff1a; Dubbo&#xff1a; 选择&#xff1a; 区别 结语 我的其他博客 前言 构建分布式系统是…

Netty组件基础

Netty入门简介 netty是一个异步、基于事件驱动的网络应用框架&#xff0c;用于快速开发可维护、高性能的网络服务器和客户端。 Netty优势 Netty解决了TCP传输问题&#xff0c;如黏包、半包问题&#xff0c;解决了epoll空轮询导致CPU100%的问题。并且Netty对API进行增强&#xf…

Playbook中jinja2模板的使用

本章主要介绍playbook中如何使用jinja2模板 什么是jinja2模板在jinja2模板文件中写if判断语句在jinja2模板文件在写for循环语句handlers的使用 可以使用copy模块把本地的一个文件拷贝到远端机器&#xff0c;下面再次复习一下 本章实验都在demo4文件夹下操作&#xff0c;跟之…

【RocketMQ】Console页面报错:rocketmq remote exception,connect to xxx failed.

现象 console报错&#xff0c;无法连接该节点&#xff0c;把该节点杀掉&#xff0c;还是继续报错&#xff0c;重启之后&#xff0c;报错的端口变成11911。 分析 正常一个broker会启动三个端口&#xff0c;不同版本的规律不太一样&#xff0c;4.X版本是&#xff1a; 配置文件…