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

news2025/1/4 14:56:55

文章目录

    • 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

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

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

相关文章

产品经理2025年展望

产品经理作为连接技术、设计与市场需求的桥梁&#xff0c;在快速变化的商业环境中扮演着至关重要的角色。展望2025年&#xff0c;随着技术的不断进步和消费者需求的日益多样化&#xff0c;产品经理的工作将面临更多挑战与机遇。 一、人工智能与自动化深化应用&#xff1a; 到…

风力涡轮机缺陷检测数据集,91.4%准确识别率,18912张图片,支持yolo,PASICAL VOC XML,COCO JSON格式的标注

风力涡轮机缺陷检测数据集&#xff0c;91.4&#xff05;准确识别率&#xff0c;18912张图片&#xff0c;支持yolo&#xff0c;PASICAL VOC XML&#xff0c;COCO JSON格式的标注 数据集下载&#xff1a; &#xff59;&#xff4f;&#xff4c;&#xff4f; &#xff56;&#…

五、Vue 循环语句

文章目录 简介一、基础数组迭代二、对象属性迭代三、整数循环 简介 在 Vue.js 的世界里&#xff0c;当我们需要处理重复性的结构并依据数据动态渲染时&#xff0c;v-for 指令就成了不可或缺的工具&#xff0c;它赋予开发者简洁且强大的能力&#xff0c;轻松应对各种列表渲染场景…

用css实现瀑布流布局

上效果 知识理解 column-count: 4; column-gap: 15px;实现固定四行瀑布流布局 columns: 200px auto;column-gap: 15px;由浏览器根据容器的宽度自动调整&#xff0c;尽可能一行多个200px宽度的列数 <!DOCTYPE html> <html lang"en"><head><me…

275-增强型多功能数据采集卡PCIe-6251-EX

产品特点&#xff1a; 高速高精度数据采集&#xff0c;16bit10MSPS&#xff0c;32路单端/16路差分高速高精度任意波形发生&#xff0c;14bit165MHz&#xff0c;2路完全独立完全可编程的I/O端口&#xff0c;33个完全可编程的量程选择&#xff0c;0~5V/0~10V/5V/10VPCIe通信接口…

如何将联系人从Android转移到 OPPO? [解决了]

概括 OPPO Reno4系列预计将于2020年10月1日上午9点30分举行线上发布会。从其官方预告片中我们不难发现&#xff0c;OPPO Reno4旗舰手机试图诠释梦想、挑战、勇气、自信和可能性。 3D曲面屏&#xff0c;图形流畅&#xff0c;机身更轻薄&#xff0c;色彩真实。听起来棒极了&…

uniapp 微信小程序开发使用高德地图、腾讯地图

一、高德地图 1.注册高德地图开放平台账号 &#xff08;1&#xff09;创建应用 这个key 第3步骤&#xff0c;配置到项目中locationGps.js 2.下载高德地图微信小程序插件 &#xff08;1&#xff09;下载地址 高德地图API | 微信小程序插件 &#xff08;2&#xff09;引入项目…

Rabbitmq追问2

分析rabbitmq 默认使用姿势是什么 direct fanout还是什么 public void convertAndSend(String exchange, String routingKey, Object object, CorrelationData correlationData) throws AmqpException { this.send(exchange, routingKey, this.convertMessageIfNecessary(obje…

工作中常用Vim的命令

Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 目录 0. ctags -R 1.认识 Vim的几种工作模式 2.高频使用命令 2.1 修改文件 2.2 关于行号 2.3 删除多行&#xff0c;删除部分 2.4 复制粘贴 2.5 光标移动 2.…

【ComfyUI + 自定义节点】图片叠加掩膜(mask)部分扣掉(变黑)

Comfyui的官方示例&#xff1a;https://github.com/comfyanonymous/ComfyUI/blob/master/custom_nodes/example_node.py.example 一、代码 &#xff08; 逻辑&#xff1a;将图片对应掩膜覆盖的区域替换为黑色&#xff09; 因为comfyui加载的图片后&#xff0c;转化为tensor i…

RocketMQ学习笔记(持续更新中......)

目录 1. 单机搭建 2. 测试RocketMQ 3. 集群搭建 4. 集群启动 5. RocketMQ-DashBoard搭建 6. 不同类型消息发送 1.同步消息 2. 异步消息发送 3. 单向发送消息 7. 消费消息 1. 单机搭建 1. 先从rocketmq官网下载二进制包&#xff0c;ftp上传至linux服务器&#xff0c…

【二】arcgis JavaScript api 实现加载不同坐标系的底图和三维服务

提示&#xff1a;如果是天地图底图参考这篇文章 【一】arcgis JavaScript api 实现加载不同坐标系的底图和三维服务_arcgis js api 调用三维地图服务-CSDN博客 需求&#xff1a; 前端开发实现底图&#xff08;wkid&#xff1a;3857&#xff0c;web墨卡托&#xff09;&#x…

PDF怎么压缩得又小又清晰?5种PDF压缩方法

PDF 文件在日常办公与学习中使用极为频繁&#xff0c;可想要把它压缩得又小又清晰却困难重重。一方面&#xff0c;PDF 格式本身具有高度兼容性&#xff0c;集成了文字、图像、矢量图等多样元素&#xff0c;压缩时难以兼顾不同元素特性&#xff0c;稍不注意&#xff0c;文字就会…

数据结构与算法之动态规划: LeetCode 62. 不同路径 (Ts版)

不同路径 https://leetcode.cn/problems/unique-paths/description/ 描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “…

Edge如何获得纯净的启动界面

启动Edge会出现快速链接&#xff0c;推广链接&#xff0c;网站导航&#xff0c;显示小组件&#xff0c;显示信息提要&#xff0c;背景 ●复杂页面 ●精简页面 点击页面设置按钮 关闭快速链接 关闭网站导航 关闭小组件 关闭信息提要 关闭背景 关闭天气提示 精简页面看起来十分舒…

如何利用java爬虫获得AMAZON商品详情

在数字化时代&#xff0c;数据的价值不言而喻&#xff0c;尤其是对于电商平台而言&#xff0c;获取商品的详细信息对于优化用户体验、制定营销策略至关重要。亚马逊作为全球最大的电商平台之一&#xff0c;拥有海量的商品信息。本文将介绍如何使用Java编写爬虫程序&#xff0c;…

人工智能基础软件-Jupyter Notebook

简介&#xff1a; Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算&#xff1a;开发、文档编写、运行代码和展示结果。 Jupyter Notebook是以网页的形式打开&#xff0c;可以在网页页面中直接编写代码和运行代码&#xff0c;代码的运行结果也会直…

数据库系列之分布式数据库下误删表怎么恢复?

数据的完整性是数据库可用性的基本功能&#xff0c;在实际应用数据库变更操作过程中可能因为误操作导致误删表或者truncate操作影响业务的正常访问。本文介绍了分布式数据库中在误删表场景下的数据恢复方案&#xff0c;并进行了对比。 1、数据库误删表恢复方案 应用数据的完整…

【分布式缓存中间件Memcached原理与应用】

分布式缓存中间件&#xff08;以 Memcached 为例&#xff09; 一、分布式缓存中间件概述 &#xff08;一&#xff09;概念 分布式缓存中间件是一种用于存储频繁访问的数据副本的软件系统&#xff0c;它位于应用程序和数据源&#xff08;通常是数据库&#xff09;之间。通过在…

No.2十六届蓝桥杯备战|练习题4道|数据类型|字符型|整型|浮点型|布尔型|signed|unsigned(C++)

B2002 Hello,World! - 洛谷 #include <iostream> using namespace std; int main() { cout << "Hello,World!" << endl; return 0; }打印飞机 #include <iostream> using namespace std;int main() {cout << " …