minio临时凭证直传切换到阿里云oss

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: minio临时凭证直传切换到阿里云oss

代码非常简单,像之前的实现:

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ContentType;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.namaste.hsswobjectstorage.api.service.IOssService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.Date;
import java.util.List;

import static java.util.stream.Collectors.*;

/**
 * AliOssServiceImpl
 *
 * @author achao@apache.org
 */
@Service
public class AliOssServiceImpl implements IOssService {

    @Resource
    private OSS ossClient;

    /**
     * @param rootPath bucket是配死的
     * @param fileName fileName
     * @return 预签名url
     */
    @Override
    public String getPresignedUrlPut(String bucket, String fileName) {
        var expiration = new Date(new Date().getTime() + 3600 * 1000L);
        var objectName = DateUtil.date().toDateStr() +
                FileNameUtil.UNIX_SEPARATOR +
                UUID.fastUUID() +
                DateUtil.date().toTimestamp() +
                StrPool.DOT +
                FileNameUtil.extName(fileName);
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, objectName, HttpMethod.PUT);
        request.setExpiration(expiration);
        request.setContentType(ContentType.OCTET_STREAM.getValue());
        return ossClient.generatePresignedUrl(request).toString();
    }

    @Override
    public void deleteBatch(List<String> fileUrls) {
        if (ObjectUtils.isEmpty(fileUrls)) {
            return;
        }
        var bucketObjectsMap = fileUrls.stream()
                .collect(groupingBy(
                        url -> url.substring(url.indexOf(StrPool.SLASH) + 2, url.indexOf(StrPool.DOT)),
                        mapping(url -> StrUtil.removePrefix(URLUtil.getPath(url), StrPool.SLASH),
                                toList())));
        bucketObjectsMap.entrySet().stream()
                .map(entry -> {
                    var req = new DeleteObjectsRequest(entry.getKey());
                    req.setKeys(entry.getValue());
                    return req;
                }).forEach(ossClient::deleteObjects);
    }

}

minio的实现:

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.text.StrPool;

import io.minio.RemoveObjectsArgs;
import io.minio.messages.DeleteObject;
import jakarta.annotation.Resource;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.minio.MinioConstants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.*;

/**
 * OssServiceImpl
 *
 * @author VampireAchao<achao @ hutool.cn>
 * @since 2023/10/5
 */
//@Service
public class MinioOssServiceImpl implements IOssService {

    @Value("${camel.component.minio.presigned-url-expire}")
    private Duration presignedUrlExpire;
    @Resource
    private ProducerTemplate producerTemplate;
    @Lazy
    @Resource
    private IOssService ossService;

    @Override
    public String getPresignedUrlPut(String bucket, String fileName) {
        var objectName = DateUtil.date().toDateStr() +
                FileNameUtil.UNIX_SEPARATOR +
                UUID.fastUUID() +
                DateUtil.date().toTimestamp() +
                StrPool.DOT +
                FileNameUtil.extName(fileName);
        return String.valueOf(producerTemplate.requestBodyAndHeaders(
                "direct:createUploadLink", "",
                Map.of(MinioConstants.BUCKET_NAME, bucket,
                        MinioConstants.OBJECT_NAME, objectName,
                        MinioConstants.PRESIGNED_URL_EXPIRATION_TIME, presignedUrlExpire)));
    }

    @Override
    public void deleteBatch(List<String> fileUrls) {
        if (ObjectUtils.isEmpty(fileUrls)) {
            return;
        }
        var bucketObjectsMap = fileUrls.stream().map(path -> UrlBuilder.of(path).getPath())
                .collect(groupingBy(path -> path.getSegment(0), mapping(path -> {
                    path.getSegments().remove(0);
                    return String.join(StrPool.SLASH, path.getSegments());
                }, toList())));
        bucketObjectsMap.entrySet().stream()
                .map(entry -> RemoveObjectsArgs.builder()
                        .bucket(entry.getKey())
                        .objects(entry.getValue().stream().map(DeleteObject::new).toList())
                ).parallel()
                .forEach(args -> producerTemplate.sendBody("direct:deleteBatch", args));
    }

}

对应的service

import com.namaste.enums.GreenLabelEnum;
import org.dromara.streamquery.stream.core.variable.BoolHelper;

import java.util.List;

/**
 * IOssService
 *
 * @author VampireAchao<achao @ hutool.cn>
 * @since 2023/10/5
 */
public interface IOssService {

    /**
     * 获取预签名url上传
     *
     * @param bucket   桶
     * @param fileName fileName
     * @return 用于上传资源的url
     */
    String getPresignedUrlPut(String bucket, String fileName);

    /**
     * 批量删除
     *
     * @param fileUrls fileUrls
     */
    void deleteBatch(List<String> fileUrls);

    /**
     * 内容安全审查
     *
     * @param img 图片url
     * @return 审查结果
     */
    default GreenVO green(String img) {
        var result = GreenUtil.inspectImg(img, GreenLabelEnum.LIVE_STREAM_CHECK);
        var vo = GreenVO.of(result);
        if (BoolHelper.isFalsy(vo.getIsViolation())) {
            deleteBatch(List.of(img));
        }
        return vo;
    }

}

test case

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.FileNotFoundException;
import java.util.List;

/**
 * OssServiceTest
 *
 * @author VampireAchao<achao @ hutool.cn>
 * @since 2023/10/5
 */
@SpringBootTest
class OssServiceTest {

    @Resource
    private IOssService ossService;

    @Test
    @SneakyThrows
    void getUploadSTSAndDeleteBatchTest() {
        var presignedUrl = ossService.getPresignedUrlPut("test", "test.txt");
        Assertions.assertNotNull(presignedUrl);
        var content = "Hello, Minio! Again!";
        try (var response = HttpUtil.createRequest(Method.PUT, presignedUrl)
                .body(content, "application/octet-stream").execute()) {
            Assertions.assertTrue(response.isOk());
        }
        var urlBuilder = UrlBuilder.of(presignedUrl).setQuery(new UrlQuery());
        Assertions.assertEquals(content,
                IoUtil.readUtf8(urlBuilder.toURL().openStream()));
        ossService.deleteBatch(List.of(urlBuilder.toString()));
        Assertions.assertThrows(FileNotFoundException.class,
                () -> IoUtil.readUtf8(urlBuilder.toURL().openStream()));
    }

    @Test
    void greenNormalTest() {
        var url = [foo];
        var bytes = IoUtil.readBytes(URLUtil.getStream(URLUtil.url(url)));
        var preUrl = ossService.getPresignedUrlPut("test", "normal.jpg");
        try (var response = HttpUtil.createRequest(Method.PUT, preUrl).contentType(ContentType.OCTET_STREAM.getValue()).body(bytes).execute()) {
            Assertions.assertTrue(response.isOk());
            var urlBuilder = UrlBuilder.of(preUrl).setQuery(new UrlQuery());
            Assertions.assertEquals(bytes.length, IoUtil.readBytes(URLUtil.getStream(urlBuilder.toURL())).length);
            var imgUrl = urlBuilder.toURL().toString();
            var greenVO = ossService.green(imgUrl);
            Assertions.assertFalse(greenVO.getIsViolation());
            Assertions.assertThrows(FileNotFoundException.class,
                    () -> IoUtil.readUtf8(urlBuilder.toURL().openStream()));

        }
    }


    @Test
    void greenYellowTest() {
        var url = [bar];
        var bytes = IoUtil.readBytes(URLUtil.getStream(URLUtil.url(url)));
        var preUrl = ossService.getPresignedUrlPut("test", "normal.jpg");
        try (var response = HttpUtil.createRequest(Method.PUT, preUrl).body(bytes).execute()) {
            Assertions.assertTrue(response.isOk());
            var urlBuilder = UrlBuilder.of(preUrl).setQuery(new UrlQuery());
            Assertions.assertEquals(bytes.length, IoUtil.readBytes(URLUtil.getStream(urlBuilder.toURL())).length);
            var imgUrl = urlBuilder.toURL().toString();
            var greenVO = ossService.green(imgUrl);
            Assertions.assertTrue(greenVO.getIsViolation());
            var readBytes = IoUtil.readBytes(URLUtil.getStream(urlBuilder.toURL()));
            Assertions.assertEquals(readBytes.length, bytes.length);
        }
    }

}
相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
30天前
|
存储 安全 对象存储
手把手教你搭建阿里云图床(PicGo+Typora+阿里云OSS),新手小白一看就会
本文详细介绍了怎样帮助新手小白从注册,购买阿里云OSS,到一步一步配置OSS做为图床,和PicGo、Typora软件连接,配置好关联之后,在使用Typora写文章时,如果需要插入图片,只需要将图片复制粘贴到Typora的编辑区域,就会自动通过PicGo上传到指定图床,自动复制外网能访问的URL并展示,简直不要太方便,极大的解决了编辑文章时复制处理图片链接的痛点。
149 2
手把手教你搭建阿里云图床(PicGo+Typora+阿里云OSS),新手小白一看就会
|
1月前
|
弹性计算 前端开发 小程序
微信小程序上传文件至阿里云OSS直传(java后端签名+前端直传)
当前的通用文件上传方式是通过前端上传到服务器,再由服务器转存至对象存储。这种方式在处理小文件时效率尚可,但大文件上传因受限于服务器带宽,速度较慢。例如,一个100MB的文件在5Mbps带宽的阿里云ECS上上传至服务器需160秒。为解决此问题,可以采用后端签名的方式,使微信小程序直接上传文件到阿里云OSS,绕过服务器中转。具体操作包括在JAVA后端引入相关依赖,生成签名,并在微信小程序前端使用这个签名进行文件上传,注意设置正确的请求头和formData参数。这样能提高大文件上传的速度。
|
6天前
|
存储 Java API
阿里云oss简介和使用流程
本文档介绍了如何准备阿里云OSS(对象存储服务)并开始使用它。首先,需要注册阿里云账号并进行实名认证,然后购买OSS资源包。在阿里云控制台中,可以创建和管理OSS存储空间(称为“Bucket”)。接着,文章简要介绍了阿里云OSS,它是一个基于云端的对象存储服务,提供高可靠性、高性能、低成本和易于使用的特性。 在阿里云OSS控制台,用户可以进行文件的上传和下载操作。通过API,开发者可以使用各种编程语言(如Java)来创建、删除Bucket以及上传、下载和删除文件。例如,Java代码示例展示了如何创建Bucket、上传文件、删除文件以及下载文件到本地的操作。
|
13天前
|
开发工具 对象存储
阿里云OSS文件上传
阿里云OSS文件上传
53 0
|
13天前
|
存储 缓存 Java
阿里云OSS实战从入门到大神
说起阿里云OSS,那作用和功能都是非常强大的,它可以存放图片,音频,视频等资源文件,这些资源文件,你不必存放到服务器的硬盘里,这样既可以节省服务器硬盘空间,又可以降低服务器的读写压力,非常适合大并发的架构。
53 0
|
25天前
|
存储 对象存储 容器
阿里云OSS对象存储基础入门
阿里云OSS对象存储基础入门
87 0
|
1月前
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
769 1
|
4月前
|
存储 测试技术 区块链
阿里云、百度云及移动云对象存储横向性能对比测试
在企业的数字化转型进程中,我们观察到越来越多的公司将其IT基础设施迁移到云端。随着企业业务的持续运营,无论是储存、处理、分享还是删除,都会产生大量的数据,这就要求有一个既可靠又高效的系统来管理和存储这些信息。对象存储产品在这个场景中扮演了至关重要的角色。它们以一种可扩展、安全、持久的方式,有效地满足了对大规模非结构化数据存储的需求。 尽管市场上云计算提供商众多,各自都有自己独特的对象存储产品,面对这样的丰富选择,如何寻找最符合企业需求的产品呢?这正是企业今天寻求解答的问题。 在本篇文章中,我们将深入进行一项横向对比测试,专门对阿里云OSS、百度云BOS和移动云EOS这三大云服务提供商的对象
1359 0
|
3月前
|
存储 Java 对象存储
springboot配置阿里云OSS存储实现文件上传下载功能
【1月更文挑战第1天】springboot配置阿里云OSS存储实现文件上传下载功能
533 2
|
3月前
|
Cloud Native Java 开发工具
云原生 阿里云分布式文件系统 对象存储OSS 服务配置
【1月更文挑战第8天】云原生 阿里云分布式文件系统 对象存储OSS 服务配置