spring boot + minio 分布式文件上传

news2024/11/26 14:57:46

介绍

1、分布式文件系统

简单理解为:一个计算机无法存储海量的文件,通过网络将若干计算机组织起来共同去存储海量的文件,去接收海量用户的请求,这些组织起来的计算机通过网络进行通信。

好处:

  • 一台计算机的文件系统处理能力扩充到多台计算机同时处理。
  • 一台计算机挂了还有另外副本计算机提供数据。
  • 每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度。

在这里插入图片描述

2、市面上有哪些分布式文件系统的产品呢?

2.1、网络文件系统(NFS)

特点:

  • 在客户端上映射NFS服务器的驱动器。
  • 客户端通过网络访问NFS服务器的硬盘完全透明。

2.2、GFS

特点:

  • GFS采用主从结构,一个GFS集群由一个master和大量的chunkserver组成。
  • master存储了数据文件的元数据,一个文件被分成了若干块存储在多个chunkserver中。
  • 用户从master中获取数据元信息,向chunkserver存储数据。

2.3、HDFS

HDFS,是Hadoop Distributed File System的简称,是Hadoop抽象文件系统的一种实现。HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。 HDFS的文件分布在集群机器上,同时提供副本进行容错及可靠性保证。例如客户端写入读取文件的直接操作都是分布在集群各个机器上的,没有单点性能压力。

特点:

  • HDFS采用主从结构,一个HDFS集群由一个名称结点和若干数据结点组成。
  • 名称结点存储数据的元信息,一个完整的数据文件分成若干块存储在数据结点。
  • 客户端从名称结点获取数据的元信息及数据分块的信息,得到信息客户端即可从数据块来存取数据。

2.4、云计算厂家

  • 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.9999999999%(12 个 9),服务设计可用性(或业务连续性)不低于 99.995%。
    官方网站:https://www.aliyun.com/product/oss
  • 百度对象存储BOS提供稳定、安全、高效、高可扩展的云存储服务。您可以将任意数量和形式的非结构化数据存入BOS,并对数据进行管理和处理。BOS支持标准、低频、冷和归档存储等多种存储类型,满足多场景的存储需求。
    官方网站:https://cloud.baidu.com/product/bos.html

3、MinIO

3.1、介绍

官网:https://min.io
中文:https://www.minio.org.cn/,http://docs.minio.org.cn/docs/

本项目采用MinIO构建分布式文件系统,MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合使用,它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。

它一大特点就是轻量,使用简单,功能强大,支持各种平台,单个文件最大5TB,兼容 Amazon S3接口,提供了 Java、Python、GO等多版本SDK支持。

MinIO集群采用去中心化共享架构,每个结点是对等关系,通过Nginx可对MinIO进行负载均衡访问。

去中心化有什么好处?

  • 在大数据领域,通常的设计理念都是无中心和分布式。Minio分布式模式可以帮助你搭建一个高可用的对象存储服务,你可以使用这些存储设备,而不用考虑其真实物理位置。
  • 它将分布在不同服务器上的多块硬盘组成一个对象存储服务。由于硬盘分布在不同的节点上,分布式Minio避免了单点故障。如下图:
    在这里插入图片描述

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

使用纠删码的好处是即便丢失一半数量(N/2)的硬盘,仍然可以恢复数据。 比如上边集合中有4个以内的硬盘损害仍可保证数据恢复,不影响上传和下载,如果多于一半的硬盘坏了则无法恢复。

3.2、Windows安装测试

3.2.1、下载安装

在官网下载minio.exe文件即可
地址:https://www.minio.org.cn/download.shtml#/windows
在这里插入图片描述

3.2.2、启动

CMD进入有minio.exe的目录,运行下边的命令:

minio.exe server D:\my\minio_data\data1  D:\my\minio_data\data2 D:\my\minio_data\data3 D:\my\minio_data\data4

在这里插入图片描述

  • 老版本使用的MINIO_ACCESS_KEY 和 MINIO_SECRET_KEY不推荐使用,推荐使用MINIO_ROOT_USER 和MINIO_ROOT_PASSWORD设置账号和密码。
  • pool即minio节点组成的池子,当前有一个pool和4个硬盘组成的set集合
  • 因为集合是4个硬盘,大于2的硬盘损坏数据将无法恢复。
  • 账号和密码默认为minioadmin、minioadmin,可以在环境变量中设置通过’MINIO_ROOT_USER’ and ‘MINIO_ROOT_PASSWORD’ 进行设置。
3.2.3、访问,登录

http://localhost:9000
默认账号密码:minioadmin
在这里插入图片描述

3.3.4、创建Bucket桶
  • 系统页面创建
    在这里插入图片描述
    在这里插入图片描述
  • 存储目录查看
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
3.2.5、上传文件
  • 系统页面上传
    在这里插入图片描述

在这里插入图片描述

  • 目录查看
    在这里插入图片描述

SDK操作(java代码)

1、引入依赖

        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.8.1</version>
        </dependency>
        <!-- 测试的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

2、上传文件

连接

  • endpoint:minio服务的地址
  • credentials:用户密码

上传

  • bucket:桶的名称
  • object:上传后的对象名称
  • filename:要上传的文件的路径
public class MinIOTest {

//    连接minio
    static MinioClient minioClient =
            MinioClient.builder()
                    .endpoint("http://localhost:9000")
                    .credentials("minioadmin", "minioadmin")
                    .build();


    @Test
    public void upload() {

        try {
            UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket("myfile")
                    .object("刘亦菲.jpeg")//同一个桶内对象名不能重复
                    .filename("C:\\Users\\86152\\Pictures\\Camera Roll\\lyf01.jpeg")
                    .build();
            //上传
            minioClient.uploadObject(uploadObjectArgs);
            System.out.println("上传成功了");
        } catch (Exception e) {
            System.out.println("上传失败");
        }
    }
}

3、删除文件

    //删除文件
    @Test
    public void delete() {

        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs
                    .builder()
                    .bucket("myfile")
                    .object("刘亦菲.jpeg")
                    .build();
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
        }
    }

没有了
在这里插入图片描述

4、查询文件(下载文件)

//查询文件
    @Test
    public void getFile() {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket("myfile").object("高圆圆.jpeg").build();
        try(
                FilterInputStream inputStream = minioClient.getObject(getObjectArgs);
                FileOutputStream outputStream = new FileOutputStream(new File("D:\\my\\minio_data\\gyy.jpeg"));
                ) {

            if(inputStream!=null){
                IOUtils.copy(inputStream,outputStream);
            }
        } catch (Exception e) {
        }

    }

在这里插入图片描述

文件上传(实战)

1、引入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.8.1</version>
        </dependency>
        <!-- 测试的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

        <!-- mybatis plus 代码生成器 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.9</version>
        </dependency>

        <!-- druid 连接池管理 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>

        <!-- mySQL数据库驱动包管理 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <!-- fastjson ,json解析工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

        <!-- 工具类管理 -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>

        <!--google推荐的一套工具类库-->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.0-jre</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
        </dependency>

        <!-- Servlet 容器管理 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- Spring Boot 集成 log4j2 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</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>
    </dependencies>

2、环境配置

server.port=9001
spring.application.name=file


spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url: jdbc:mysql://localhost:3306/hm?serverTimezone=UTC&userUnicode=true&useSSL=false&
spring.datasource.username: root
spring.datasource.password: zzybzb


# 日志文件配置路径
logging.config=classpath:log4j2-dev.xml

minio.endpoint=http://localhost:9000
minio.accessKey=minioadmin
minio.secretKey=minioadmin
minio.bucket.files=myfile

spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=50MB

3、关键代码

3.1、minio配置类

package com.file.config;

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

/**
    minio配置类
 */
@Configuration
public class MinioConfig {

    //读取参数

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

    @Bean
    public MinioClient minioClient() {

        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(endpoint)
                        .credentials(accessKey, secretKey)
                        .build();
        return minioClient;
    }
}

3.2、controller层代码

    @RequestMapping(value = "/upload/coursefile", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile filedata,
                                      @RequestParam(value = "folder",required=false) String folder,
                                      @RequestParam(value= "objectName",required=false) String objectName) {

        Long companyId = 1232141425L;
        UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();
        String contentType = filedata.getContentType();
        uploadFileParamsDto.setContentType(contentType);
        uploadFileParamsDto.setFileSize(filedata.getSize());//文件大小
        if (contentType.indexOf("image") >= 0) {
            //是个图片
            uploadFileParamsDto.setFileType("001001");
        } else {
            uploadFileParamsDto.setFileType("001003");
        }
        uploadFileParamsDto.setFilename(filedata.getOriginalFilename());//文件名称
        UploadFileResultDto uploadFileResultDto = null;
        try {
            uploadFileResultDto = mediaFileService.uploadFile(companyId, uploadFileParamsDto, filedata.getBytes(), folder, objectName);
        } catch (Exception e) {
            XueChengPlusException.cast("上传文件过程中出错");
        }

        return uploadFileResultDto;

    }

3.3、service层代码

  • service
public interface MediaFileService {
	 /**
	  * @description 上传文件的通用接口
	  * @param companyId  机构id
	  * @param uploadFileParamsDto  文件信息
	  * @param bytes  文件字节数组
	  * @param folder 桶下边的子目录
	  * @param objectName 对象名称
	 */
	 public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, byte[] bytes, String folder, String objectName);

}
  • impl代码
@Slf4j
@Service
public class MediaFileServiceImpl implements MediaFileService {

    @Autowired
    MediaFilesMapper mediaFilesMapper;

    @Autowired
    MinioClient minioClient;

    @Value("${minio.bucket.files}")
    private String bucket_files;

    @Override
    public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, byte[] bytes, String folder, String objectName) {


        //得到文件的md5值
        String fileMd5 = DigestUtils.md5DigestAsHex(bytes);

        if(StringUtils.isEmpty(folder)){
            //自动生成目录的路径 按年月日生成,
            folder = getFileFolder(new Date(), true, true, true);
        }else if(folder.indexOf("/")<0){
            folder = folder+"/";
        }
        //文件名称
        String filename = uploadFileParamsDto.getFilename();

        if(StringUtils.isEmpty(objectName)){
            //如果objectName为空,使用文件的md5值为objectName
            objectName = fileMd5 + filename.substring(filename.lastIndexOf("."));
        }

        objectName = folder + objectName;

        try {
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            String contentType = uploadFileParamsDto.getContentType();

            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucket_files)
                    .object(objectName)
                    //InputStream stream, long objectSize 对象大小, long partSize 分片大小(-1表示5M,最大不要超过5T,最多10000)
                    .stream(byteArrayInputStream, byteArrayInputStream.available(), -1)
                    .contentType(contentType)
                    .build();
            //上传到minio
            minioClient.putObject(putObjectArgs);

            //保存到数据库
            MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);
            if(mediaFiles == null){
                mediaFiles = new MediaFiles();

                //封装数据
                BeanUtils.copyProperties(uploadFileParamsDto,mediaFiles);
                mediaFiles.setId(fileMd5);
                mediaFiles.setFileId(fileMd5);
                mediaFiles.setCompanyId(companyId);
                mediaFiles.setFilename(filename);
                mediaFiles.setBucket(bucket_files);
                mediaFiles.setFilePath(objectName);
                mediaFiles.setUrl("/"+bucket_files+"/"+objectName);
                mediaFiles.setCreateDate(new Date());
                mediaFiles.setStatus("1");
                mediaFiles.setAuditStatus("002003");

                //插入文件表
                mediaFilesMapper.insert(mediaFiles);

            }

            //准备返回数据
            UploadFileResultDto uploadFileResultDto = new UploadFileResultDto();
            BeanUtils.copyProperties(mediaFiles,uploadFileResultDto);
            return uploadFileResultDto;


        } catch (Exception e) {
            log.debug("上传文件失败:{}",e.getMessage());
        }

        return null;
    }

    //根据日期拼接目录
    private String getFileFolder(Date date, boolean year, boolean month, boolean day){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //获取当前日期字符串
        String dateString = sdf.format(new Date());
        //取出年、月、日
        String[] dateStringArray = dateString.split("-");
        StringBuffer folderString = new StringBuffer();
        if(year){
            folderString.append(dateStringArray[0]);
            folderString.append("/");
        }
        if(month){
            folderString.append(dateStringArray[1]);
            folderString.append("/");
        }
        if(day){
            folderString.append(dateStringArray[2]);
            folderString.append("/");
        }
        return folderString.toString();
    }
}

3.4、mapper层代码

@Mapper
public interface MediaFilesMapper extends BaseMapper<MediaFiles> {

}

4、启动项目,测试

  • 使用httpclient测试
### 上传文件
POST http://localhost:9001/upload/coursefile
Content-Type: multipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Disposition: form-data; name="filedata"; filename="widget-3.jpg"
Content-Type: application/octet-stream

< C:\Users\86152\Pictures\Camera Roll\lyf01.jpeg

在这里插入图片描述

  • 执行结果
    在这里插入图片描述
  • 查看数据库
    在这里插入图片描述
  • 查看miniO存储目录
    在这里插入图片描述

上传成功。

结束!!!
hy:11


										谎言最大的伤害是让人们不再相信真相。---苏格拉底

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

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

相关文章

固定风格任意内容的快速风格迁移(讲解网络模型部分)

目录 一、目标&#xff1a;求出一个某种固定风格图像转换网络二、对比一下&#xff1a;v1算法和v2算法的区别在哪里&#xff1f;三、参数四、v2算法的优点五、图像风格转换算法的扩展性六、网络细节&#xff08;该算法的特点&#xff09;七、参考资料 下面我们统一把&#xff1…

《计算机网络——自顶向下方法》精炼——4.3.1-4.4.1

学习和研究好比爬梯子,要一步一步地往上爬,企图一脚跨上四五步,平地登天,那就必须会摔跤了。——华罗庚 文章目录 路由器工作原理输入端口概述交换结构概述输出端口何处出现排队路由选择控制平面 网际协议&#xff1a;因特网中的转发和编址数据报格式IP数据报分片 路由器工作原…

29 # node 中的 eventloop

process.cwd cwd&#xff1a;current working directory 表示当前用户的工作目录&#xff08;这个目录可以更改用户自己切换即可&#xff09; 当用户在哪执行 node 命令&#xff0c;就去哪找配置文件 console.log(process.cwd());__dirname&#xff1a;表示当前文件所在的目…

【计算机网络】网络编程套接字(一)

目录 1.预备知识 1.1.理解源IP地址和目的IP地址 1.2.认识端口号 1.2.1.理解"端口号"和"进程ID" 1.2.2.理解源端口号和目的端口号 1.3.认识TCP/UDP协议 1.3.1.TCP协议 1.3.2.UDP协议 1.4.网络字节序 网络字节序和主机字节序的转换 2.socket编程接…

8B/10B编码

8B/10B编码 8B/10B编码介绍实现方式8b/10b编码中的编码表和字节编码RD控制符号 8B/10B编码 介绍 8b/10b编码是将8位符号映射到10位符号&#xff0c;以实现直流平衡&#xff0c;同时提供足够多的状态来实现时钟恢复。这意味着在一个至少20位的字符串中&#xff0c;1和0的计数之…

[论文阅读笔记74]The Power of Scale for Parameter-Efficient Prompt Tuning

1. 基本信息 题目论文作者与单位来源年份The Power of Scale for Parameter-Effificient Prompt TuningBrian Lester等googleConference on Empirical Methods in Natural Language Processing2021 857 Citations 论文链接&#xff1a;https://arxiv.org/abs/2104.08691 论…

配置SSH远程登录和免密登录

上一篇我们已经讲了如何配置修改Linux的主机名和网络设置&#xff0c;这一篇我们来讲一下配置Linux的SSH免密登录。   首先讲一下我们为什么要配置SSH 免密登录&#xff0c;通过VMware Workstation工具操作虚拟机十分不方便&#xff0c;无法复制内容到虚拟机中&#xff0c;也…

Python使用多进程并行加速业务操作 完整代码

Python使用多进程并行加速业务操作 完整代码 需求分析 完整代码 本demo性能分析 Python中单线程、多线程和多进程的效率对比实验 需求分析 最近在对一个数据集进行处理&#xff0c;共2000条&#xff0c;每条去调一个第三方接口&#xff0c;耗时7-10秒。单线程处理一次要3.…

Vue - 项目编译速度、性能优化、打包体积优化

GitHub Demo 地址 在线预览 Vue - 项目编译速度、性能优化、打包体积优化 序一、编译速度优化1、使用缓存1.1、缓存插件 - HardSourceWebpackPlugin1.2、webpack5 配置cache1.3、cache-loader 插件 2、合理使用source-map3、多线程打包3.1、thread-loader3.2、parallel-webpac…

阿里5面,成功唬住面试官拿了21K,面试也没有那么难吧....

阿里的面试挺独特&#xff0c;每轮面试都没有 HR 约时间&#xff0c;一般是晚上 8 点左右面试官来一个电话&#xff0c;问是否能面试&#xff0c;能的话开始面&#xff0c;不能就约一个其它时间。 全程 5 面&#xff0c;前四面技术面&#xff0c;电话面试&#xff0c;最后一面…

吴恩达 ChatGPT Prompt Engineering for Developers 系列课程笔记--08 Chatbot

08 Chatbot ChatGPT的一种重要功能是作为一个聊天机器人&#xff0c;本节将展示如何和ChatGPT进行对话 1) 不同的角色&#xff08;Roles&#xff09; 前面几节的课程中&#xff0c;我们通过如下函数调用ChatGPT的接口&#xff0c;输入用户输入的prompt&#xff0c;返回模型生…

第二章硬件入门之电容

第二章硬件入门之电容 文章目录 第二章硬件入门之电容一、电容是什么&#xff1f;二、实际应用场景常见电容&#xff1a;1.陶瓷电容&#xff08;无正负极之分&#xff09;1、旁路2、去耦 2.铝电解电容贴片式插件式3.安规电容x电容Y电容 总结 一、电容是什么&#xff1f; **电容…

【kernel exploit】CVE-2022-2602 UNIX_GC错误释放io_uring注册的file结构-UAF

本文主要参考 [漏洞分析] CVE-2022-2602 io_uring UAF内核提权详细解析 并做一些补充。 影响版本&#xff1a;Linux Kernel < v6.0.3。v6.0.3已修复。 测试版本&#xff1a;Linux-v6.0.2 &#xff08;v6.0.2 测试失败&#xff0c;v5.18.19测试成功&#xff09; exploit及测…

React Fiber 使用 MessageChannel + requestAnimationFrame 模拟实现 requestIdleCallback

由于 requestIdleCallback 兼容性较差且不支持 Safari&#xff0c;React Fiber 需要实现一个 requestIdleCallback polyfill 做浏览器兼容&#xff1b; MDN RequestIdleCallbackMDN RequestAnimationFrameMDN MessageChannel 以下为其使用 MessageChannel requestAnimationF…

vivado中ila的使用方法记录

ILA工具生成方法 一、 ILA工具介绍 在FPGA的开发中&#xff0c;当完成代码设计后&#xff0c;为了验证代码的准确性和各种不同条件下的可靠性&#xff0c;往往需要优先想到通过逻辑仿真进行相关验证。使用逻辑仿真进行验证虽然可以周密的考虑给出不同输入条件下的输出结果或交…

“智慧赋能 强链塑链”—— 汽车行业供应链管理数字化应用探讨

01车企供应链数字化的必要性 汽车供应链是一个复杂的系统&#xff0c;很多汽车企业因为供应链管理不当&#xff0c;造成资源浪费、成本高、客户满意度低等一系列问题&#xff1b;而汽车行业规模技术门槛高、配合协同复杂的特性&#xff0c;决定了其供应链缺口无法在短时间内填…

Three.js系列-报错export ‘Geometry‘ (imported as ‘THREE‘) was not found in ‘three‘

今天遇到报错export ‘Geometry’ (imported as ‘THREE’) was not found in ‘three’ port Geometry (imported as THREE) was not found in three (possible exports: ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, …

为什么大家都不用postman而选择 Apifox呢?

丢掉 Postman&#xff0c;Apifox 更香 作为开发者&#xff0c;丢掉 Postman 和 Jmeter吧&#xff0c;这款国产 API 工具更香&#xff0c;更安全&#xff01;一键即可导入 Postman 数据&#xff01; 一、Apifox 是什么&#xff1f; 1、Apifox 定位 Apifox Postman Swagger …

Altium Designer(AD)局域网内使用解冲突

1. Altium Designer 版本 AD15.0.8&#xff0c;电路设计软件&#xff0c;硬件工攻城狮必备技能&#xff0c;软件攻城狮也要会一点点 2. AD软件出现“Your license is already used on computer “LAPTOP-F99R6OR1” using product “AltiumDesigner” 用同事的安装包解压安装的…

Mysql 索引详细解析——底层->应用

1、索引的数据结构 1.1 概述 索引&#xff08;index&#xff09;是帮助Mysql高效获取数据的数据结构。 索引的本质&#xff1a; 索引是数据结构。简单理解为“排好序的快速查找数据结构”&#xff0c;满足特定查找算法。这些数据结构以某种方式指向数据&#xff0c; 这样就可…