【分布式文件存储系统Minio】2024.12保姆级教程

文章目录

    • 1.介绍
        • 1.分布式文件系统
        • 2.基本概念
    • 2.环境搭建
        • 1.访问网址
        • 2.账号密码都是minioadmin
        • 3.创建一个桶
        • 4.**Docker安装miniomc突破7天限制**
          • 1.拉取镜像
          • 2.运行容器
          • 3.进行配置
            • 1.格式
            • 2.具体配置
          • 4.查看桶
          • 5.给桶开放权限
    • 3.搭建minio模块
        • 1.创建一个oss模块
          • 1.在sun-common下创建
          • 2.引入minio依赖
            • 1.sun-dependencies 锁定版本
            • 2.sun-common-oss 引入依赖
        • 2.sun-common-oss 模块
          • 1.概览
          • 2.MinioConfig.java
          • 3.FileInfo.java
          • 4.MinioUtil.java
          • 5.StorageAdapter.java
          • 6.MinioStorageAdapter.java
        • 3.sun-demo操作minio
          • 1.引入sun-common-oss
          • 2.application.yml 配置minio参数
          • 3.暴露接口 MinioController.java
          • 4.测试

1.介绍

1.分布式文件系统

CleanShot 2024-08-02 at 15.21.59@2x

CleanShot 2024-08-02 at 15.22.16@2x

2.基本概念

CleanShot 2024-08-02 at 15.34.01@2x

2.环境搭建

1.访问网址

http://ip:9090/

2.账号密码都是minioadmin
3.创建一个桶

CleanShot 2024-08-02 at 15.35.14@2x

CleanShot 2024-08-02 at 15.35.50@2x

4.Docker安装miniomc突破7天限制
1.拉取镜像
docker pull minio/mc:RELEASE.2023-11-15T22-45-58Z.fips
2.运行容器
docker run -it --entrypoint=/bin/sh minio/mc:RELEASE.2023-11-15T22-45-58Z.fips
3.进行配置
1.格式
mc config host add <ALIAS> <YOUR-S3-ENDPOINT> <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY>
2.具体配置
mc config host add minio http://ip:9000 9i14IBbM2ysYVPDa52oK eXRpXcXcX5w4Tmy8HprUkemVi5zzrbpS4NksxxtU
4.查看桶
mc ls minio
5.给桶开放权限
mc anonymous set download minio/桶

3.搭建minio模块

1.创建一个oss模块
1.在sun-common下创建

CleanShot 2024-08-02 at 15.37.36@2x

2.引入minio依赖
1.sun-dependencies 锁定版本
        <minio.version>8.2.0</minio.version>
        
        <!-- minio依赖 -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>${minio.version}</version>
        </dependency>
2.sun-common-oss 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- 继承父模块的版本和通用依赖 -->
    <parent>
        <groupId>com.sunxiansheng</groupId>
        <artifactId>sun-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>sun-common-oss</artifactId>
    <!-- 子模块的version,如果不写就默认跟父模块的一样 -->
    <version>${children.version}</version>

    <dependencies>
        <!-- minio依赖 -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
        </dependency>
        <!-- spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>
2.sun-common-oss 模块
1.概览

CleanShot 2024-08-02 at 17.55.46@2x

2.MinioConfig.java
package com.sunxiansheng.oss.config;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Description: minio配置管理
 * @Author sun
 * @Create 2024/5/31 9:22
 * @Version 1.0
 */
@Configuration
public class MinioConfig {

    /**
     * minioUrl
     */
    @Value("${minio.url}")
    private String url;

    /**
     * minio账户
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * minio密码
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 构造minioClient
     */
    @Bean
    public MinioClient getMinioClient() {
        return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
    }

}

3.FileInfo.java
package com.sunxiansheng.oss.entity;

import lombok.Data;

/**
 * FileInfo类用于存储文件的基本信息,包括文件名、是否为目录的标志以及文件的ETag。
 * 这个类可以在对象存储系统中用于描述文件的属性。
 * @Author sun
 * @Create 2024/5/31 9:47
 * @Version 1.0
 */
@Data
public class FileInfo {

    // 文件的名称
    private String fileName;

    // 指示该文件是否为目录的标志
    private Boolean directoryFlag;

    // 文件的ETag,用于标识文件的唯一性
    private String etag;

}
4.MinioUtil.java
package com.sunxiansheng.oss.util;

import com.sunxiansheng.oss.entity.FileInfo;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * MinioUtil是一个用于与MinIO对象存储服务进行交互的工具类。
 * 提供了一系列方法用于管理存储桶和对象,包括创建桶、上传文件、下载文件、删除文件等操作。
 * @Author sun
 * @Create 2024/5/31 9:30
 * @Version 1.0
 */
@Component
public class MinioUtil {

    @Resource
    private MinioClient minioClient; // MinIO客户端实例,用于执行各种存储操作。

    /**
     * 创建存储桶。
     * 如果指定名称的存储桶不存在,则创建它。
     *
     * @param bucket 存储桶的名称
     * @throws Exception 如果创建存储桶时发生错误
     */
    public void createBucket(String bucket) throws Exception {
        boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!exists) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
        }
    }

    /**
     * 上传文件到指定存储桶。
     *
     * @param inputStream 文件输入流
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @throws Exception 如果上传文件时发生错误
     */
    public void uploadFile(InputStream inputStream, String bucket, String objectName) throws Exception {
        minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
                .stream(inputStream, -1, 5242889L).build());
    }

    /**
     * 获取所有存储桶的名称列表。
     *
     * @return 存储桶名称的列表
     * @throws Exception 如果获取存储桶列表时发生错误
     */
    public List<String> getAllBucket() throws Exception {
        List<Bucket> buckets = minioClient.listBuckets();
        return buckets.stream().map(Bucket::name).collect(Collectors.toList());
    }

    /**
     * 获取指定存储桶中的所有文件信息。
     *
     * @param bucket 存储桶的名称
     * @return 文件信息列表,其中包含文件名、是否为目录标志和ETag
     * @throws Exception 如果获取文件列表时发生错误
     */
    public List<FileInfo> getAllFile(String bucket) throws Exception {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucket).build());
        List<FileInfo> fileInfoList = new LinkedList<>();
        for (Result<Item> result : results) {
            FileInfo fileInfo = new FileInfo();
            Item item = result.get();
            fileInfo.setFileName(item.objectName());
            fileInfo.setDirectoryFlag(item.isDir());
            fileInfo.setEtag(item.etag());
            fileInfoList.add(fileInfo);
        }
        return fileInfoList;
    }

    /**
     * 从指定存储桶下载文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件输入流,用于读取下载的文件内容
     * @throws Exception 如果下载文件时发生错误
     */
    public InputStream downLoad(String bucket, String objectName) throws Exception {
        return minioClient.getObject(
                GetObjectArgs.builder().bucket(bucket).object(objectName).build()
        );
    }

    /**
     * 删除指定存储桶。
     * 注意:存储桶必须为空才能被删除。
     *
     * @param bucket 存储桶的名称
     * @throws Exception 如果删除存储桶时发生错误
     */
    public void deleteBucket(String bucket) throws Exception {
        minioClient.removeBucket(
                RemoveBucketArgs.builder().bucket(bucket).build()
        );
    }

    /**
     * 删除指定存储桶中的文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即要删除的文件在存储桶中的名称
     * @throws Exception 如果删除文件时发生错误
     */
    public void deleteObject(String bucket, String objectName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()
        );
    }

    /**
     * 获取文件的预览URL。
     * 该URL可以用于在浏览器中查看或下载文件。
     *
     * @param bucketName 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件的预签名URL
     * @throws Exception 如果获取预签名URL时发生错误
     */
    public String getPreviewFileUrl(String bucketName, String objectName) throws Exception{
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName).object(objectName).build();
        return minioClient.getPresignedObjectUrl(args);
    }
}
5.StorageAdapter.java
package com.sunxiansheng.oss.adapter;

import com.sunxiansheng.oss.entity.FileInfo;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;

/**
 * StorageAdapter接口定义了与对象存储服务交互的方法。
 * 这些方法提供了基本的存储操作,如创建存储桶、上传和下载文件、获取文件信息等。
 * @Author sun
 * @Create 2024/5/31 10:03
 * @Version 1.0
 */
public interface StorageAdapter {

    /**
     * 创建存储桶。
     * 如果指定名称的存储桶不存在,则创建它。
     *
     * @param bucket 存储桶的名称
     */
    void createBucket(String bucket);

    /**
     * 上传文件到指定存储桶。
     *
     * @param uploadFile 要上传的文件
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     */
    String uploadFile(MultipartFile uploadFile, String bucket, String objectName);

    /**
     * 获取所有存储桶的名称列表。
     *
     * @return 存储桶名称的列表
     */
    List<String> getAllBucket();

    /**
     * 获取指定存储桶中的所有文件信息。
     *
     * @param bucket 存储桶的名称
     * @return 文件信息列表,其中包含文件名、是否为目录标志和ETag
     */
    List<FileInfo> getAllFile(String bucket);

    /**
     * 从指定存储桶下载文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件输入流,用于读取下载的文件内容
     */
    InputStream downLoad(String bucket, String objectName);

    /**
     * 删除指定存储桶。
     * 注意:存储桶必须为空才能被删除。
     *
     * @param bucket 存储桶的名称
     */
    void deleteBucket(String bucket);

    /**
     * 删除指定存储桶中的文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即要删除的文件在存储桶中的名称
     */
    void deleteObject(String bucket, String objectName);

    /**
     * 获取文件的访问URL。
     * 该URL可以用于在浏览器中查看或下载文件。
     * @param originalFilename 原始文件名
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件的URL
     */
    public String getUrl(String originalFilename, String bucket, String objectName);
}
6.MinioStorageAdapter.java
package com.sunxiansheng.oss.adapter;

import com.sunxiansheng.oss.entity.FileInfo;
import com.sunxiansheng.oss.util.MinioUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.List;

/**
 * MinioStorageAdapter类实现了StorageAdapter接口,使用MinioUtil类与MinIO对象存储服务进行交互。
 * 提供了一系列方法来管理存储桶和对象,包括创建桶、上传文件、下载文件、删除文件等操作。
 * @Author sun
 * @Create 2024/5/31 10:06
 * @Version 1.0
 */
@Component
public class MinioStorageAdapter implements StorageAdapter {

    @Resource
    private MinioUtil minioUtil; // 使用MinioUtil工具类来执行存储操作

    /**
     * MinIO服务的URL。
     * 该URL通常在配置文件中设置,用于构建文件访问的完整URL。
     */
    @Value("${minio.url}")
    private String url;

    /**
     * 创建存储桶。
     * 使用MinioUtil工具类创建存储桶。
     *
     * @param bucket 存储桶的名称
     */
    @Override
    @SneakyThrows
    public void createBucket(String bucket) {
        minioUtil.createBucket(bucket);
    }

    // ============================== 文件上传后的URL:url + 桶名 + 上传时的objectName ==============================
    /**
     * 上传文件到指定存储桶,并返回可访问的url
     * 使用提供的对象名称或文件的原始名称进行上传。
     *
     * @param uploadFile 要上传的文件
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,表示完整的文件路径和名称
     */
    @Override
    @SneakyThrows
    public String uploadFile(MultipartFile uploadFile, String bucket, String objectName) {
        minioUtil.createBucket(bucket);
        String finalObjectName = generateObjectName(uploadFile.getOriginalFilename(), objectName);
        minioUtil.uploadFile(uploadFile.getInputStream(), bucket, finalObjectName);
        return getUrl(uploadFile.getOriginalFilename(), bucket, objectName);
    }

    /**
     * 自定义对象名的格式,上传时的对象名是什么格式,那么下载时的对象名也是什么格式
     * url的格式就是 url + 桶名 + 对象名
     *
     * @param originalFilename 原始文件名字
     * @param objectName 提供的对象名称
     * @return 最终用于存储的对象名称
     */
    private String generateObjectName(String originalFilename, String objectName) {
        // 如果对象名为空,则使用文件的原始名称作为对象名
        if (objectName == null) {
            return originalFilename;
        }
        // 如果对象名不为空,则对象名 + / + 文件名作为对象名
        return objectName + "/" + originalFilename;
    }

    /**
     * 获取文件的访问URL。
     * 该URL可以用于在浏览器中查看或下载文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件的完整URL
     */
    @Override
    @SneakyThrows
    public String getUrl(String originalFilename, String bucket, String objectName) {
        // 首先生成对象名
        String finalObjectName = generateObjectName(originalFilename, objectName);
        // url的格式就是 url + 桶名 + 对象名
        return url + "/" + bucket + "/" + finalObjectName;
    }
    // ============================== 文件上传后的URL:url + 桶名 + 上传时的objectName ==============================

    /**
     * 获取所有存储桶的名称列表。
     *
     * @return 存储桶名称的列表
     */
    @Override
    @SneakyThrows
    public List<String> getAllBucket() {
        return minioUtil.getAllBucket();
    }

    /**
     * 获取指定存储桶中的所有文件信息。
     *
     * @param bucket 存储桶的名称
     * @return 文件信息列表,其中包含文件名、是否为目录标志和ETag
     */
    @Override
    @SneakyThrows
    public List<FileInfo> getAllFile(String bucket) {
        return minioUtil.getAllFile(bucket);
    }

    /**
     * 从指定存储桶下载文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即文件在存储桶中的名称
     * @return 文件输入流,用于读取下载的文件内容
     */
    @Override
    @SneakyThrows
    public InputStream downLoad(String bucket, String objectName) {
        return minioUtil.downLoad(bucket, objectName);
    }

    /**
     * 删除指定存储桶。
     * 注意:存储桶必须为空才能被删除。
     *
     * @param bucket 存储桶的名称
     */
    @Override
    @SneakyThrows
    public void deleteBucket(String bucket) {
        minioUtil.deleteBucket(bucket);
    }

    /**
     * 删除指定存储桶中的文件。
     *
     * @param bucket 存储桶的名称
     * @param objectName 对象名称,即要删除的文件在存储桶中的名称
     */
    @Override
    @SneakyThrows
    public void deleteObject(String bucket, String objectName) {
        minioUtil.deleteObject(bucket, objectName);
    }

}
3.sun-demo操作minio
1.引入sun-common-oss
        <!-- 引入sun-common-oss -->
        <dependency>
            <groupId>com.sunxiansheng</groupId>
            <artifactId>sun-common-oss</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
2.application.yml 配置minio参数
# minio配置
minio:
  url: http://ip:9000
  accessKey: minioadmin
  secretKey: minioadmin
3.暴露接口 MinioController.java
package com.sunxiansheng.user.controller;

import com.sunxiansheng.oss.adapter.StorageAdapter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

/**
 * Description:
 * @Author sun
 * @Create 2024/8/2 16:25
 * @Version 1.0
 */
@RestController
public class MinioController {

    @Resource
    private StorageAdapter storageAdapter;

    /**
     * 上传文件并返回url
     */
    @RequestMapping("/upload")
    public String upload(MultipartFile uploadFile, String bucket, String objectName) throws Exception {
        return storageAdapter.uploadFile(uploadFile, bucket, objectName);
    }

}
4.测试

CleanShot 2024-08-02 at 18.18.25@2x

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

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

相关文章

目标检测入门指南:从原理到实践

目录 1. 数据准备与预处理 2. 模型架构设计 2.1 特征提取网络原理 2.2 区域提议网络(RPN)原理 2.3 特征金字塔网络(FPN)原理 2.4 边界框回归原理 2.5 非极大值抑制(NMS)原理 2.6 多尺度训练与测试原理 2.7 损失函数设计原理 3. 损失函数设计 4. 训练策略优化 5. 后…

react中实现拖拽排序

效果图&#xff1a;如下 效果说明&#xff1a; 1. 点击“选择”按钮&#xff0c;打开弹窗 2. 左侧数据是调接口回显来的 3. 点击左侧某条数据&#xff0c;这条被点击的数据就会被添加到右侧 4. 右侧的数据可以上下拖动换位置 5. 右侧有数据时&#xff0c;点击"确定"…

亚马逊国际站商品爬虫:Python实战指南

在数字化时代&#xff0c;数据的价值不言而喻。对于电商领域而言&#xff0c;获取竞争对手的商品信息、价格、评价等数据&#xff0c;对于市场分析和策略制定至关重要。本文将带你了解如何使用Python编写爬虫&#xff0c;以亚马逊国际站为例&#xff0c;按照关键字搜索并获取商…

Problem: 3046. 分割数组(LeetCode)

题目来源&#xff1a; https://leetcode.cn/problems/split-the-array/description/3046. 分割数组 - 给你一个长度为 偶数 的整数数组 nums 。你需要将这个数组分割成 nums1 和 nums2 两部分&#xff0c;要求&#xff1a; * nums1.length nums2.length nums.length / 2 。 *…

InstructGPT:基于人类反馈训练语言模型遵从指令的能力

大家读完觉得有意义记得关注和点赞&#xff01;&#xff01;&#xff01; 大模型进化树&#xff0c;可以看到 InstructGPT 所处的年代和位置。来自 大语言模型&#xff08;LLM&#xff09;综述与实用指南&#xff08;Amazon&#xff0c;2023&#xff09; 目录 摘要 1 引言 …

【浏览器】缓存

为什么有缓存&#xff1f; 在一个C/S结构中&#xff0c;最基本的缓存分为两种&#xff1a; 客户端缓存服务器缓存 以下重点讲客户端缓存 所谓客户端缓存&#xff0c;顾名思义&#xff0c;是将某一次的响应结果保存在客户端&#xff08;比如浏览器&#xff09;中&#xff0c;而…

产品原型设计

&#x1f923;&#x1f923;目录&#x1f923;&#x1f923; 一、Axure原型设计&#xff08;Axure RP 9 &#xff09;1.1 软件下载安装1.2 产品原型展示1.3 产品原型下载1.4 视频课程推荐 二、磨刀原型设计2.1 软件下载安装2.2 产品原型展示2.3 产品原型下载2.4 视频课程推荐 什…

力扣-数据结构-7【算法学习day.78】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(一)

****非斜体正文为原文献内容&#xff08;也包含笔者的补充&#xff09;&#xff0c;灰色块中是对文章细节的进一步详细解释&#xff01; 三、传统微调范式&#xff08;Traditional Fine-Tuning Paradigm&#xff09; 在这个范式中&#xff0c;首先在大量未标记的文本数据上预…

基于springboot的膳食问答系统的设计与实现

摘 要 本文介绍了一个基于SpringBoot框架的膳食问答系统&#xff0c;该系统融合了文章查看、膳食问答、用户管理、文章管理、知识点管理、系统日志查看、在线用户查看以及办公管理等多项功能。系统采用主流界面设计风格&#xff0c;前端使用HTML构建用户界面&#xff0c;后端则…

LeetCode - Google 校招100题 第7天 序列(数据结构贪心) (15题)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/144744418 相关文章&#xff1a; LeetCode 合计最常见的 112 题&#xff1a; 校招100题 第1天 链表(List) (19题)校招100题 第2天 树(Tree) (21…

《Java核心技术 卷II》流的创建

流的创建 Collection接口中stream方法可以将任何集合转换为一个流。 用静态Stream.of转化成数组。 Stream words Stream.of(contents.split("\\PL")); of方法具有可变长参数&#xff0c;可以构建具有任意数量的流。 使用Array.stream(array,from,to)可以用数组…

应用层协议(Https)(超详解)

前言&#xff1a; https是在http基础上的进行一些"加密"操作&#xff0c;也可以认为是http的强化版。 在下面展开对https的讨论中&#xff0c;可能不会再涉及到http的相关协议&#xff0c;如有对http的疑惑或是其他不一样的看法可以浏览上一篇文章&#xff1a;应用层…

ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础

文章目录 简介为什么需要I2S&#xff1f;关于音频信号采样率分辨率音频声道 怎样使用I2S传输音频&#xff1f;位时钟BCLK字时钟WS串行数据SD I2S传输模型I2S通信格式I2S格式左对齐格式右对齐格式 i2s基本配置i2s 底层API加载I2S驱动设置I2S使用的引脚I2S读取数据I2S发送数据卸载…

优化租赁小程序提升服务效率与用户体验的策略与实践

内容概要 在这个快速发展的商业环境中&#xff0c;租赁小程序成为了提升服务效率和用户体验的重要工具。通过对用户需求的深入挖掘&#xff0c;我们发现他们对于功能的便捷性、响应速度和界面的友好性有着极高的期待。因此&#xff0c;针对这些需求&#xff0c;完善租赁小程序…

HTML——13.超链接

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>超链接</title></head><body><!--超链接:从一个网页链接到另一个网页--><!--语法&#xff1a;<a href"淘宝网链接的地址"> 淘宝…

day-102 二进制矩阵中的最短路径

思路 BFS 解题过程 从起点依次向八个方向尝试&#xff08;之后也一样&#xff09;&#xff0c;如果某个位置在矩阵内且值为0且没有访问过&#xff0c;将其添加到一个队列中&#xff0c;依次类推&#xff0c;直到到达出口 Code class Solution {public int shortestPathBinar…

王佩丰24节Excel学习笔记——第十八讲:Lookup和数组

【以 Excel2010 系列学习&#xff0c;用 Office LTSC 专业增强版 2021 实践】 【本章技巧】 地址栏公式可以使用 F9 查看&#xff0c;取消请按Esc键&#xff0c;或者公式前的红色叉&#xff1b;使用数组时一定要注意使用绝对引用&#xff0c;方便下拉&#xff1b;使用数组时一…

Java - 日志体系_Simple Logging Facade for Java (SLF4J)日志门面_SLF4J集成Log4j1.x 及 原理分析

文章目录 Pre官网集成Log4j1.x步骤POM依赖使用第一步&#xff1a;编写 Log4j 配置文件第二步&#xff1a;代码 原理分析1. 获取对应的 ILoggerFactory2. 根据 ILoggerFactory 获取 Logger 实例3. 日志记录过程 小结 Pre Java - 日志体系_Apache Commons Logging&#xff08;JC…

嵌入式开发中的机器人表情绘制

机器人的表情有两种&#xff0c;一种是贴图&#xff0c;一钟是调用图形API自绘。 贴图效果相对比较好&#xff0c;在存储空间大的情况下是可以采用的。 自绘比较麻烦&#xff0c;但在资源和空缺少的情况下&#xff0c;也是很有用的。而且自绘很容易通过调整参数加入随机效果&…