阿里 对象存储OSS 云存储服务

1.简介

对象存储服务(Object Storage Service ,OSS) 是一种 海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。

2.如何使用。参考文档

看文档,说的很明白,这里就不演示了

3. SpringCloudAlibaba-OSS

spring-cloud-alibaba/README-zh.md at 2022.x · alibaba/spring-cloud-alibaba · GitHub

好像新版本没有starter了

自己封装一下原生API吧

java 复制代码
package com.jmj.gulimall.product.config;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OssClientConfiguration {

    @Value("${spring.cloud.alicloud.access-key}")
    private String accessKey;
    @Value("${spring.cloud.alicloud.secret-key}")
    private String secretKey;
    @Value("${spring.cloud.alicloud.endpoint}")
    private String endpoint;

    @Bean
    public OSS ossClient() {
        // 创建OSSClient实例。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKey, secretKey);
        // 创建ClientBuilderConfiguration。
        // ClientBuilderConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置Socket层传输数据的超时时间,默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间,默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置失败请求重试次数,默认为3次。
        conf.setMaxErrorRetry(5);
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider,conf);
        return ossClient;
    }


}
java 复制代码
package com.jmj.gulimall.product.ossclient;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Component
@Slf4j
public class OssClientTemplate {

    @Autowired
    private OSS ossClient;

    public Boolean uploadFile(String bucketName, String objectName, File file) {
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, String content){
        // 创建PutObjectRequest对象。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content.getBytes());
        try {

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, byteArrayInputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (byteArrayInputStream!=null){
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (inputStream!=null){
                try {
                    //其实流已经被关闭了,我再关闭一下保险一点
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
    public Boolean uploadFile(String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        return uploadFile("gulimall-jmj", objectName, inputStream);
    }
}

4.后端签名直传

java 复制代码
package com.jmj.gulimall.third.config;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.jmj.gulimall.third.ossclient.OssClientTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties({OssConfigurationProperties.class})
@Slf4j
@RefreshScope //动态从配置中心获取配置
public class OssClientConfiguration {

    @Autowired
    private OssConfigurationProperties ossConfigurationProperties;

    @Bean
    public OSS ossClient() {
        // 创建OSSClient实例。
        CredentialsProvider credentialsProvider = new DefaultCredentialProvider(ossConfigurationProperties.getAccessKey(), ossConfigurationProperties.getSecretKey());
        // 创建ClientBuilderConfiguration。
        // ClientBuilderConfiguration是OSSClient的配置类,可配置代理、连接超时、最大连接数等参数。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置是否支持CNAME。CNAME用于将自定义域名绑定到目标Bucket。
        conf.setSupportCname(true);
        // 设置Socket层传输数据的超时时间,默认为50000毫秒。
        conf.setSocketTimeout(10000);
        // 设置建立连接的超时时间,默认为50000毫秒。
        conf.setConnectionTimeout(10000);
        // 设置失败请求重试次数,默认为3次。
        conf.setMaxErrorRetry(5);
        OSS ossClient = new OSSClientBuilder().build(ossConfigurationProperties.getEndpoint(), credentialsProvider, conf);
        log.info("ossClient初始化完成,properties={}",ossConfigurationProperties);
        return ossClient;
    }


    @Bean
    public OssClientTemplate ossClientTemplate(OSS ossClient) {
        return new OssClientTemplate(ossClient,ossConfigurationProperties);
    }

}
java 复制代码
package com.jmj.gulimall.third.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@ConfigurationProperties(prefix = "spring.cloud.alicloud")
@Data
@RefreshScope //动态从配置中心获取配置
public class OssConfigurationProperties {

    private String accessKey;

    private String secretKey;

    private String endpoint;

    private String regionEnd;

    private String bucket;



}
java 复制代码
package com.jmj.gulimall.third.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.jmj.gulimall.third.common.R;
import com.jmj.gulimall.third.config.OssConfigurationProperties;
import com.jmj.gulimall.third.ossclient.OssClientTemplate;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@RestController
@Slf4j
@RequestMapping("/oss")
public class OssController {

    @Autowired
    private OssClientTemplate ossClientTemplate;

    @Autowired
    private OssConfigurationProperties properties;

    @GetMapping("/policy")
    public R policy(HttpServletRequest request, HttpServletResponse response) {

        // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
//                String callbackUrl = "https://192.168.0.0:8888";
        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String formatDate = simpleDateFormat.format(new Date());
        String dir = formatDate + "/";

        OSS ossClient = ossClientTemplate.getOssClient();
        String accessKeyId = properties.getAccessKey();
        String regionEnd = properties.getRegionEnd();
        String bucket = properties.getBucket();
        String host = "https://" + bucket + "." + regionEnd;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            // PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String accessId = accessKeyId;
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));
            return R.ok().put("data",respMap);

        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            log.error(e.getMessage(), e);
        }
        return  R.error("上传签名异常");
    }


}
java 复制代码
package com.jmj.gulimall.third.ossclient;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.jmj.gulimall.third.config.OssConfigurationProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class OssClientTemplate {

    private OSS ossClient;

    public OSS getOssClient() {
        return ossClient;
    }
    private OssConfigurationProperties properties;

    public OssClientTemplate(OSS ossClient, OssConfigurationProperties properties) {
        this.ossClient = ossClient;
        this.properties = properties;
    }

    public Boolean uploadFile(String bucketName, String objectName, File file) {
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, String content){
        // 创建PutObjectRequest对象。
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(content.getBytes());
        try {

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, byteArrayInputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (byteArrayInputStream!=null){
                try {
                    byteArrayInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public Boolean uploadFile(String bucketName, String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", true);
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            putObjectRequest.setMetadata(metadata);
            // 上传文件。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            log.info("上传成功:文件名 {}", objectName);
            return true;
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            log.error("Error Message:" + oe.getErrorMessage());
            log.error("Error Code:" + oe.getErrorCode());
            log.error("Request ID:" + oe.getRequestId());
            log.error("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            log.error("Error Message:" + ce.getMessage());
        }finally {
            if (inputStream!=null){
                try {
                    //其实流已经被关闭了,我再关闭一下保险一点
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
    public Boolean uploadFile(String objectName, InputStream inputStream){
        // 创建PutObjectRequest对象。
        return uploadFile(properties.getBucket(), objectName, inputStream);
    }
}
相关推荐
一枚小小程序员哈2 小时前
基于Vue的个人博客网站的设计与实现/基于node.js的博客系统的设计与实现#express框架、vscode
vue.js·node.js·express
定栓2 小时前
vue3入门-v-model、ref和reactive讲解
前端·javascript·vue.js
LIUENG3 小时前
Vue3 响应式原理
前端·vue.js
wycode4 小时前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode5 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏5 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
pepedd8646 小时前
还在开发vue2老项目吗?本文带你梳理vue版本区别
前端·vue.js·trae
前端缘梦6 小时前
深入理解 Vue 中的虚拟 DOM:原理与实战价值
前端·vue.js·面试
HWL56796 小时前
pnpm(Performant npm)的安装
前端·vue.js·npm·node.js
柯南95277 小时前
Vue 3 reactive.ts 源码理解
vue.js