OSS 对象存储

项目总结

使用 Minio 实现开发环境下面的对象处理操作,使用 aliyun 实现上线环境下面的对象存储操作,同时使用storage.type实现Factory构建一个替换工厂模式,实现对应 OSS 环境的替换操作

Minio 实现对象存储

Docker 或者本地直接构建 Minio 环境

直接 Pull 对应的 Docker Image 实现部署 Docker 的minio 环境实现数据对象的存储操作

# 拉取 minio 镜像
docker pull minio/minio:[version] eg -> RELEASE.2023-09-30T07-02-29Z
# 开启 minio 镜像
docker run minio/minio:[version]
# 注意开放的端口是 9000 9090

配置 POM 的 maven 依赖

使用对应的版本的 maven 的依赖实现对应的 API 的引入操作,之后配置对应的链接 endpoint, accessKey, secretKey之后实现链接本地的部署环境的Minio

        <!--对象存储 Minio-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
        </dependency>

配置对应的 yaml 文件

对应的 endpoint, accessKey, secretKey 是不能直接硬编码的,所以使用yaml配置实现对应的数据引入操作

# 项目中间使用 storage 作为前面的总文件头实现 OSS 环境的替换操作
minio:
  endpoint: http://127.0.0.1:9000
  accessKey: caiusluo
  secretKey: caiusluo

配置 Config 与 Properties 实现类

Config -> 导入配置 endpoint, accessKey, secretKey, 同时构建对象操作的 Client

Properties -> 配置endpoint, accessKey, secretKey

// Properties 文件
@ConfigurationProperties(prefix = "storage.minio")
@Component
@Data
public class MinioProperties {
    private String endPoint;
    private String accessKey;
    private String secretKey;
}
// Config 文件
@Configuration
public class MinioConfig {

    @Resource
    private  MinioProperties minioProperties;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(minioProperties.getEndPoint())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey())
                .build();
    }
}

上传文件实现 upload 操作

@Slf4j
public class MinioFileStrategy implements FileStrategy {

    @Resource
    private MinioProperties minioProperties;

    @Resource
    private MinioClient minioClient;

    @Override
    @SneakyThrows
    public String uploadFile(MultipartFile file, String buketName) {
        log.info("## 文件上传至 Minio ...");
        // 文件判空
        if (file == null || file.getSize() == 0) {
            log.error("==> 上传文件异常: 文件大小为空 ...");
            throw new RuntimeException("文件大小不能为空");
        }
        String originalFilename = file.getOriginalFilename();
        String contentType = file.getContentType();

        String key = UUID.randomUUID().toString().replace("-", "");
        String suffex = originalFilename.substring(originalFilename.lastIndexOf("."));

        String objectName = String.format("%s%s", key, suffex);

        log.info("==> 开始上传文件至 Minio, ObjectName: {}", objectName);

        // 上传文件
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(buketName)
                .object(objectName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(contentType)
                .build());

        // 返回访问文件 URL
        String url = String.format("%s/%s/%s", minioProperties.getEndPoint(), buketName, objectName);

        log.info("==> 文件上传至 Minio 成功, 访问路径: {}", url);

        return url;
    }
}

Aliyun 实现对象存储

购买 aliyun 的 OSS 服务

直接购买对应的 aliyun 服务之后使用对应的服务指导实现开始步骤即可,之后使用的 POM 文件直接使用 Aliyun 提供的文件操作

导入 POM 的 maven 依赖

直接看 aliyun 的 guide 文件 https://help.aliyun.com/zh/oss/developer-reference/getting-started

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
        </dependency>

配置对应的 yaml 文件

aliyun-oss:
  endpoint: oss-cn-shenzhen.aliyuncs.com
  accessKey: # 阿里云 accessKeyId
  secretKey: # 阿里云 accessKeySecret

配置 config 和 Properties 实现类

// config 文件
@Configuration
public class AliyunOSSConfig {

    @Resource
    private AliyunOSSProperties aliyunOSSProperties;

    /**
     * 构建阿里云 OSS 实例
     * @return
     */
    @Bean
    public OSS aliyunOSSClient() {
        // 设置访问凭证
        DefaultCredentialProvider credentialsProvider = CredentialsProviderFactory.newDefaultCredentialProvider(
                aliyunOSSProperties.getAccessKey(), aliyunOSSProperties.getSecretKey());

        // 创建 OSSClient 实例
        return new OSSClientBuilder().build(aliyunOSSProperties.getEndPoint(), credentialsProvider);
    }
}
// properties 文件
@ConfigurationProperties(prefix = "storage.aliyun-oss")
@Component
@Data
public class AliyunOSSProperties {
    private String endPoint;
    private String accessKey;
    private String secretKey;
}

upload file 文件上传操作

aliyun guide doc

        // 1. 创建存储空间(Bucket)
        ossClient.createBucket(bucketName);
        System.out.println("1. Bucket " + bucketName + " 创建成功。");
        // 2. 上传文件
        String objectName = "exampledir/exampleobject.txt";
        String content = "Hello OSS";
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
        System.out.println("2. 文件 " + objectName + " 上传成功。");
        // 3. 下载文件
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
        InputStream contentStream = ossObject.getObjectContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(contentStream));
        String line;
        System.out.println("3. 下载的文件内容:");
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        contentStream.close();
        // 4. 列出文件
        System.out.println("4. 列出 Bucket 中的文件:");
        ObjectListing objectListing = ossClient.listObjects(bucketName);
        for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
            System.out.println(" - " + objectSummary.getKey() + " (大小 = " + objectSummary.getSize() + ")");
        }
        // 5. 删除文件
        ossClient.deleteObject(bucketName, objectName);
        System.out.println("5. 文件 " + objectName + " 删除成功。");
        // 6. 删除存储空间(Bucket)
        ossClient.deleteBucket(bucketName);
        System.out.println("6. Bucket " + bucketName + " 删除成功。");

项目配置

@Slf4j
public class AliyunOSSFileStrategy implements FileStrategy {

    @Resource
    private AliyunOSSProperties aliyunOSSProperties;

    @Resource
    private OSS aliyunOSSClient;

    @Override
    @SneakyThrows
    public String uploadFile(MultipartFile file, String buketName) {
        log.info("## 文件上传至阿里云 OSS ...");
        if (file == null || file.getSize() == 0) {
            log.error("==> 上传文件异常: 文件大小不能为空 ...");
            throw new RuntimeException("文件大小不能为空");
        }
        String originalFilename = file.getOriginalFilename();
        String contentType = file.getContentType();

        String key = UUID.randomUUID().toString().replace("-", "");
        String suffex = originalFilename.substring(originalFilename.lastIndexOf("."));

        String objectName = String.format("%s%s", key, suffex);

        log.info("==> 开始上传文件至 aliyun, ObjectName: {}", objectName);

        // 上传文件到 aliyun
        aliyunOSSClient.putObject(buketName, objectName, new ByteArrayInputStream(file.getInputStream().readAllBytes()));

        // 生成链接对应 aliyun 的配置文件
        String url = String.format("https://%s.%s/%s", buketName, aliyunOSSProperties.getEndPoint(), objectName);

        log.info("==> 上传文件至阿里云成功, 访问路径:{}", url);

        return url;
    }
}