相关文章推荐

MinIO 是一款基于Go语言发开的高性能、分布式的对象存储系统。 MinIO 英文官网 MinIO 中文官网 注意:中文官方更新不及时,会有很多坑,请以英文官网为准。

项目中使用minio存放抓拍图片,按抓拍类型(人脸图片、车辆图片、报警图片)分为不同的桶bucket,服务器存储空间的原因,需要定期删除人脸、车辆图片,使用了removeObjects函数,后来发现可以设置minio 桶的生命周期BucketLifecycle存储天数,囧了各大囧。

各种操作参考 java 客户端调用minio服务

以下是对项目中使用minio的java整理。

1、使用minio的包

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

2、minio 客户端的创建

@Component public class MinioClientManager implements InitializingBean { * 服务器查询地址,多个以逗号分开 @Value("${minio.searchIp}") private String searchIp; * 登录账号 @Value("${minio.accessKey}") private String accessKey; * 登录密码 @Value("${minio.secretKey}") private String secretKey; public static Map<String, MinioClient> minioClientMap = new HashMap<>(); public OkHttpClient httpClient() { OkHttpClient okHttpClient = new OkHttpClient.Builder() .retryOnConnectionFailure(true) .callTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .build(); return okHttpClient; @Override public void afterPropertiesSet() { String[] searchIps = searchIp.split(","); for (String s : searchIps) { MinioClient minioClient = MinioClient .builder() .endpoint(s) .httpClient(httpClient()) .credentials(accessKey, secretKey) .build(); minioClientMap.put(s, minioClient);

3、minio项目中用到的操作

@Component
public class MultiMinioTemplate implements InitializingBean {
     * 主服务器地址
    public static String nowIp;
    @Value("${minio.ip}")
    public void setNowIp(String nowIp) {
        MultiMinioTemplate.nowIp = nowIp;
     * 服务器地址
    @Value("${minio.oldIp}")
    private String oldIp;
     * 服务器查询地址,多个以逗号分开
    @Value("${minio.searchIp}")
    private String searchIp;
     * 图片访问前缀
    @Value("${minio.accessUrlPrefix}")
    private String accessUrlPrefix;
    @Autowired
    private MinioClientManager minioClientManager;
    public MinioClient getMinioClientByIp(String ip) {
        if (StringUtils.isBlank(ip)) {
            ip = oldIp;
        return minioClientManager.minioClientMap.get(ip);
    public String getAccessUrlPrefix() {
        return accessUrlPrefix;
     * 检查文件存储桶是否存在
     * @param bucketName
     * @return
    @SneakyThrows
    public boolean bucketExists(String bucketName, String ip) {
        BucketExistsArgs build = BucketExistsArgs.builder().bucket(bucketName).build();
        return getMinioClientByIp(ip).bucketExists(build);
     * 创建bucket
     * @param bucketName bucket名称
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (bucketExists(bucketName, nowIp)) {
            return;
        getMinioClientByIp(nowIp).makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
     * 根据bucketName删除信息
     * @param bucketName bucket名称
    @SneakyThrows
    public void removeBucket(String bucketName, String ip) {
        if (StringUtils.isBlank(ip)) {
            String[] searchIps = searchIp.split(",");
            for (String s : searchIps) {
                if (this.bucketExists(s, bucketName)) {
                    RemoveBucketArgs build = RemoveBucketArgs.builder().bucket(bucketName).build();
                    getMinioClientByIp(s).removeBucket(build);
        } else {
            if (this.bucketExists(ip, bucketName)) {
                RemoveBucketArgs build = RemoveBucketArgs.builder().bucket(bucketName).build();
                getMinioClientByIp(ip).removeBucket(build);
     * 获取文件外链
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
    @SneakyThrows
    public String getObjectURL(String bucketName, String ip, String objectName, Integer expires) {
        GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
                .builder()
                .bucket(bucketName)
                .object(objectName)
                .expiry(expires, TimeUnit.DAYS)
                .method(Method.GET)
                .build();
        return getMinioClientByIp(ip).getPresignedObjectUrl(build);
     * 获取文件外链
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return url
    @SneakyThrows
    public String getObjectURL(String bucketName, String ip, String objectName) {
        return this.getObjectURL(bucketName, ip, objectName, 7);
     * 获取文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
    @SneakyThrows
    public InputStream getObject(String bucketName, String ip, String objectName) {
        GetObjectArgs build = GetObjectArgs
                .builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return getMinioClientByIp(ip).getObject(build);
     * 上传文件
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param size        大小
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
        PutObjectArgs build = PutObjectArgs
                .builder()
                .bucket(bucketName)
                .object(objectName)
                .stream(stream, -1, 10 * 1024 * 1024)
                .contentType(contextType)
                .build();
        getMinioClientByIp(nowIp).putObject(build);
     * 删除文件
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
    public void removeObject(String bucketName, String ip, String objectName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, ErrorResponseException, io.minio.errors.InternalException, XmlParserException, ServerException, InvalidResponseException {
        RemoveObjectArgs build = RemoveObjectArgs
                .builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        getMinioClientByIp(ip).removeObject(build);
     * 删除文件s
     * @param bucketName bucket名称
     * @param objectNames 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
    public Iterable<Result<DeleteError>> removeObjects(String bucketName, String ip, List<String> objectNames) {
        List<DeleteObject> objects = new LinkedList<>();
        objectNames.forEach(objectName->objects.add(new DeleteObject(objectName)));
        RemoveObjectsArgs build = RemoveObjectsArgs
                .builder()
                .bucket(bucketName)
                .objects(objects)
                .build();
        return getMinioClientByIp(ip).removeObjects(build);
     * 列出某个存储桶中的所有对象。
     * @param ip minio ip
     * @param args 查询条件
     *    // Lists maximum 100 objects information with version whose names starts with 'E' and after
     *    // 'ExampleGuide.pdf'.
     *    Iterable<Result<Item>> results = minioClient.listObjects(
     *         ListObjectsArgs.builder()
     *             .bucket("my-bucketname")
     *             .startAfter("ExampleGuide.pdf")
     *             .prefix("E")
     *             .maxKeys(100)
     *             .includeVersions(true)
     *             .build());
    public Iterable<Result<Item>> listObjects(String ip, ListObjectsArgs args) throws XmlParserException {
         return getMinioClientByIp(ip).listObjects( args);
    public void setBucketLifecycle(String ip, SetBucketLifecycleArgs args)
            throws ErrorResponseException, InsufficientDataException, io.minio.errors.InternalException,
            InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
            ServerException, XmlParserException {
        getMinioClientByIp(ip).setBucketLifecycle(args);
    public LifecycleConfiguration getBucketLifecycle(String ip, GetBucketLifecycleArgs args)
            throws ErrorResponseException, InsufficientDataException, io.minio.errors.InternalException,
            InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
            ServerException, XmlParserException {
        return getMinioClientByIp(ip).getBucketLifecycle(args);
    public void deleteBucketLifecycle(String ip, DeleteBucketLifecycleArgs args)
            throws ErrorResponseException, InsufficientDataException, io.minio.errors.InternalException,
            InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
            ServerException, XmlParserException {
        getMinioClientByIp(ip).deleteBucketLifecycle(args);
    @Override
    public void afterPropertiesSet() {

4、生命周期的设置

    public String setBucketLifeCycle(String ip,String bucketName,String ruleId,int expireDays,Boolean deleteMarker){
        List<LifecycleRule> rules = new LinkedList<>();
        rules.add(new LifecycleRule(Status.ENABLED,
                        null,
                        new Expiration((ZonedDateTime) null, expireDays, deleteMarker),
                        null,
                        ruleId,
                        null,
                        null,
                        null));
        LifecycleConfiguration config = new LifecycleConfiguration(rules);
        try {
            minioTemplate.setBucketLifecycle(ip,SetBucketLifecycleArgs.builder().bucket(bucketName).config(config).build());
        }catch (Exception e){
            log.error("设置桶{}:{}生命周期异常", ip, bucketName, e);
            return "错误类型:"+e.getClass().getName();
        return "OK";
LifecycleRule 的配置参数
        AbortIncompleteMultipartUpload(int daysAfterInitiation)设置分片在距最后修改时间30天后过期。
        Expiration(ZonedDateTime date, Integer days, Boolean expiredObjectDeleteMarker) 指定日期或天数过期,标志删除or删除
        RuleFilter(AndOperator andOperator,String prefix,Tag tag) 依据前缀删除(前缀即桶内的文件夹名)还是tag标志删除
        id,一个桶可以设置多个rule
        NoncurrentVersionExpiration(int noncurrentDays)设置非当前版本的Object
        NoncurrentVersionTransition(int noncurrentDays,String storageClass) 设置非当前版本的Object距最后修改时间90天之后转为低频访问类型、归档类型。非当前版本对象何时进行存储类型的转换和转换的存储类型,待确认storageClass

一次可设置多个rule,第二次设置setBucketLifecycle会覆盖第一次设置setBucketLifecycle

5、生命周期获取、删除

minioTemplate.deleteBucketLifecycle(ip,DeleteBucketLifecycleArgs.builder() .bucket(bucketName).build()); minioTemplate.getBucketLifecycle(ip,GetBucketLifecycleArgs.builder() .bucket(bucketName).build())
还有三个参数设置,没明白怎么用
builder().region(String region)
builder().extraHeaders(Map<String, String> headers)  minioClient通过httpClicent访问,可设置http请求参数
builder().extraQueryParams(Map<String, String> queryParams)
minio-java
Minio 提供了多种语言的SDK,比如java、go、python等。JAVA开发平台可以选择JS和java SDK,也就是前端和后端都可以直接集成minio。
每个OSS的用户都会用到上传服务。Web端常见的上传方法是用户在浏览器或App端上传文件到应用服务器,应用服务器再把文件上传到OSS。具体流程如下图所示。
和数据直传到OSS相比,以上方法有三个缺点:
上传慢:用户数据需先上传到应用服务器,之后再上传到OSS。网络传输时间比直传到O
  endpoint: http://192.168.1.55:9000
  accessKey: 1777QN2GK9S6N02G83NK
  secretKey: 6gMzG26973fXJfKxEOSxaUTrFdy3+QtSggdprESJ
  bucketName: test
2. 创建minio的配置文件:
package com.common.properties;
import org.springframework.
				
直接在linux上进行环境搭建,使用命令进行下载minio并且启动服务 服务启动之后,可以直接对9000端口进行访问,同样的启动服务之后有日志进行输出。可以看到日志所表达的意思,在这里的一个控制台的端口是一个动态生成的,每一次启动服务的端口都会发生变换,在后续进行使用的使用肯定需要用到一个静态端口,可以使用来进行端口指定,并且第二个的话是指不推荐使用默认账号密码。 对账号密码进行设置,并且指定控制台端口进行启动。 在设置完账号密码之后进行启动,发现了报错,访问密钥长度至少3个字符,密钥长度至少8个字符……,
Java中使用Minio进行对象存储时,上传一个对象后会返回一个临时URL,该URL在一定时间后会失效。如果需要获取永久的URL,可以使用Minio提供的`presignedPutObject`和`presignedGetObject`方法。 - `presignedGetObject`: 获取一个永久的可下载URL,该URL可以用于下载指定的对象。示例代码如下: ```java // 初始化一个Minio客户端对象 MinioClient minioClient = new MinioClient("http://minio.example.com", "accessKey", "secretKey"); // 获取一个永久的可下载URL String url = minioClient.presignedGetObject("my-bucket", "my-object", 60 * 60 * 24 * 7); System.out.println("永久的可下载URL: " + url); - `presignedPutObject`: 获取一个永久的可上传URL,该URL可以用于上传一个对象。示例代码如下: ```java // 初始化一个Minio客户端对象 MinioClient minioClient = new MinioClient("http://minio.example.com", "accessKey", "secretKey"); // 获取一个永久的可上传URL String url = minioClient.presignedPutObject("my-bucket", "my-object", 60 * 60 * 24 * 7); System.out.println("永久的可上传URL: " + url); 以上示例代码中,`60 * 60 * 24 * 7`表示获取的URL有效期为一周,可以根据实际需求进行调整。获取到的永久URL可以保存在数据库或其他地方,用于后续的操作。