docker安装minIO并整合springboot

简介

Minio是Apache License v2.0下发布的对象存储服务器。它与Amazon S3云存储服务兼容。它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/ VM映像。对象的大小可以从几KB到最大5TBMinio服务器足够轻,可以与应用程序堆栈捆绑在一起,类似于NodeJS,Redis和MySQL。https://docs.minio.io/

使用分布式文件服务FASTDFS和阿里云的OSS对象存储来存文件。奈何OSS太贵,FASTDFS搭建配置又太繁琐,推荐高性能对象存储服务MinIO。

Docker安装

docker pull minio/minio
docker run -p 9000:9000 --name minio 
  -e "MINIO_ACCESS_KEY=minio" 
  -e "MINIO_SECRET_KEY=gulimall_minio" 
  -v /mydata/minio/data:/data 
  -v /mydata/minio/config:/root/.minio 
  -d minio/minio server /data
存储桶命名规则

以下规则适用于命名 S3 存储桶:

  • 存储桶名称必须长在 3 到 63 个字符之间。
  • 存储桶名称只能由小写字母、数字、点 (.) 和连字符 (-) 组成。
  • 存储桶名称必须以字母或数字开头和结尾。
  • 存储桶名称不得格式化为 IP 地址(例如,192.168.5.4)。
  • 存储桶名称在分区中必须是唯一的。分区是区域的分组。AWS 目前有三个分区:(标准区域)、(中国区域)和(AWS GovCloud [美国]区域)。awsaws-cnaws-us-gov
  • 与 Amazon S3 传输加速一起使用的存储桶的名称中不能有点 (.)。有关传输加速的详细信息,请参阅亚马逊S3 传输加速。

java客户端使用

依赖:

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>7.0.2</version>
</dependency>

application.yml配置

# 图片服务器 minio配置
minio:
  ip: xxxxxxx:9000
  # minio登录账号密码
  accessKey: xxxxxxx
  secretKey: xxxxxxxx
 
  ## 桶名(文件夹)命名规则要符合 亚马逊S3标准 详情可看http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
  bucketName:
    ## 照片文件夹
    facility: facility-photos

操作API 类

/**
 * @author zhan
 * @since 2020-05-18 11:23
 */
@Slf4j
public class Minio {

    /**
     * 服务器地址
     */
    @Value("${minio.ip}")
    private String ip;

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

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

    /**
     * 缩略图大小
     */
    @Value("${minio.thumbor.width}")
    private String thumborWidth;


    /**
     * Minio文件上传
     *
     * @param file       文件实体
     * @param fileName   修饰过的文件名 非源文件名
     * @param bucketName 所存文件夹(桶名)
     * @return
     */
    public R minioUpload(MultipartFile file, String fileName, String bucketName) {
        try {
            MinioClient minioClient = new MinioClient("http://" + ip, accessKey, secretKey);
            boolean bucketExists = minioClient.bucketExists(bucketName);
            if (bucketExists) {
                log.info("仓库" + bucketName + "已经存在,可直接上传文件。");
            } else {
                minioClient.makeBucket(bucketName);
            }
            if (file.getSize() <= 20971520) {
                // fileName为空,说明要使用源文件名上传
                if (fileName == null) {
                    fileName = file.getOriginalFilename();
                    fileName = fileName.replaceAll(" ", "_");
                }
                // minio仓库名
                minioClient.putObject(bucketName, fileName, file.getInputStream(), file.getContentType());
                log.info("成功上传文件 " + fileName + " 至 " + bucketName);
                String fileUrl = bucketName + "/" + fileName;
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("fileUrl", fileUrl);
                map.put("bucketName", bucketName);
                map.put("originFileName", fileName);
                return R.ok(map);
            } else {
                throw new Exception("请上传小于20mb的文件");
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("ORA")) {
                return R.error("上传失败:【查询参数错误】");
            }
            return R.error("上传失败:【" + e.getMessage() + "】");
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param fileName   文件名
     * @param bucketName 桶名(文件夹)
     * @return
     */
    public boolean isFileExisted(String fileName, String bucketName) {
        InputStream inputStream = null;
        try {
            MinioClient minioClient = new MinioClient("http://" + ip, accessKey, secretKey);
            inputStream = minioClient.getObject(bucketName, fileName);
            if (inputStream != null) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 删除文件
     *
     * @param bucketName 桶名(文件夹)
     * @param fileName   文件名
     * @return
     */
    public boolean delete(String bucketName, String fileName) {
        try {
            MinioClient minioClient = new MinioClient("http://" + ip, accessKey, secretKey);
            minioClient.removeObject(bucketName, fileName);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 下载文件
     *
     * @param objectName 文件名
     * @param bucketName 桶名(文件夹)
     * @param response
     * @return
     */
    public R downloadFile(String objectName, String bucketName, HttpServletResponse response) {
        try {
            MinioClient minioClient = new MinioClient("http://" + ip, accessKey, secretKey);
            InputStream file = minioClient.getObject(bucketName, objectName);
            String filename = new String(objectName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
            return R.ok(objectName + "下载成功");
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("ORA")) {
                return R.error("下载失败:【查询参数错误】");
            }
            return R.error("下载失败:【" + e.getMessage() + "】");
        }
    }

    /**
     * 获取文件流
     *
     * @param objectName 文件名
     * @param bucketName 桶名(文件夹)
     * @return
     */
    public InputStream getFileInputStream(String objectName, String bucketName) {
        try {
            MinioClient minioClient = new MinioClient("http://" + ip, accessKey, secretKey);
            return minioClient.getObject(bucketName, objectName);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return null;
    }
}

springboot整合Minio
  1. 导入依赖
<!-- https://mvnrepository.com/artifact/com.jlefebure/spring-boot-starter-minio -->
        <dependency>
            <groupId>com.jlefebure</groupId>
            <artifactId>spring-boot-starter-minio</artifactId>
            <version>1.4</version>
        </dependency>
  1. 配置yml
spring:
  minio:
    url: http://192.168.1.119:9000/
    access-key: minio
    secret-key: gulimall_minio
    bucket: gulimall
    create-bucket: true
  1. 直接在controller中使用
package com.atguigu.gulimall.product.controller;

import com.jlefebure.spring.boot.minio.MinioConfigurationProperties;
import com.jlefebure.spring.boot.minio.MinioService;
import io.minio.messages.Item;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author zhan
 * @since 2020-05-18 14:50
 */
@RestController
public class TestController {
    @Autowired
    MinioService minioService;

    @Autowired
    private MinioConfigurationProperties configurationProperties;

    @GetMapping("/files")
    public List<Item> testMinio(){
        return minioService.list();
    }

    /**
     * 根据文件名称下载文件
     * @param object
     * @param response
     * @throws com.jlefebure.spring.boot.minio.MinioException
     * @throws IOException
     * @throws IOException
     */
    @GetMapping("files/{object}")
    public void getObject(@PathVariable("object") String object, HttpServletResponse response) throws com.jlefebure.spring.boot.minio.MinioException, IOException, IOException {
        InputStream inputStream = minioService.get(Paths.get(object));
        InputStreamResource inputStreamResource = new InputStreamResource(inputStream);

        // Set the content type and attachment header.
        response.addHeader("Content-disposition", "attachment;filename=" + object);
        response.setContentType(URLConnection.guessContentTypeFromName(object));

        // Copy the stream to the response's output stream.
        IOUtils.copy(inputStream, response.getOutputStream());
        response.flushBuffer();
    }
    @PostMapping("/upload")
    public void addAttachement(@RequestParam("file") MultipartFile file) throws IOException {
        System.out.println(file);
        String filename = file.getOriginalFilename();
        // System.out.println(filename);
        // Path path = Paths.get(file.getResource().getURI());
        Path path = Paths.get(filename);
        String url = configurationProperties.getUrl() + "/" + configurationProperties.getBucket() + path.toAbsolutePath();
        // System.out.println(path.toAbsolutePath());
        // url += path.toAbsolutePath();
        System.out.println(url);
        // System.out.println(path);
        try {
            minioService.upload(path, file.getInputStream(), file.getContentType());
            System.out.println("上传完成!!!");
        } catch (com.jlefebure.spring.boot.minio.MinioException e) {
            throw new IllegalStateException("The file cannot be upload on the internal storage. Please retry later", e);
        } catch (IOException e) {
            throw new IllegalStateException("The file cannot be read", e);
        }
    }
}
    # 附上单元方法测试结论。
    @Test
    public void t1() throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidExpiresRangeException, InvalidResponseException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException, BucketPolicyTooLargeException, InvalidObjectPrefixException {
        System.out.println(mmclient);
        Iterable<Result<Item>> results = mmclient.listObjects("gulimall");
        for (Result<Item> result : results) {
            Item item = result.get();
            System.out.println(item.lastModified() + ", " + item.size() + ", " + item.objectName());
        }
        //根据文件名称获取浏览地址,此种方式在不设置策略的情况下【使用默认策略】是不能直接下载文件的
        String gulimall = mmclient.presignedGetObject("gulimall", "11111.jpg");
        System.out.println("下载地址:"+gulimall);
        String gulimall1 = mmclient.getBucketLifeCycle("gulimall");
        System.out.println(gulimall1);// 空
        String policy = mmclient.getBucketPolicy("gulimall");
        System.out.println("policy:"+policy);
        //通过修改桶策略即可使用返回的url直接访问minio中的文件【推荐这种方式!!!】
        String objectUrl = mmclient.getObjectUrl("gulimall", "刘德华+-+练习.ape");
        System.out.println("objectUrl:" + objectUrl);
        //不能下载
        String putObject = mmclient.presignedPutObject("gulimall", "刘德华+-+练习.ape");
        System.out.println("putObject:"+putObject);

    }

读写策略json如下【简单粗暴点也可在搭建完成后直接在控制台操作】:

{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {
            "AWS": ["*"]
        },
        "Action": ["s3:ListBucketMultipartUploads", "s3:GetBucketLocation", "s3:ListBucket"],
        "Resource": ["arn:aws:s3:::gulimall"]
    }, {
        "Effect": "Allow",
        "Principal": {
            "AWS": ["*"]
        },
        "Action": ["s3:AbortMultipartUpload", "s3:DeleteObject", "s3:GetObject", "s3:ListMultipartUploadParts", "s3:PutObject"],
        "Resource": ["arn:aws:s3:::gulimall/*"]
    }]
}

image-20200825175638426

链接:https://www.jianshu.com/p/d81e9ecb4298

原文地址:https://www.cnblogs.com/dalianpai/p/13561008.html