使用阿里云OSS实现文件上传功能


目录

1.前提

2.OSS存储的创建

3.SDK的安装

4.配置访问凭证(使用STS)

4.1创建用户

4.2为RAM用户授予请求AssumeRole的权限

4.3为RAM用户创建AccessKey

4.4创建阿里云账号(主账号)的AccessKey

4.5创建RAM角色

4.6为RAM角色授予上传文件的权限

4.6.1创建权限

4.6.2授予权限

5.获取临时访问凭证(官方提供的需要设置环境变量)

6.使用临时访问凭证上传文件至OSS

7.将配置获取访问凭证与上传文件功能(返回URL)封装为工具类

8.对于不清楚操作的建议查看相关官方文档


1.前提

注册阿里云账号,登录之后在右上角找到控制台并点击

进入页面

点击开始免费试用进入页面找到对象存储OSS免费试用

点击后购买即可,建议绑定支付宝可以顺便实名认证了

然后点击控制台回到控制台页面,鼠标左上角悬浮菜单栏出现以下界面,在产品与服务的搜索框搜索        对象存储        进入OSS管理控制台

2.OSS存储的创建

点击Bucket列表,然后点击创建Bucket

在创建界面填写名称,关闭阻止公共访问,并且将读写权限改为公共读即可完成创建

地域可改可不改

3.SDK的安装

在Maven工程中使用OSS Java SDK,在pom.xml中加入以下依赖即可

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


如果使用的是Java 9及以上的版本,则需要添加JAXB相关依赖。添加JAXB相关依赖示例代码如下:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

4.配置访问凭证(使用STS)

4.1创建用户

登录RAM控制台,在左侧导航栏,点击用户后在用户界面点击创建用户

填写完登录名称和显示名称后勾选OpenAPI调用访问,确定后完成安全验证即可

4.2为RAM用户授予请求AssumeRole的权限

单击已创建RAM用户右侧对应的添加权限,新增授权页面,搜索AliyunSTSAssumeRoleAccess系统策略,勾选后确认新增即可

4.3为RAM用户创建AccessKey

回到用户界面,点击刚刚创建的用户,在认证管理页签下的AccessKey区域,单击创建AccessKey

根据界面提示完成安全验证,在创建AccessKey对话框,查看AccessKey ID和AccessKey Secret,建议单击下载CSV文件,下载AccessKey信息。或者选择单击复制,复制AccessKey信息。

4.4创建阿里云账号(主账号)的AccessKey

鼠标悬浮在右上方的账号图标上,单击AccessKey管理

安全提示对话框,阅读安全提示信息,然后单击继续使用AccessKey,AccessKey页面,单击创建AccessKey即可(流程与为RAM用户创建AccessKey基本一致)

4.5创建RAM角色

进入RAM控制台,点击左栏角色右边显示角色界面,点击创建角色,选择阿里云账号点击下一步,输入角色名称后点击完成,关闭。在角色页面点击刚刚创建的角色,复制ARN,关闭

4.6为RAM角色授予上传文件的权限

4.6.1创建权限

点击左侧的权限策略,在该页面

创建权限策略,创建权限策略页面,单击脚本编辑,然后在策略文档输入框中赋予角色上传文件到examplebucket的权限。注意examplebucket需要更改为你最先创建的bucket

{
    "Version": "1",
    "Statement": [
     {
           "Effect": "Allow",
           "Action": [
             "oss:PutObject"
           ],
           "Resource": [
             "acs:oss:*:*:examplebucket/*"             
           ]
     }
    ]
}

策略配置完成后,单击继续编辑基本信息,基本信息区域,填写策略名称,然后单击确定

4.6.2授予权限

点击左侧角色,为刚刚创建的角色授予权限,点击新增授权,点击自定义策略,勾选刚刚创建的权限,确认授权即可

5.获取临时访问凭证(官方提供的需要设置环境变量)

package com.enjoy.utils;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;

public class StsServiceSample {

    public static void main(String[] args) {
        // STS服务接入点,例如sts.cn-hangzhou.aliyuncs.com。您可以通过公网或者VPC接入STS服务。
        String endpoint = "sts.cn-hangzhou.aliyuncs.com";
        //你的角色accessKeyId
        String accessKeyId = "";
        //你的角色accessKeySecret
        String accessKeySecret = "";
        //你的角色roleArn
        String roleArn = "";
        //会话名
        String roleSessionName = "test";

        // 临时访问凭证将获得角色拥有的所有权限。
        String policy = null;

        // 临时访问凭证的有效时间,单位为秒。最小值为900,最大值以当前角色设定的最大会话时间为准。
        // 当前角色最大会话时间取值范围为3600秒~43200秒,默认值为3600秒。
        Long durationSeconds = 3600L;

        try {
            // 发起STS请求所在的地域。建议保留默认值,默认值为空字符串("")。
            String regionId = "";

            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);

            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);

            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);

            // 创建AssumeRoleRequest对象,用于指定请求参数。
            final AssumeRoleRequest request = new AssumeRoleRequest();

            // 设置请求方法为POST。适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);

            // 设置要扮演的角色的ARN。
            request.setRoleArn(roleArn);

            // 设置角色会话名称,用于区分不同的令牌。
            request.setRoleSessionName(roleSessionName);

            // 设置权限策略。这里使用null表示不指定特定策略,即获取角色默认的权限。
            request.setPolicy(policy);

            // 设置临时凭证的有效时间,单位为秒。
            request.setDurationSeconds(durationSeconds);

            // 发送请求并获取响应。
            final AssumeRoleResponse response = client.getAcsResponse(request);

            // 打印获取到的临时凭证信息。
            System.out.println("Expiration: " + response.getCredentials().getExpiration());
            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
            System.out.println("RequestId: " + response.getRequestId());

        } catch (ClientException e) {
            // 捕获异常并输出错误信息。
            System.out.println("Failed:");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        }
    }
}

如果希望临时访问凭证在获得角色拥有的权限后,进一步限制权限范围,例如角色被授予了上传文件到你的bucket的权限,需要限制临时访问凭证只能向该Bucket下的某个目录上传文件,可以通过参考以下示例设置policy。

// 以下Policy用于限制仅允许使用临时访问凭证向examplebucket下的src目录上传文件。
// 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集,即仅允许将文件上传至examplebucket下的src目录。      
String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:PutObject\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:examplebucket/src/*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";

6.使用临时访问凭证上传文件至OSS

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyuncs.exceptions.ClientException;

import java.io.File;

public class Demo {
    public static void main(String[] args) throws ClientException {
// OSS访问域名。以华东1(杭州)地域为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取步骤5生成的临时访问密钥AccessKey ID和AccessKey Secret,非阿里云账号AccessKey ID和AccessKey Secret。
String accessKeyId = "OSS_ACCESS_KEY_ID";
String accessKeySecret = "OSS_ACCESS_KEY_SECRET";
// 从环境变量中获取步骤5生成的安全令牌SecurityToken。
String securityToken = "OSS_SESSION_TOKEN";

// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
// 将本地文件exampletest.txt上传至examplebucket(你的bucket)。
PutObjectRequest putObjectRequest = new PutObjectRequest("examplebucket", "exampletest.txt", new File("D:\\localpath\\exampletest.txt"));

// ObjectMetadata metadata = new ObjectMetadata();
// 上传文件时设置存储类型。
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// 上传文件时设置读写权限ACL。
// metadata.setObjectAcl(CannedAccessControlList.Private);
// putObjectRequest.setMetadata(metadata);

try {
     // 上传文件。
     ossClient.putObject(putObjectRequest);
    } catch (OSSException oe) {
        System.out.println("Caught an OSSException, which means your request made it to OSS, "
                + "but was rejected with an error response for some reason.");
        System.out.println("Error Message:" + oe.getErrorMessage());
        System.out.println("Error Code:" + oe.getErrorCode());
        System.out.println("Request ID:" + oe.getRequestId());
        System.out.println("Host ID:" + oe.getHostId());
    } finally {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }
}
}

7.将配置获取访问凭证与上传文件功能(返回URL)封装为工具类(建议使用7.2版本)

7.1 需要手动刷新来获取临时凭证

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
    private String oosEndpoint;
    private String stsEndpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String roleArn;
    private String bucketName;
}
#yml

#阿里云OSS
aliyun:
  oss:
    oosEndpoint: https://oss-cn-chengdu.aliyuncs.com
    stsEndpoint: sts.cn-chengdu.aliyuncs.com
    accessKeyId: 
    accessKeySecret: 
    roleArn: 
    bucketName: 
package com.enjoy.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

@Component
public class OSSUtils {

    @Autowired
    private AliOSSProperties aliOSSProperties;

    /**
     * 获取临时访问凭证。
     *
     * @param roleSessionName 角色会话名称,用于区分不同的令牌
     * @param durationSeconds 临时凭证的有效时间,单位为秒
     * @param policy          权限策略,传入null表示获取角色默认的权限
     * @return 临时访问凭证的响应对象
     */
    public AssumeRoleResponse getTemporaryCredentials(String roleSessionName, Long durationSeconds, String policy) {
        try {
            String regionId = "";
            DefaultProfile.addEndpoint(regionId, "Sts", aliOSSProperties.getStsEndpoint());
            IClientProfile profile = DefaultProfile.getProfile(regionId, aliOSSProperties.getAccessKeyId(), aliOSSProperties.getAccessKeySecret());
            DefaultAcsClient client = new DefaultAcsClient(profile);
            AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(aliOSSProperties.getRoleArn());
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(durationSeconds);
            return client.getAcsResponse(request);

        } catch (ClientException e) {
            // 捕获异常并输出错误信息。
            System.err.println("无法获取临时凭证:");
            System.err.println("Error code: " + e.getErrCode());
            System.err.println("Error message: " + e.getErrMsg());
            System.err.println("RequestId: " + e.getRequestId());
            return null;
        }
    }

    /**
     * 上传文件到OSS,并返回文件的URL。
     *
     * @param file 上传的文件
     * @return 文件的URL,上传失败返回null
     */
    public String uploadFile(MultipartFile file) {
        // 获取临时访问凭证
        AssumeRoleResponse response = getTemporaryCredentials("test", 3600L, null);

        if (response == null) {
            System.err.println("获取临时访问凭证失败,无法上传文件。");
            return null;
        }

        String endpoint = aliOSSProperties.getOosEndpoint();
        String accessKeyId = response.getCredentials().getAccessKeyId();
        String accessKeySecret = response.getCredentials().getAccessKeySecret();
        String securityToken = response.getCredentials().getSecurityToken();
        String bucketName = aliOSSProperties.getBucketName();

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        try {
            // 避免文件覆盖,生成带UUID的新文件名
            String originalFilename = file.getOriginalFilename();
            String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

            // 获取上传文件的输入流
            InputStream inputStream = file.getInputStream();

            // 构造上传文件请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);

            // 执行文件上传
            ossClient.putObject(putObjectRequest);

            // 生成文件的URL
            String fileUrl = "https://" + bucketName + "." + endpoint.replace("https://", "") + "/" + fileName;
            System.out.println("文件上传成功。文件URL:" + fileUrl);

            return fileUrl;

        } catch (OSSException | IOException oe) {
            System.err.println("文件上传失败:" + oe.getMessage());
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        return null;
    }
}

7.2 项目启动,自动获取临时凭证,临时凭证自动刷新


import com.aliyun.credentials.Client;
import com.aliyun.credentials.models.Config;
import com.aliyun.credentials.models.CredentialModel;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentials;
import com.aliyun.oss.common.comm.SignVersion;
import com.enjoy.entity.AliOSSProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class AliyunCredentialsUtil {
    private final AliOSSProperties aliOSSProperties;
    private CredentialsProvider credentialsProvider;

    @Autowired
    public AliyunCredentialsUtil(AliOSSProperties aliOSSProperties) {
        this.aliOSSProperties = aliOSSProperties;
        getTemporaryCredentials(); // 在构造函数中获取临时凭证
    }

    private void getTemporaryCredentials() {
        try {
            Config config = new Config();
            config.setType("ram_role_arn");
            config.setRoleArn(aliOSSProperties.getRoleArn());
            config.setAccessKeyId(aliOSSProperties.getAccessKeyId());
            config.setAccessKeySecret(aliOSSProperties.getAccessKeySecret());
            config.setRoleName(aliOSSProperties.getRoleSessionName());

            final Client credentialsClient = new Client(config);

            credentialsProvider = new CredentialsProvider() {
                @Override
                public Credentials getCredentials() {
                    CredentialModel credential = credentialsClient.getCredential();
                    return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken());
                }
                @Override
                public void setCredentials(Credentials credentials) {
                }
            };
            log.info("成功获取临时凭证" + credentialsProvider);
        } catch (Exception e) {
            log.error("获取临时凭证失败", e);
            throw new RuntimeException("无法初始化凭证提供者", e);
        }
    }


    public OSS createOSSClient() {
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(aliOSSProperties.getEndpoint())
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(aliOSSProperties.getRegion())
                .build();

        return ossClient;
    }
}

7.3 基于7.2版本实现的文件上传、下载、删除工具


import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.enjoy.entity.AliOSSProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.UUID;
@Slf4j
@Component
public class OSSUtils {

    @Autowired
    private AliOSSProperties aliOSSProperties;
    @Autowired
    private AliyunCredentialsUtil aliyunCredentialsUtil;

    public String uploadFile(MultipartFile file) {

        String bucketName = aliOSSProperties.getBucketName();
        OSS ossClient = aliyunCredentialsUtil.createOSSClient();
        String endpoint = aliOSSProperties.getEndpoint();

        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        try {
            InputStream inputStream = file.getInputStream();
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
            ossClient.putObject(putObjectRequest);
            String fileUrl = "https://" + bucketName + "." + endpoint.replace("https://", "") + "/" + fileName;
            System.out.println("文件上传成功。文件URL:" + fileUrl);

            return fileUrl;

        } catch (OSSException oe) {
            log.error("OSS异常,Error Message: {},Error Code: {},Request ID: {},Host ID: {}",
                    oe.getErrorMessage(), oe.getErrorCode(), oe.getRequestId(), oe.getHostId());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭OSSClient。
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }
    public void downloadFile(String objectName) {
        String bucketName = aliOSSProperties.getBucketName();
        OSS ossClient = aliyunCredentialsUtil.createOSSClient();
        String downloadPath = "D:\\file\\";

        try {
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            InputStream content = ossObject.getObjectContent();

            if (content != null) {
                // 创建保存文件的路径
                File downloadFile = new File(downloadPath + objectName);

                // 创建文件输出流
                FileOutputStream outputStream = new FileOutputStream(downloadFile);
                byte[] buffer = new byte[1024];
                int length;

                // 读取流内容并写入文件
                while ((length = content.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, length);
                }

                // 关闭输出流和输入流
                outputStream.close();
                content.close();

                log.info("文件下载成功,保存路径:{}", downloadFile.getAbsolutePath());
            }
        } catch (OSSException oe) {
            log.error("OSS异常,Error Message: {},Error Code: {},Request ID: {},Host ID: {}",
                    oe.getErrorMessage(), oe.getErrorCode(), oe.getRequestId(), oe.getHostId());
        } catch (ClientException ce) {
            log.error("客户端异常,Error Message: {}", ce.getMessage());
        } catch (Exception e) {
            log.error("文件下载失败", e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

8.对于不清楚操作的建议查看相关官方文档

开发参考文档

使用sts获取临时访问凭证

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值