欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Docker搭建Minio容器的流程步驟(完整詳細版)

 更新時間:2024年08月11日 15:16:39   作者:@昊陽  
Minio 是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),雖然輕量,卻擁有著不錯的性能,它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù),本文將給大家介紹Docker搭建Minio容器的流程步驟,需要的朋友可以參考下

簡介:

Minio 是一個基于Apache License v2.0開源協(xié)議的對象存儲服務(wù),雖然輕量,卻擁有著不錯的性能。它兼容亞馬遜S3云存儲服務(wù)接口,非常適合于存儲大容量非結(jié)構(gòu)化的數(shù)據(jù)。

例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機鏡像等,而一個對象文件可以是任意大小,從幾 kb 到最大 5T 不等。

最重要的是免費

說明:

Docker如果想安裝軟件 , 必須先到Docker鏡像倉庫下載鏡像。

Docker官方鏡像

1、尋找Minio鏡像

image-20231129205553602

image-20231130160039562

2、下載Minio鏡像

# 下載鏡像
docker pull minio/minio

#查看鏡像
docker images
命令描述
docker pull minio/minio下載最新版Minio鏡像 (其實此命令就等同于 : docker pull minio/minio:latest )
docker pull minio/minio:RELEASE.2023-11-20T22-40-07Z.fips下載指定版本的Minio鏡像 (xxx指具體版本號)

image-20231129210410277

3、創(chuàng)建目錄

一個用來存放配置,一個用來存儲上傳文件的目錄

啟動前需要先創(chuàng)建Minio外部掛載的配置文件( /opt/minio/config),和存儲上傳文件的目錄( /opt/minio/data)

mkdir -p /opt/minio/config

mkdir -p /opt/minio/data

4、創(chuàng)建Minio容器并運行

docker run \
-p 19000:9000 \
-p 9090:9090 \
--net=host \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=minioadmin" \
-e "MINIO_SECRET_KEY=minioadmin" \
-v /opt/minio/data:/data \
-v /opt/minio/config:/root/.minio \
 minio/minio server \
/data --console-address ":9090" -address ":19000"

命令描述
-p 9000:9000 -p 9090:9090這是端口映射,前一個是服務(wù)器的端口,后一個是客戶端也就是api接口訪問的端口地址
–name minio這是給新創(chuàng)建的容器命名的選項,名字是 “minio”
–net=host這是網(wǎng)絡(luò)設(shè)置,表示容器將使用主機的網(wǎng)絡(luò)棧,這樣就不需要在容器內(nèi)部配置網(wǎng)絡(luò)
-d --restart=always這是運行容器的其他選項,-d使容器在后臺運行,–restart=always表示容器總是會在退出后自動重啟
-e “MINIO_ACCESS_KEY=minioadmin”用戶名
-e “MINIO_SECRET_KEY=minioadmin”密碼
-v /opt/minio/data:/data這意味著將宿主機上的 /opt/minio/data 目錄掛載到容器內(nèi)的 /data 目錄
-v /opt/minio/config:/root/.minio將宿主機上的 /opt/minio/config 目錄掛載到容器內(nèi)的 /root/.minio 目錄
minio/minio server /data --console-address “:9090” -address “:9000”這是容器內(nèi)要運行的命令,啟動一個名為 “minio” 的服務(wù)器,數(shù)據(jù)存儲在 /data 目錄下,服務(wù)器的控制臺地址為 “:9090”,服務(wù)地址為 “:9000”
\換行

4.1、訪問操作

訪問:http://47.117.160.102:9090/login 用戶名:密碼 minioadmin:minioadmin

image-20231130165641764

4.2、創(chuàng)建用戶

image-20231130173302737

image-20231130173436591

4.3、創(chuàng)建組

image-20231130173619690

image-20231130173728073

4.4、創(chuàng)建Buckets

image-20231130195452040

image-20231130195548997

4.5、創(chuàng)建Access Keys

image-20231130195953522

4.6、文件上傳

image-20231201195412713

4.7、瀏覽器訪問上傳文件

image-20231201195651424

4.6.1、輸入ip:19000/Buckets名/文件名,如果不行,看看端口是否開放

image-20231201195743467

5、Springboot簡單使用

5.1、添加MinIO依賴Pom

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

        <!-- MinIO 客戶端 -->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.7</version>
        </dependency>
    
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

5.2、配置MinIO的yaml

server:
  port: 3333

spring:
  servlet:
    multipart:
      max-request-size: 200MB
      max-file-size: 200MB

minio:
  url: http://127.0.0.1:19000 #換成自己的minio服務(wù)端地址
  accessKey: minioadmin # 用戶名
  secretKey: minioadmin # 密碼
  bucketName: demo  # bucketName指的就是之前創(chuàng)建的MinIO桶Bucket

5.3、配置類Config

/**
 * @author HAOYANG
 * @create 2023-12-01 20:40
 */
@Data
@Configuration
public class MinioConfig {

    /**
     * 訪問地址
     */
    @Value("${minio.url}")
    private String endpoint;

    /**
     * accessKey類似于用戶ID,用于唯一標識你的賬戶
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * secretKey是你賬戶的密碼
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 默認存儲桶
     */
    @Value("${minio.bucketName}")
    private String bucketName;

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

5.4、創(chuàng)建MinIO工具類

/**
 * MinIO工具類
 *
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MinioUtils {

    private final MinioClient minioClient;

    /******************************  Operate Bucket Start  ******************************/

    /**
     * 啟動SpringBoot容器的時候初始化Bucket
     * 如果沒有Bucket則創(chuàng)建
     *
     * @param bucketName
     */
    @SneakyThrows(Exception.class)
    private void createBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 判斷Bucket是否存在,true:存在,false:不存在
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

    /**
     * 獲得Bucket的策略
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public String getBucketPolicy(String bucketName) {
        return minioClient.getBucketPolicy(GetBucketPolicyArgs
                .builder()
                .bucket(bucketName)
                .build());
    }

    /**
     * 獲得所有Bucket列表
     *
     * @return
     */
    @SneakyThrows(Exception.class)
    public List<Bucket> getAllBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * 根據(jù)bucketName獲取其相關(guān)信息
     *
     * @param bucketName
     * @return
     */
    @SneakyThrows(Exception.class)
    public Optional<Bucket> getBucket(String bucketName) {
        return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /**
     * 根據(jù)bucketName刪除Bucket,true:刪除成功; false:刪除失敗,文件或已不存在
     *
     * @param bucketName
     * @throws Exception
     */
    @SneakyThrows(Exception.class)
    public void removeBucket(String bucketName) {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /******************************  Operate Bucket End  ******************************/


    /******************************  Operate Files Start  ******************************/

    /**
     * 判斷文件是否存在
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public boolean isObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            log.error("[Minio工具類]>>>> 判斷文件是否存在, 異常:", e);
            exist = false;
        }
        return exist;
    }

    /**
     * 判斷文件夾是否存在
     *
     * @param bucketName
     * @param objectName
     * @return
     */
    public boolean isFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && objectName.equals(item.objectName())) {
                    exist = true;
                }
            }
        } catch (Exception e) {
            log.error("[Minio工具類]>>>> 判斷文件夾是否存在,異常:", e);
            exist = false;
        }
        return exist;
    }

    /**
     * 根據(jù)文件前置查詢文件
     *
     * @param bucketName 存儲桶
     * @param prefix     前綴
     * @param recursive  是否使用遞歸查詢
     * @return MinioItem 列表
     */
    @SneakyThrows(Exception.class)
    public List<Item> getAllObjectsByPrefix(String bucketName,
                                            String prefix,
                                            boolean recursive) {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
        if (objectsIterator != null) {
            for (Result<Item> o : objectsIterator) {
                Item item = o.get();
                list.add(item);
            }
        }
        return list;
    }

    /**
     * 獲取文件流
     *
     * @param bucketName 存儲桶
     * @param objectName 文件名
     * @return 二進制流
     */
    @SneakyThrows(Exception.class)
    public InputStream getObject(String bucketName, String objectName) {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    /**
     * 斷點下載
     *
     * @param bucketName 存儲桶
     * @param objectName 文件名稱
     * @param offset     起始字節(jié)的位置
     * @param length     要讀取的長度
     * @return 二進制流
     */
    @SneakyThrows(Exception.class)
    public InputStream getObject(String bucketName, String objectName, long offset, long length) {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .offset(offset)
                        .length(length)
                        .build());
    }

    /**
     * 獲取路徑下文件列表
     *
     * @param bucketName 存儲桶
     * @param prefix     文件名稱
     * @param recursive  是否遞歸查找,false:模擬文件夾結(jié)構(gòu)查找
     * @return 二進制流
     */
    public Iterable<Result<Item>> listObjects(String bucketName, String prefix, boolean recursive) {
        return minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive)
                        .build());
    }

    /**
     * 使用MultipartFile進行文件上傳
     *
     * @param bucketName  存儲桶
     * @param file        文件名
     * @param objectName  對象名
     * @param contentType 類型
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) {
        InputStream inputStream = file.getInputStream();
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .contentType(contentType)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /**
     * 圖片上傳
     * @param bucketName
     * @param imageBase64
     * @param imageName
     * @return
     */
    public ObjectWriteResponse uploadImage(String bucketName, String imageBase64, String imageName) {
        if (!StringUtils.isEmpty(imageBase64)) {
            InputStream in = base64ToInputStream(imageBase64);
            String newName = System.currentTimeMillis() + "_" + imageName + ".jpg";
            String year = String.valueOf(new Date().getYear());
            String month = String.valueOf(new Date().getMonth());
            return uploadFile(bucketName, year + "/" + month + "/" + newName, in);

        }
        return null;
    }
// BASE64Decoder在jdk8以上的版本移除了,報錯最簡單解決換成jdk8就行了
    public static InputStream base64ToInputStream(String base64) {
        ByteArrayInputStream stream = null;
        try {
            byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
            stream = new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stream;
    }


    /**
     * 上傳本地文件
     *
     * @param bucketName 存儲桶
     * @param objectName 對象名稱
     * @param fileName   本地文件路徑
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) {
        return minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .filename(fileName)
                        .build());
    }

    /**
     * 通過流上傳文件
     *
     * @param bucketName  存儲桶
     * @param objectName  文件對象
     * @param inputStream 文件流
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /**
     * 創(chuàng)建文件夾或目錄
     *
     * @param bucketName 存儲桶
     * @param objectName 目錄路徑
     * @return
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse createDir(String bucketName, String objectName) {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
                        .build());
    }

    /**
     * 獲取文件信息, 如果拋出異常則說明文件不存在
     *
     * @param bucketName 存儲桶
     * @param objectName 文件名稱
     * @return
     */
    @SneakyThrows(Exception.class)
    public String getFileStatusInfo(String bucketName, String objectName) {
        return minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()).toString();
    }

    /**
     * 拷貝文件
     *
     * @param bucketName    存儲桶
     * @param objectName    文件名
     * @param srcBucketName 目標存儲桶
     * @param srcObjectName 目標文件名
     */
    @SneakyThrows(Exception.class)
    public ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) {
        return minioClient.copyObject(
                CopyObjectArgs.builder()
                        .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                        .bucket(srcBucketName)
                        .object(srcObjectName)
                        .build());
    }

    /**
     * 刪除文件
     *
     * @param bucketName 存儲桶
     * @param objectName 文件名稱
     */
    @SneakyThrows(Exception.class)
    public void removeFile(String bucketName, String objectName) {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    /**
     * 批量刪除文件
     *
     * @param bucketName 存儲桶
     * @param keys       需要刪除的文件列表
     * @return
     */
    public void removeFiles(String bucketName, List<String> keys) {
        List<DeleteObject> objects = new LinkedList<>();
        keys.forEach(s -> {
            objects.add(new DeleteObject(s));
            try {
                removeFile(bucketName, s);
            } catch (Exception e) {
                log.error("[Minio工具類]>>>> 批量刪除文件,異常:", e);
            }
        });
    }

    /**
     * 獲取文件外鏈
     *
     * @param bucketName 存儲桶
     * @param objectName 文件名
     * @param expires    過期時間 <=7 秒 (外鏈有效時間(單位:秒))
     * @return url
     */
    @SneakyThrows(Exception.class)
    public String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * 獲得文件外鏈
     *
     * @param bucketName
     * @param objectName
     * @return url
     */
    @SneakyThrows(Exception.class)
    public String getPresignedObjectUrl(String bucketName, String objectName) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /**
     * 將URLDecoder編碼轉(zhuǎn)成UTF8
     *
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
        String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
        return URLDecoder.decode(url, "UTF-8");
    }
}

5.5、創(chuàng)建Controller

/**
 * @author HAOYANG
 * @create 2023-12-01 20:38
 */
@Slf4j
@RestController
@RequestMapping("/oss")
public class OSSController {

    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private MinioConfig minioConfig;

    /**
     * 文件上傳
     *
     * @param file
     */
    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) {
        try {
            //文件名
            String fileName = file.getOriginalFilename();
            String newFileName = System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
            //類型
            String contentType = file.getContentType();
            minioUtils.uploadFile(minioConfig.getBucketName(), file, newFileName, contentType);
            return "上傳成功";
        } catch (Exception e) {
            log.error("上傳失敗");
            return "上傳失敗";
        }
    }

    /**
     * 刪除
     *
     * @param fileName
     */
    @DeleteMapping("/")
    public void delete(@RequestParam("fileName") String fileName) {
        minioUtils.removeFile(minioConfig.getBucketName(), fileName);
    }

    /**
     * 獲取文件信息
     *
     * @param fileName
     * @return
     */
    @GetMapping("/info")
    public String getFileStatusInfo(@RequestParam("fileName") String fileName) {
        return minioUtils.getFileStatusInfo(minioConfig.getBucketName(), fileName);
    }

    /**
     * 獲取文件外鏈
     *
     * @param fileName
     * @return
     */
    @GetMapping("/url")
    public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {
        return minioUtils.getPresignedObjectUrl(minioConfig.getBucketName(), fileName);
    }

    /**
     * 文件下載
     *
     * @param fileName
     * @param response
     */
    @GetMapping("/download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
        try {
            InputStream fileInputStream = minioUtils.getObject(minioConfig.getBucketName(), fileName);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType("application/force-download");
            response.setCharacterEncoding("UTF-8");
            IOUtils.copy(fileInputStream, response.getOutputStream());
        } catch (Exception e) {
            log.error("下載失敗");
        }
    }

}

6、測試驗證

6.1、文件上傳

使用Postman調(diào)用http://localhost:3333/oss/upload 接口,選擇某個文件測試上傳功能,如下圖所示:

image-20231201213316663

6.2、文件下載

在瀏覽器中,調(diào)用http://localhost:3333/oss/download?fileName=1701436432918.gif 接口,驗證文件下載接口,如下圖所示:

image-20231201213607507

以上就是Docker搭建Minio容器的流程步驟的詳細內(nèi)容,更多關(guān)于Docker搭建Minio容器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Docker部署SpringBoot項目的實現(xiàn)步驟

    Docker部署SpringBoot項目的實現(xiàn)步驟

    本文主要介紹了Docker部署SpringBoot項目的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2007-02-02
  • docker-compose之基本語法解讀

    docker-compose之基本語法解讀

    這篇文章主要介紹了docker-compose之基本語法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • linux中無make命令的問題(make: *** 沒有指明目標并且找不到 makefile及make命令安裝方法)

    linux中無make命令的問題(make: *** 沒有指明目標并且找不到 makefile及make命令安裝方法)

    這篇文章主要介紹了linux中無make命令的問題(make: *** 沒有指明目標并且找不到 makefile及make命令安裝方法),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • docker 啟動elasticsearch鏡像,掛載目錄后報錯的解決

    docker 啟動elasticsearch鏡像,掛載目錄后報錯的解決

    這篇文章主要介紹了docker 啟動 elasticsearch鏡像,掛載目錄后報錯的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • docker容器下配置jupyter notebook的操作

    docker容器下配置jupyter notebook的操作

    這篇文章主要介紹了docker容器下配置jupyter notebook的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • docker 設(shè)置windows存儲路徑的操作

    docker 設(shè)置windows存儲路徑的操作

    這篇文章主要介紹了docker 設(shè)置windows存儲路徑的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Docker搭建LibreSpeed的實現(xiàn)步驟

    Docker搭建LibreSpeed的實現(xiàn)步驟

    LibreSpeed 是一個輕量級的網(wǎng)絡(luò)速度測試工具,本文主要介紹了Docker搭建LibreSpeed的實現(xiàn)步驟,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • CentOS安裝Docker的方法

    CentOS安裝Docker的方法

    這篇文章介紹了CentOS安裝Docker的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-01-01
  • 在alpine鏡像中添加ansible服務(wù)的方法

    在alpine鏡像中添加ansible服務(wù)的方法

    今天小編就為大家分享一篇關(guān)于在alpine鏡像中添加ansible服務(wù)的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 關(guān)于docker容器部署redis步驟介紹

    關(guān)于docker容器部署redis步驟介紹

    大家好,本篇文章主要講的是關(guān)于docker容器部署redis步驟介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-11-11

最新評論