MinIO学习文档(Java版)

目录

    • 一、安装
      • 1、在k8s中安装minio单机版
        • (1)创建minio名称空间
        • (2)minio单机版安装yaml
    • 二、操作minio代码
      • 1、pom.xml(说明:minio所用依赖)
      • 2、application.yml(说明:放置minio连接信息、minio文件上传限制)
      • 3、MinioProperties.java(说明:读取minio连接信息)
      • 4、MinioConfig.java(说明:配置minio连接客户端类)
      • 5、ObjectItem.java(说明:接收Minio返回内容)
      • 6、MinioUtil.java(说明:Minio连接客户端)
      • 7、StorageController.java(说明:测试Minio的Controller)
      • 8、测试代码
        • 8.1、上传文件
        • 8.2、删除文件
        • 8.3、下载文件
        • 8.4、获取文件临时分享地址
    • 三、资料

一、安装

1、在k8s中安装minio单机版

(1)创建minio名称空间

kubectl create ns minio

我们下面的yaml文件用到了minio名称空间,所以需要先把该名称空间创建出来

(2)minio单机版安装yaml

在安装minio之前,以下几点需要先说明一下

yaml文件内容修改说明:大家只用把写注释的地方改成自己的,其他地方都不用变

安装命令:大家可以把下面yaml文件内容复制到minio.yaml中,然后上传到linux中,之后通过kubectl apply -f minio.yaml命令来安装minio

端口解释:对于端口部分解释一下,5000端口是供浏览器访问UI页面的,而9000端口是供客户端连接的

访问链接:安装完成之后,可以通过http://ip:port来访问minio,其中ip就是虚拟机ip,而端口就是5000端口对应的nodePort端口,比如下面yaml文件中的就是30427

登录信息:登录用户名和密码需要看yaml文件中的MINIO_ROOT_USERMINIO_ROOT_PASSWORD的value值,比如我的就是adminadmin123456

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  # 名称空间
  namespace: minio
spec:
  # 副本数量,建议1个,集群版可能存在问题
  replicas: 1
  selector:
    matchLabels:
      app: minio
  serviceName: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
        - command:
            - /bin/sh
            - -c
            - minio server /data --console-address ":5000"
          env:
            - name: MINIO_ROOT_USER
              # 登录用户名,按照自己的来设置
              value: "admin"
            - name: MINIO_ROOT_PASSWORD
              # 登录密码,按照自己的来设置
              value: "admin123456"
          image: minio/minio:latest
          name: minio
          ports:
            - containerPort: 9000
              name: data
              protocol: TCP
            - containerPort: 5000
              name: console
              protocol: TCP
          volumeMounts:
            - mountPath: /data
              name: data
  volumeClaimTemplates:
    - apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: data
      spec:
        accessModes:
          - ReadWriteMany
        resources:
          requests:
            # MioIO存储空间大小
            storage: 5Gi
        # nfs动态挂载存储类名称
        storageClassName: "managed-nfs-storage-bakckup"

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: minio
  name: minio
  namespace: minio
spec:
  ports:
    - name: data
      port: 9000
      protocol: TCP
      targetPort: 9000
      # 暴露端口
      nodePort: 30024
    - name: console
      port: 5000
      protocol: TCP
      targetPort: 5000
      # 暴露端口
      nodePort: 30427
  selector:
    app: minio
  type: NodePort

登录之后效果如下图:

MinIO学习文档(Java版)_第1张图片

二、操作minio代码

1、pom.xml(说明:minio所用依赖)

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>minio-study-springboot</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.4.0</version>
        </dependency>
        <!-- 注意:这个依赖必须添加,否则无法启动程序 -->
        <!-- 解决报错:okhttp3.RequestBody.create([BLokhttp3/MediaType;)Lokhttp3/RequestBody -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、application.yml(说明:放置minio连接信息、minio文件上传限制)

# minio文件上传大小限制
spring:
  servlet:
    multipart:
      max-file-size: 1GB
      max-request-size: 1GB

# minio连接配置
minio:
  # minio通信地址
  endpoint: http://192.168.139.128:30024
  # minio登录用户名
  userName: admin
  # minio登录密码
  password: admin123456

3、MinioProperties.java(说明:读取minio连接信息)

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties("minio")
public class MinioProperties {

    /**
     * 访问地址 http://localhost:9000
     */
    private String endpoint;
    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String password;
}

4、MinioConfig.java(说明:配置minio连接客户端类)

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;

@Data
@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfig {

    @Resource
    private MinioProperties minioProperties;

    /**
     * 注入minio 客户端
     */
    @Bean
    public MinioClient minioClient() {

        return MinioClient.builder()
                .endpoint(minioProperties.getEndpoint())
                .credentials(minioProperties.getUserName(), minioProperties.getPassword())
                .build();
    }
}

5、ObjectItem.java(说明:接收Minio返回内容)

import lombok.Data;

@Data
public class ObjectItem {

    private String objectName;
    private Long size;
}

6、MinioUtil.java(说明:Minio连接客户端)

@Component
@Slf4j
public class MinioUtil {

    @Resource
    private MinioClient minioClient;

    /**
     * 判断存储桶是否存在,不存在则创建
     *
     * @param bucketName 存储桶名称
     */
    public void existBucket(String bucketName) {
        try {
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查看存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return 桶是否存在
     */
    public boolean bucketExists(String bucketName) {
        boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            found = false;
            e.printStackTrace();
        }
        return found;
    }

    /**
     * 创建存储桶
     *
     * @param bucketName 存储桶名称
     * @return 是否创建成功
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 删除存储桶
     *
     * @param bucketName 存储桶名称
     * @return 是否删除成功
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 文件上传
     *
     * @param bucketName 存储桶名称
     * @param file       文件
     * @return 桶中位置
     */
    public String upload(String bucketName, MultipartFile file) {
        MultipartFile[] fileArr = {file};
        List<String> fileNames = upload(bucketName, fileArr);
        return fileNames.size() == 0 ? null : fileNames.get(0);
    }

    /**
     * 上传文件
     *
     * @param bucketName 存储桶名称
     * @param fileList   文件列表
     * @return 桶中位置列表
     */
    public List<String> upload(String bucketName, List<MultipartFile> fileList) {
        MultipartFile[] fileArr = fileList.toArray(new MultipartFile[0]);
        return upload(bucketName, fileArr);
    }

    /**
     * description: 上传文件
     *
     * @param bucketName 存储桶名称
     * @param fileArr    文件列表
     * @return 桶中位置列表
     */
    public List<String> upload(String bucketName, MultipartFile[] fileArr) {
        // 保证桶一定存在
        existBucket(bucketName);
        // 执行正常操作
        List<String> bucketFileNames = new ArrayList<>(fileArr.length);
        for (MultipartFile file : fileArr) {
            // 获取桶中文件名称
            // 获取原始文件名称
            String originalFileName = file.getOriginalFilename();
            // 获取当前日期,格式例如:2022/12-04/00,这种年/月-日/小时的文件存储方式是我们公司的文件存储方式,所以这里我也采用这种方式
            String datePath = new SimpleDateFormat("yyyy/MM-dd/HH").format(new Date());
            // 文件名称
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            // 获取文件后缀
            String type;
            int index = originalFileName.lastIndexOf(46);
            if (index != -1) {
                type = originalFileName.substring(index + 1);
            } else {
                type = "unkown";
            }
            String bucketFileName = datePath + "/" + uuid + "." + type;

            // 推送文件到MinIO
            try (InputStream in = file.getInputStream()) {
                minioClient.putObject(PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(bucketFileName)
                        .stream(in, in.available(), -1)
                        .contentType(file.getContentType())
                        .build()
                );
            } catch (Exception e) {
                e.printStackTrace();
            }
            bucketFileNames.add(bucketFileName);
        }
        return bucketFileNames;
    }

    /**
     * 文件下载
     *
     * @param bucketName       存储桶名称
     * @param bucketFileName   桶中文件名称
     * @param originalFileName 原始文件名称
     * @param response         response对象
     */
    public void download(String bucketName, String bucketFileName, String originalFileName, HttpServletResponse response) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(bucketFileName).build();
        try (GetObjectResponse objResponse = minioClient.getObject(objectArgs)) {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = objResponse.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                response.setCharacterEncoding("utf-8");
                //设置强制下载不打开
                response.setContentType("application/force-download");
                // 设置附件名称编码
                originalFileName = new String(originalFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                // 设置附件名称
                response.addHeader("Content-Disposition", "attachment;fileName=" + originalFileName);
                // 写入文件
                try (ServletOutputStream stream = response.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取已上传对象的文件流
     *
     * @param bucketName     存储桶名称
     * @param bucketFileName 桶中文件名称
     * @return 文件流
     */
    public InputStream getFileStream(String bucketName, String bucketFileName) throws Exception {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName).object(bucketFileName).build();
        return minioClient.getObject(objectArgs);
    }

    /**
     * 批量删除文件对象结果
     *
     * @param bucketName      存储桶名称
     * @param bucketFileName 桶中文件名称
     * @return 删除结果
     */
    public DeleteError removeObjectsResult(String bucketName, String bucketFileName) {
        List<DeleteError> results = removeObjectsResult(bucketName, Collections.singletonList(bucketFileName));
        return results.size() > 0 ? results.get(0) : null;
    }

    /**
     * 批量删除文件对象结果
     *
     * @param bucketName      存储桶名称
     * @param bucketFileNames 桶中文件名称集合
     * @return 删除结果
     */
    public List<DeleteError> removeObjectsResult(String bucketName, List<String> bucketFileNames) {
        Iterable<Result<DeleteError>> results = removeObjects(bucketName, bucketFileNames);
        List<DeleteError> res = new ArrayList<>();
        for (Result<DeleteError> result : results) {
            try {
                res.add(result.get());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("遍历删除结果出现错误:" + e.getMessage());
            }
        }
        return res;
    }

    /**
     * 批量删除文件对象
     *
     * @param bucketName      存储桶名称
     * @param bucketFileNames 桶中文件名称集合
     */
    private Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> bucketFileNames) {
        List<DeleteObject> dos = bucketFileNames.stream().map(DeleteObject::new).collect(Collectors.toList());
        return minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
    }

    /**
     * 查看文件对象
     *
     * @param bucketName 存储桶名称
     * @return 文件对象集合
     */
    public List<ObjectItem> listObjects(String bucketName) {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build());
        List<ObjectItem> objectItems = new ArrayList<>();
        try {
            for (Result<Item> result : results) {
                Item item = result.get();
                ObjectItem objectItem = new ObjectItem();
                objectItem.setObjectName(item.objectName());
                objectItem.setSize(item.size());
                objectItems.add(objectItem);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectItems;
    }

    /**
     * 获取桶(桶类型:public)中文件访问url
     *
     * @param bucketName     存储桶名称
     * @param bucketFileName 桶中文件名称
     * @return 访问url
     */
    public String getUploadedObjectUrlForPublicBucket(String bucketName, String bucketFileName) {
        return bucketName + "/" + bucketFileName;
    }

    /**
     * 获取桶(不限制桶类型)中文件访问url
     *
     * @param bucketName     存储桶名称
     * @param bucketFileName 桶中文件名称
     * @param expiry         过期时间数量
     * @param timeUnit       过期时间单位
     * @return 访问url
     */
    public String getUploadedObjectUrl(String bucketName, String bucketFileName, Integer expiry, TimeUnit timeUnit) {
        GetPresignedObjectUrlArgs urlArgs = GetPresignedObjectUrlArgs.builder()
                .method(Method.GET)
                .bucket(bucketName)
                .object(bucketFileName)
                .expiry(expiry, timeUnit)
                .build();
        try {
            return minioClient.getPresignedObjectUrl(urlArgs);
        } catch (Exception e) {
            log.error("获取已上传文件的 Url 失败:" + e.getMessage());
            return "";
        }
    }
}

7、StorageController.java(说明:测试Minio的Controller)

import com.atguigu.miniostudyspringboot.util.MinioUtil;
import io.minio.messages.DeleteError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

@RestController
public class StorageController {

    private static final String BUCKET_NAME = "knowledge";

    @Resource
    private MinioUtil minIoUtil;

    // 上传文件
    @PostMapping("/uploadFile")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        return minIoUtil.upload(BUCKET_NAME, file);
    }

    // 删除文件
    @GetMapping("/deleteFile")
    public DeleteError deleteFile(@RequestParam String bucketFileName) {
        return minIoUtil.removeObjectsResult(BUCKET_NAME, bucketFileName);
    }

    // 下载文件
    @GetMapping("/downloadFile")
    public void uploadFile(@RequestParam String bucketFileName, @RequestParam String originalFilename, HttpServletResponse response) {
        minIoUtil.download(BUCKET_NAME, bucketFileName, originalFilename, response);
    }

    // 获取文件临时分享地址
    @GetMapping("/shareUrl")
    public String shareUrl(@RequestParam String bucketFileName) {
        return minIoUtil.getUploadedObjectUrl(BUCKET_NAME, bucketFileName, 7, TimeUnit.DAYS);
    }

}

8、测试代码

8.1、上传文件

MinIO学习文档(Java版)_第2张图片

8.2、删除文件

MinIO学习文档(Java版)_第3张图片

8.3、下载文件

在这里插入图片描述

8.4、获取文件临时分享地址

MinIO学习文档(Java版)_第4张图片

三、资料

  1. MinIO的Java Client API参考文档

你可能感兴趣的:(java学习之路,学习,java,运维)