栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

SpringBoot整合MinIO 「看这一篇就够了」

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot整合MinIO 「看这一篇就够了」

文章目录
    • MinIo安装及启动
      • 1. 通过 docker 安装 MinIo
      • 2. 启动 及配置 MinIo
      • 3.其他OPTIONS解释
    • SpringBoot 整合 MinIO
      • 1.导入依赖
      • 2.application.yml 配置信息
      • 3.MinioConfig.class配置类
      • 4.minio工具类
      • 5.文件处理接口
    • 验证结果
      • 上传
      • 删除
      • 预览
    • 报错解决

MinIo安装及启动 1. 通过 docker 安装 MinIo
# 搜索是否有 minio 镜像
docker search minio
# 有则拉取镜像
docker pull minio/minio
2. 启动 及配置 MinIo
# 先创建minio 文件存放的位置
mkdir -p /opt/docker/minio/data

# 启动并指定端口
docker run 
  -p 5000:9000 
  -p 5001:5001 
  --name minio 
  -v /opt/docker/minio/data:/data 
  -e "MINIO_ROOT_USER=Jonny" 
  -e "MINIO_ROOT_PASSWORD=minioadmin" 
  -d minio/minio server /data --console-address ":5001"
 
# 设置为和 docker 绑定启动,docker 启动则 minio 就启动
docker update --restart=always

这里解释一下 docker 里面的几个参数

-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

-e “MINIO_ROOT_USER=Jonny”: 设置环境变量;

-d: 后台运行容器,并返回容器ID;

-v: 绑定一个卷



3.其他OPTIONS解释

docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

OPTIONS参数说明:
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-P: 随机端口映射,容器内部端口随机映射到主机的端口
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
name=“nginx-lb”: 为容器指定一个名称;
dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h “mars”: 指定容器的hostname;
-e username=“ritchie”: 设置环境变量;
env-file=[]: 从指定文件读入环境变量;
cpuset=“0-2” or cpuset=“0,1,2”: 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
link=[]: 添加链接到另一个容器;
expose=[]: 开放一个端口或一组端口;
volume , -v: 绑定一个卷
例如,使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx:
docker run name mynginx -d nginx:latest
使用镜像nginx:latest以后台模式启动一个容器,并将容器的80端口映射到主机随机端口:
docker run -P -d nginx:latest
使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data:
docker run -p 80:80 -v /data:/data -d nginx:latest
绑定容器的 8080 端口,并将其映射到本地主机 127.0.0.1 的 80 端口上:
docker run -p 127.0.0.1:80:8080/tcp ubuntu bash
使用镜像nginx:latest以交互模式启动一个容器,在容器内执行/bin/bash命令:
docker run -it nginx:latest /bin/bash

SpringBoot 整合 MinIO 1.导入依赖


    io.minio
    minio
    8.4.0

2.application.yml 配置信息
minio:
  endpoint: http://127.0.0.1:9000 #Minio服务所在地址
  bucketName: tulaoda #存储桶名称
  accessKey: Jonny #访问的key
  secretKey: minioadmin #访问的秘钥
3.MinioConfig.class配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String bucketName;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}
4.minio工具类
@Component
@Slf4j
public class MinioUtil {
    @Autowired
    private MinioConfig prop;

    @Resource
    private MinioClient minioClient;
    @Autowired
    private CodeService codeService;

    
    public Boolean bucketExists(String bucketName) {
        Boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    public List getAllBuckets() {
        try {
            List buckets = minioClient.listBuckets();
            return buckets;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }



    
    public String upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)){
            throw new RuntimeException();
        }
        String fileName = UuidUtils.generateUuid() + originalFilename.substring(originalFilename.lastIndexOf("."));
        String objectName = CommUtils.getNowDateLongStr("yyyy-MM/dd") + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(prop.getBucketName()).object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return objectName;
    }

    
    public String preview(String fileName){
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(prop.getBucketName()).object(fileName).method(Method.GET).build();
        try {
            String url = minioClient.getPresignedObjectUrl(build);
            return url;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    
    public void download(String fileName, HttpServletResponse res) {
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(prop.getBucketName())
                .object(fileName).build();
        try (GetObjectResponse response = minioClient.getObject(objectArgs)){
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
                while ((len=response.read(buf))!=-1){
                    os.write(buf,0,len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
                try (ServletOutputStream stream = res.getOutputStream()){
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
    public List listObjects() {
        Iterable> results = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(prop.getBucketName()).build());
        List items = new ArrayList<>();
        try {
            for (Result result : results) {
                items.add(result.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return items;
    }

    
    public boolean remove(String fileName){
        try {
            minioClient.removeObject( RemoveObjectArgs.builder().bucket(prop.getBucketName()).object(fileName).build());
        }catch (Exception e){
            return false;
        }
        return true;
    }

}
5.文件处理接口

@Api(tags = "文件相关接口")
@Slf4j
@RestController
@RequestMapping(value = "product/file")
public class FileController {


    @Autowired
    private MinioUtil minioUtil;
    @Autowired
    private MinioConfig prop;

    @ApiOperation(value = "查看存储bucket是否存在")
    @GetMapping("/bucketExists")
    public R bucketExists(@RequestParam("bucketName") String bucketName) {
        return R.ok().put("bucketName",minioUtil.bucketExists(bucketName));
    }

    @ApiOperation(value = "创建存储bucket")
    @GetMapping("/makeBucket")
    public R makeBucket(String bucketName) {
        return R.ok().put("bucketName",minioUtil.makeBucket(bucketName));
    }

    @ApiOperation(value = "删除存储bucket")
    @GetMapping("/removeBucket")
    public R removeBucket(String bucketName) {
        return R.ok().put("bucketName",minioUtil.removeBucket(bucketName));
    }

    @ApiOperation(value = "获取全部bucket")
    @GetMapping("/getAllBuckets")
    public R getAllBuckets() {
        List allBuckets = minioUtil.getAllBuckets();
        return R.ok().put("allBuckets",allBuckets);
    }

    @ApiOperation(value = "文件上传返回url")
    @PostMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile file) {
        String objectName = minioUtil.upload(file);
        if (null != objectName) {
            return R.ok().put("url",(prop.getEndpoint() + "/" + prop.getBucketName() + "/" + objectName));
        }
        return R.error();
    }

    @ApiOperation(value = "图片/视频预览")
    @GetMapping("/preview")
    public R preview(@RequestParam("fileName") String fileName) {
        return R.ok().put("filleName",minioUtil.preview(fileName));
    }

    @ApiOperation(value = "文件下载")
    @GetMapping("/download")
    public R download(@RequestParam("fileName") String fileName, HttpServletResponse res) {
        minioUtil.download(fileName,res);
        return R.ok();
    }

    @ApiOperation(value = "删除文件", notes = "根据url地址删除文件")
    @PostMapping("/delete")
    public R remove(String url) {
        String objName = url.substring(url.lastIndexOf(prop.getBucketName()+"/") + prop.getBucketName().length()+1);
        minioUtil.remove(objName);
        return R.ok().put("objName",objName);
    }

}
验证结果 上传

注意这里的 file 要选择一下类型用 File 而不是用 text

CSDN 机制问题图片加载不出来,可以查看本人博客:兔老大-SpringBoot整合MinIO 「看这一篇就够了」

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RS6AO3oW-1652372464067)(https://cdn.jsdelivr.net/gh/Jonny-Chi/picgo_imgs/BLog/202205130001555.png)]

删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-13e1zEbq-1652372464068)(https://cdn.jsdelivr.net/gh/Jonny-Chi/picgo_imgs/BLog/202205130002859.png)]

预览


这一块的接口慢慢试,主要用的几个接口在上面


报错解决

错误原因:
minio版本太新需要更换成8.2.2的版本



    io.minio
    minio
    8.2.2

error occurred
ErrorResponse(code = RequestTimeTooSkewed, message = The difference between the request time and the server's time is too large., bucketName = null, objectName = null, resource = /gulimall-product, requestId = null, hostId = bffd91de-450a-47ac-b4b2-3d3b45ddd054)
request={method=GET, url=http://192.168.1.17:5000/gulimall-product?location=, headers=Host: 192.168.1.17:5000
Accept-Encoding: identity
User-Agent: MinIO (Mac OS X; x86_64) minio-java/8.2.2
Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date: 20220512T140028Z
Authorization: AWS4-HMAC-SHA256 Credential=*REDACTED*/20220512/us-east-1/s3/aws4_request, SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date, Signature=*REDACTED*
}
response={code=403, headers=Accept-Ranges: bytes
Content-Length: 299
Content-Type: application/xml
Server: MinIO
Vary: Origin
Date: Thu, 12 May 2022 13:32:53 GMT
}

主要是因为 : 系统时区与硬件时区不一致导致的

解决步骤如下

  1. 安装ntp ntpdate
    yum -y install ntp ntpdate
  2. 与时间服务器同步时间
    ntpdate 0.asia.pool.ntp.org
  3. 将系统时间写入硬件时间
    hwclock --systohc

报错是因为没有给buckts配置权限策略导致。

解决步骤如下:

方法一 :客户端操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ceQpFmSN-1652372464070)(https://cdn.jsdelivr.net/gh/Jonny-Chi/picgo_imgs/BLog/202205122234336.png)]

方法二: 在创建 Bucket 的时候直接设置权限策略[后端修改]

将 MinIOUtil 工具类的创建 Bucket 的方法优化一下

   public Boolean makeBucket(String bucketName) {
       try {
           if (!bucketExists(bucketName)) {
               minioClient.makeBucket(MakeBucketArgs.builder()
                       .bucket(bucketName)
                       .build());
               String policyJson = "{n" +
                       "t"Version": ""+new SimpleDateFormat("yyyy-mm-dd").format(System.currentTimeMillis())+"",n" +
                       "t"Statement": [{n" +
                       "tt"Effect": "Allow",n" +
                       "tt"Principal": {n" +
                       "ttt"AWS": ["*"]n" +
                       "tt},n" +
                       "tt"Action": ["s3:GetBucketLocation", "s3:ListBucket", "s3:ListBucketMultipartUploads"],n" +
                       "tt"Resource": ["arn:aws:s3:::" + bucketName + ""]n" +
                       "t}, {n" +
                       "tt"Effect": "Allow",n" +
                       "tt"Principal": {n" +
                       "ttt"AWS": ["*"]n" +
                       "tt},n" +
                       "tt"Action": ["s3:AbortMultipartUpload", "s3:DeleteObject", "s3:GetObject", "s3:ListMultipartUploadParts", "s3:PutObject"],n" +
                       "tt"Resource": ["arn:aws:s3:::" + bucketName + "/*"]n" +
                       "t}]n" +
                       "}n";
               minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(policyJson).build());
               log.info("buckets:【{}】,创建[readwrite]策略成功!", bucketName);
           } else {
               log.info("minio bucket->>>【{}】already exists", bucketName);
           }
       } catch (Exception e) {
           e.printStackTrace();
           return false;
       }
       return true;
   }

这一块报错是因为文件名写错了藍,注意在将文件上传到服务器的过程中修改了文件名:

文件名的格式为:yyyy-mm/dd/+uuid+文件后缀

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/881393.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号