0


Win10安装Minio及SpringBoot集成Minio

简介

Minio是一款开源的云存储服务器,旨在为企业和个人用户提供简单、易用、高性能的对象存储服务。与传统的云存储产品不同,Minio是构建在HTTP服务之上的对象存储服务器,它支持AWS S3 API,可以为用户提供简单易用的对象存储服务,可用于存储各种类型的文件,包括图片、音频、视频等。

一、下载

我们需要先到minio官网进行下载:下载地址

二、运行启动minio

下载完成后,由于minio.exe是不能直接执行的,需要cmd进入下载目录执行命令:

minio.exe server D:\data

出现以上界面说明启动成功,打开浏览器访问:http://localhost:9000,就可以看到minio自带的管理后台了,登录的用户名和密码都是minioadmin

三、将minio集成到windows服务中

由于每次都需要打开cmd窗口运行命令后才能访问minio,关掉就不能访问了,非常不方便,所以我们可以将minio集成到服务中,这样就不用每次都用cmd启动了。

集成minio到服务需要下载WinSW.exe,下载地址

下载完成后将WinSW.exe和nimio.exe放到一个自定义的目录下,可以将WinSW.exe重命名成一个喜欢的名字,比如:minio-server.exe

在目录下新建一个minio-server.xml文件,内容如下:

<service>
    <id>minio-server</id>
    <name>minio-server</name>
    <description>minio文件存储服务器</description>
    <!-- 可设置环境变量 -->
    <env name="MINIO_HOME" value="%BASE%"/>
    <executable>%BASE%\minio.exe</executable>
    <arguments>server "%BASE%\data"</arguments>
    <logpath>%BASE%\logs</logpath>
    <log mode="roll-by-size-time">
      <sizeThreshold>10240</sizeThreshold>
      <pattern>yyyyMMdd</pattern>
      <autoRollAtTime>00:00:00</autoRollAtTime>
      <zipOlderThanNumDays>5</zipOlderThanNumDays>
      <zipDateFormat>yyyyMMdd</zipDateFormat>
    </log>
</service>

需在环境变量中新建MINIO_HOME,值就是存放minio.exe的目录

打开cmd进入到目录下,运行命令安装minio服务:

minio-server.exe install

如果想卸载minio-server,运行:

minio-server.exe uninstall

访问http://localhost:9000,出现minio的管理后台,说明服务安装成功

四、Spring Boot集成Minio

1.首先引入依赖
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.4.3</version>
</dependency>
2.在yml文件中添加配置
minio:
  url: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket: test
3.添加minio配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {

    private String accessKey;

    private String secretKey;

    private String url;

    @Bean
    public MinioClient minioClient() {
        try {
            return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
        }catch (Exception e) {
            throw new RuntimeException("初始化MinioClient失败", e);
        }
    }

}
4.编写工具类
@Component
public class MinioUtils {

    @Resource
    private MinioClient minioClient;

    @Value("${minio.bucket}")
    private String bucketName;

    /**
     * 判断存储桶是否存在
     *
     * @return 桶是否存在
     */
    public boolean bucketExists() {
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new RuntimeException("桶不存在", e);
        }
    }

    /**
     * 创建桶
     */
    public void makeBucket() {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new RuntimeException("创建桶失败", e);
        }
    }

    /**
     * 上传单个对象
     *
     * @param file 文件
     * @return 上传成功
     */
    public SysResult putObject(MultipartFile file) {
        if (file == null || file.isEmpty())
            throw new IllegalArgumentException("文件不能为空");

        try (InputStream inputStream = file.getInputStream()){
            //检查存储桶是否存在
            if (!bucketExists())
                makeBucket();

            // 获取文件名
            String fileName = file.getOriginalFilename();
            
            assert fileName != null;
            // 生成随机的对象名称
            String objectName = IdUtils.simpleUUID() + "." + FileUtil.getFileSuffix(fileName);

            // 添加自定义的元数据
            Map<String, String> meta = new HashMap<>();
            meta.put("file-name", fileName);

            // 添加对象
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .userMetadata(meta)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
            return SysResult.success("上传成功", objectName);
        } catch (Exception e) {
            throw new RuntimeException("上传失败", e);
        }
    }

    /**
     * 上传多个对象
     *
     * @param files 文件数组
     * @return 上传成功
     */
    public SysResult putObject(MultipartFile[] files) {
        for (MultipartFile file : files) {
            putObject(file);
        }
        return SysResult.success("上传成功");
    }

    /**
     * 删除一个对象
     *
     * @param objectName 对象名称
     * @return 是否删除成功
     */
    public boolean removeObject(String objectName) {
        if (bucketExists()) {
            try {
                minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
                return true;
            } catch (Exception e) {
                throw new RuntimeException("删除失败", e);
            }
        }
        return false;
    }

    /**
     * 删除多个对象,返回删除失败的对象列表
     *
     * @param objectNames 对象List
     * @return 删除失败的对象List
     */
    public List<String> removeObjects(List<String> objectNames) {
        List<String> deleteErrorNames = new ArrayList<>();
        if (bucketExists()) {
            for (String objectName : objectNames) {
                if (!removeObject(objectName)) {
                    deleteErrorNames.add(objectName);
                }
            }
        }
        return deleteErrorNames;
    }

    /**
     * 获取对象的元数据
     *
     * @param objectName 对象名称
     * @return 元数据
     */
    public SysResult statObject(String objectName) {
        try {
            if (bucketExists()) {
                StatObjectResponse response = minioClient.statObject(StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
                // 输出对象的元数据信息
                Map<String, String> metadata = response.userMetadata();
                // 返回
                return SysResult.data(metadata);
            }
        } catch (Exception e) {
            throw new RuntimeException("获取元数据失败", e);
        }
        return null;
    }

    /**
     * 获取文件的临时访问路径
     *
     * @param objectName 对象名称
     * @return 临时访问url
     */
    public String getObjectUrl(String objectName) {
        String url = "";
        try {
            if (bucketExists()) {
                // 设置预签名URL的有效期(以秒为单位)
                int expiresInSeconds = 3600; // 一小时
                url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET) //只能get请求访问
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(expiresInSeconds) // 设置有效时间
                        .build());
            }
        } catch (Exception e) {
            throw new RuntimeException("获取失败", e);
        }
        return url;
    }

    /**
     * 获取(下载)单个文件
     *
     * @param fileName 文件名
     * @return 输出流
     */
    public ResponseEntity<ByteArrayResource> getObject(String fileName){
        // 获取输入流
        try (InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName).build())) {

            byte[] byteArray = IOUtils.toByteArray(inputStream);
            ByteArrayResource resource = new ByteArrayResource(byteArray);

            //设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);

            //开始下载
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(byteArray.length)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        }catch (Exception e) {
            throw new RuntimeException("下载失败", e);
        }
    }

    /**
     * 获取(下载)多个文件,写进zip压缩包返回
     *
     * @param objectNames 资源名数组
     * @return 输出流
     */
    public ResponseEntity<byte[]> getObjectList(String[] objectNames) {
        // 创建一个输出流,将文件写入压缩包
        try (ByteArrayOutputStream aos = new ByteArrayOutputStream();
             ZipOutputStream zos = new ZipOutputStream(aos)) {

            for (String objectName : objectNames) {
                // 获取对象
                InputStream inputStream = minioClient.getObject(
                        GetObjectArgs.builder()
                                .bucket(bucketName)
                                .object(objectName)
                                .build());

                // 创建一个新的ZIP条目,并将文件写入压缩包
                ZipEntry zipEntry = new ZipEntry(objectName);
                zos.putNextEntry(zipEntry);

                byte[] buffer = new byte[8192];
                int length;
                while ((length = inputStream.read(buffer)) > 0) {
                    zos.write(buffer, 0, length);
                }

                // 关闭当前的ZIP条目
                zos.closeEntry();
                inputStream.close();
            }

            // 关闭 ZIP 输出流
            zos.close();

            // 将压缩包的字节数组作为响应体返回
            byte[] zipBytes = aos.toByteArray();

            //设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=output.zip");

            //开始下载
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(zipBytes.length)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(zipBytes);
        } catch (Exception e) {
            throw new RuntimeException("文件下载失败", e);
        }
    }
}
5.编写控制器
@RestController
@RequestMapping(value = "/file")
public class FileController {

    @Resource
    private MinioUtils minioUtils;

    /**
     * 获取元数据
     * @param fileName 文件名
     * @return 元数据
     */
    @GetMapping(value = "/stat")
    public SysResult stat(String fileName) {
        return minioUtils.statObject(fileName);
    }

    /**
     * 根据文件名获取临时访问URL
     * @param fileName 文件名
     * @return 临时访问URL
     */
    @GetMapping(value = "/getUrl")
    public SysResult get(String fileName) {
        return SysResult.data(minioUtils.getObjectUrl(fileName));
    }

    /**
     * 下载单个文件
     *
     * @param fileName 文件名
     * @return 流
     */
    @GetMapping(value = "/download")
    public ResponseEntity<ByteArrayResource> downloadFile(String fileName) {
        return minioUtils.getObject(fileName);
    }

    /**
     * 下载多个文件到压缩包返回
     * @param fileName 要下载的文件名数组
     * @return 压缩流
     */
    @GetMapping(value = "/package")
    public ResponseEntity<byte[]> list(String[] fileName) {
        return minioUtils.getObjectList(fileName);
    }

    /**
     * 上传单个文件
     * @param file 文件
     * @return 是否上传成功
     */
    @PostMapping(value = "/upload")
    public SysResult upload(@RequestParam("file") MultipartFile file) {
        return minioUtils.putObject(file);
    }

    /**
     * 上传多个文件
     *
     * @param file 文件数组
     * @return 上传成功
     */
    @PostMapping(value = "/uploadList")
    public SysResult uploadList(@RequestParam("file") MultipartFile[] file) {
        return minioUtils.putObject(file);
    }

    /**
     * 删除单个文件
     *
     * @param fileName 文件名
     * @return 删除成功
     */
    @GetMapping(value = "/remove")
    public SysResult remove(String fileName) {
        minioUtils.removeObject(fileName);
        return SysResult.success("删除成功", fileName);
    }
}

接下来就可以跟接口愉快得玩耍了。

标签: spring boot 后端 java

本文转载自: https://blog.csdn.net/weixin_44081566/article/details/133146293
版权归原作者 一万大宽面 所有, 如有侵权,请联系我们删除。

“Win10安装Minio及SpringBoot集成Minio”的评论:

还没有评论