满足你对阿里云OSS的所有幻想(手动狗头)

STS临时访问OSS

什么是STS?

阿里云STS(Security Token Service)是阿里云提供的一种临时访问权限管理服务。RAM提供RAM用户和RAM角色两种身份。其中,RAM角色不具备永久身份凭证,而只能通过STS获取可以自定义时效和访问权限的临时身份凭证,即安全令牌(STS Token)。

即,阿里云提供的一个服务。我们需要创建一个RAM角色,然后通过STS赋予这个角色一定时间的权限去操作oss。

什么又是RAM角色?

RAM角色是一种虚拟用户,可以被授予一组权限策略。与RAM用户不同,RAM角色没有确定的登录密码或访问密钥,它需要被一个可信的实体用户(RAM用户、阿里云服务或身份提供商)扮演。扮演成功后实体用户将获得RAM角色的临时身份凭证,即安全令牌(STS Token),使用安全令牌就能以RAM角色身份访问被授权的资源。

详细说明,参见官网:https://help.aliyun.com/document_detail/28756.html

OSS中的几大名词

1.Bucket

存储空间

存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。

省流:放文件的容器

2.Object

文件对象

对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一

的 Key 来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

省流:一个文件上传后就是一个文件对象(元信息+文件名+文件数据)

3.Region

地域

这个就很好理解了。表示OSS数据中心所在的位置。

region 格式一般是 oss- 国家 - 地域,比如 oss-cn-beijing ,就是代表存储的物理位置是在北京。

region在创建bucket时选择,选择离自己近的地方速度会快一些

4.EndPoint

访问域名

Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同的 Region 的时候,需要不同的域名。通过内网和外网访问同一个 Region 所需要的 Endpoint 也是不同的。例如杭州 Region 的外网Endpoint 是 oss-cn-hangzhou.aliyuncs.com,内网 Endpoint 是 oss-cn-hangzhou-internal.aliyuncs.com。具体的内容请参见各个 Region 对应的 Endpoint。

5.bucket 公网域名

指的是 bucket 和 endpoint 结合在一起,让用户访问的公网域名。完整的格式是 bucket.endpoint ,比如我的 bucket 是 xiaoming,endpoint 在杭州(oss-cnhangzhou.aliyuncs.com),那么我的 bucket 公网域名就是 xiaoming.oss-cn-hangzhou.aliyuncs.com。

6.AccessKey

访问秘钥

访问秘钥包括:AccessKeyId 和 AccessKeySecret

创建Bucket

登录阿里云—右上角控制台—进入对象存储OSS(没用过oss,可以搜索oss再进入)

image-20220426161901293

点击bucket列表(左上角)—创建:

名字-------

地域--------选离你近的

存储类型-------低频访问存储即可

读写权限-------私有

服务端加密----无

其余不管。

确定即可

如何获取STS?

下文按照官方步骤,仅配上大量图,官方:https://help.aliyun.com/document_detail/100624.htm?spm=a2c4g.11186623.0.0.5e0c50c597pv2Q#concept-xzh-nzk-2gb

步骤一:创建RAM角色
  1. 登录阿里云—>搜索框搜索访问控制—>进入产品控制台—>左侧身份管理的用户

image-20220426152059572

image-20220426152538162

  1. 创建用户

image-20220426152826435

image-20220426153055636

LTAI5tBdhZewKPL1qbsCHg1K

hLy6RYkYSe8JGpohjTcRf86LuWCOCu

步骤二:为RAM用户授予请求AssumeRole的权限
  1. 选中该用户,点击添加权限

    image-20220426153417742

  2. 搜索STS,找到AliyunSTSAssumeRoleAccess权限,点击一下就添加了

    image-20220426153616043

确定即可

步骤三:创建用于获取临时访问凭证的角色
  1. 左侧身份管理–角色–创建角色

    image-20220426153923940

  2. 选择阿里云账号,下一步

    image-20220426154027618

  3. 给角色起名,点击完成—关闭

    image-20220426154156433

  4. 点击进入刚刚创建的角色,复制其ARN,待会会用到

    image-20220426154346321

image-20220426154432427

步骤四:为角色授予上传文件的权限
  1. 左侧授权管理–授权策略–创建策略

    image-20220426154720856

  2. 选择脚本编辑(当然可视化编辑也可以,这里求简单~~)

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

​ 复制粘贴。将这两处替换为自己的(ps:上传文件时,目录不存在,oss会自动创建)

image-20220426155135646

​ 下一步

  1. 取名,确定

    image-20220426155435682

  2. 回到角色页面,点击添加权限

    image-20220426155604614

  3. 选择自定义策略,选择我们刚刚创建的策略,点击即可添加。点击确定完成

image-20220426155729692

ok,以上我们就创建好了RAM用户和角色。

下面就使用RAM用户的秘钥和角色的ARN去获取访问凭证

步骤四:获取临时访问凭证

这里是官方demo:

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.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
public class StsServiceSample {
    public static void main(String[] args) { 
        // STS接入地址,例如sts.cn-hangzhou.aliyuncs.com。       
        String endpoint = "<sts-endpoint>";
        // 填写步骤1生成的访问密钥AccessKey ID和AccessKey Secret。
        String AccessKeyId = "<yourAccessKeyId>";
        String accessKeySecret = "<yourAccessKeySecret>";
        // 填写步骤3获取的角色ARN。
        String roleArn = "<yourRoleArn>";
        // 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。        
        String roleSessionName = "<yourRoleSessionName>";
        // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket上传文件。
        // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集,即仅允许将文件上传至目标存储空间examplebucket下的exampledir目录。
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:PutObject\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:examplebucket/*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。
            String regionId = "";
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 添加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);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            //request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy); // 如果policy为空,则用户将获得该角色下所有权限。
            request.setDurationSeconds(3600L); // 设置临时访问凭证的有效时间为3600秒。
            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());
        }
    }
}

这6个需要换成我们自己的东西:

image-20220426160422468

  1. sts-endpoint(STS接入点)

    去这里查看,你所属地的sts-endpoint。比如我在成都:sts.cn-chengdu.aliyuncs.com

    https://help.aliyun.com/document_detail/371859.html

  2. AccessKeyId和AccessKeySecret就是之前保存的RAM用户的访问秘钥

  3. roleARN

    之前保存的RAM角色的ARN。如果刚刚没保存,可在角色页面,点击进入角色查看

  4. roleSessionName

    区分角色会话的,可以随便取

  5. policy

    很明显,这就是我们为角色设置的权限策略。最简单的做法就是把bucketname改为自己的。

    你也可以去权限管理–权限策略下,找到之前创建的(筛选自定义策略)策略,点击进入,复制即可。

    复制的话,我担心有些新同学犯错:

    String policy = "";   // 第一步
    String policy = "粘贴复制内容即可";  // 第二步
    

替换完成,运行main方法:

image-20220426163149939

恭喜你成功了。如果你的存在问题,去官网看看。或者私信我

image-20220426163254854

我们拿到返回的数据后,其中AccessKeyIdAccessKeySecretSecurity Token是我们后续操作需要的(比如上传文件)

需要注意的是,获取到的访问凭证过期时间:

最小900秒,最大值为RAM角色的最大会话时间(可点击角色进入即可修改最大会话时间,默认3600s)

上传文件

建议查看阿里云的文档:https://help.aliyun.com/document_detail/32016.htm?spm=a2c4g.11186623.0.0.63d23c6bsjJRAu#section-nyk-bzc-kfb

STS返回的数据主要用于:构建OSSClient实例

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

然后用ossClient即可上传文件、下载文件、删除文件。。。。。。

如何让OSS的文件链接具有过期时间

点开上面的文档链接,下面就是介绍:使用签名URL进行临时授权

// 设置签名URL过期时间,单位为毫秒。
Date expiration = new Date(new Date().getTime() + 3600 * 1000);
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);

返回给前端可以toString()一下。

这样这个链接就具有时效性了。

需要注意的是URL的过期时间最大值为32400秒。默认值为3600秒

注意点:

由于STS临时账号以及签名URL均需设置有效时长,当您使用STS临时账号生成签名URL执行相关操作(例如上传、下载文件)时,以最小的有效时长为准。例如您的STS临时账号的有效时长设置为1200秒、签名URL设置为3600秒时,当有效时长超过1200秒后,您无法使用此STS临时账号生成的签名URL上传文件。

但是,如果并不采用URL上传文件,只是用来访问文件。那么这并不是什么问题。

项目中如何封装OSS?

对于我正在写的小框架来说,我将文件单独做成一个模块,用于封装oss这些对象存储服务。

要封装oss,首先这些参数需要"可配置",将他们放在配置文件,用类读取为bean。

其次,我的做法是将ossClient的操作封装为一个OssTemplate,用于service调用。

其次,对于上传的文件(oss上的文件名(filekey)为uuid生成的随机字符串),其信息需要存入数据库。用于管理文件和crud需要。

其次,上传的文件在oss上分类存放,比如图片一个目录、视频一个目录。(比如上传的一张图片,通过后缀判定上传到image目录,将filekey—>thisisuuid改为image/thisisuuid,oss会将其识别为目录)

其次,需要使用redis,缓存STS返回的临时凭证(AccessKeyIdAccessKeySecretSecurity Token

参数配置化

这是我的配置文件

image-20220426171528758

需要一个类读取oss的配置:

/**
 * @author 29443
 * @date 2022/4/23
 */
@Data
@Component
@ConfigurationProperties(prefix = "oss")
public class OssProperties {

    /** 上传文件需要的地域节点 */
    private String endpoint;

    /** 获取sts临时访问令牌需要的地域节点 */
    private String stsEndpoint;

    private String bucketName;

    private String AccessKeyId;

    private String AccessKeySecret;

    /** 角色ARN */
    private String roleArn;

    /** 角色权限策略 */
    private String policy;

    /** 自定义角色会话名称,用于区分不同的令牌,可随便填写 */
    private String roleSessionName;

    /** 临时令牌的有效期,秒 */
    @Min(value = 900, message = "临时令牌最小过期时间为900秒")
    @Max(value =43200, message = "临时令牌最大过期时间43200秒")
    private Long stsExpireTime;

    /** 访问url的有效期,秒(默认3600s,最大32400s) */
    @Max(value = 32400, message = "url有效时间最大设置为32400秒")
    private Long urlExpireTime;
}

@ConfigurationProperties(prefix = "oss")即读取配置文件中的oss开头的内容,它必须搭配@Component向Spring容器注册

封装OSS操作

内容有点长,仔细品尝。

​ 其实主要在于,获取STS临时访问令牌,以及将返回的凭证(AccessKeyId、AccessKeySecret、Security Token)存入redis。redis过期时间和凭证过期时间相同,都是由配置文件的stsExpireTime决定。

​ 而获取的文件链接过期时间由配置文件的urlExpireTime决定。

​ 每次进行OSS的操作时,检查redis中有不有凭证信息,有就取出来构建OssClient对象,然后才能操作文件。

redis中只要AccessKeyId、AccessKeySecret、Security Token有一个不存在,就会重新获取临时凭证。然后再从redis中取,如果还是有空值,那么构建OssClient对象的时候就会抛出异常。

package com.monkeylessey.config;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
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 com.monkeylessey.constant.RedisKeyPrefixConstants;
import com.monkeylessey.domain.entity.FileInfo;
import com.monkeylessey.properties.OssProperties;
import com.monkeylessey.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author 29443
 * @date 2022/4/23
 */
@Component
@RequiredArgsConstructor
public class OssTemplate {

    private final OssProperties ossProperties;
    private final RedisUtil redisUtil;

    /**
     * STS获取令牌、AccessId、AccessKeySecret
     * @return
     */
    private void getOssToken() {
        String securityToken = "";
        // regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。
        String regionId = "cn-chengdu";
        // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
        DefaultProfile.addEndpoint(regionId, "Sts", ossProperties.getStsEndpoint());
        // 添加endpoint。适用于Java SDK 3.12.0以下版本。
        // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
        // 构造default profile。
        IClientProfile profile = DefaultProfile.getProfile(regionId,
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret());
        // 构造client。
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        // 适用于Java SDK 3.12.0及以上版本。
        request.setSysMethod(MethodType.POST);
        // 适用于Java SDK 3.12.0以下版本。
        //request.setMethod(MethodType.POST);
        request.setRoleArn(ossProperties.getRoleArn());
        request.setRoleSessionName(ossProperties.getRoleSessionName());
        request.setPolicy(ossProperties.getPolicy()); // 如果policy为空,则用户将获得该角色下所有权限。
        request.setDurationSeconds(ossProperties.getStsExpireTime()); // 设置临时访问凭证的有效时间为3600秒。
        try {
            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());
            // 获得的临时访问令牌
            securityToken = response.getCredentials().getSecurityToken();
            // RAM角色临时的AccessKeyId
            String accessKeyId = response.getCredentials().getAccessKeyId();
            // RAM角色临时的AccessKeySecret
            String accessKeySecret = response.getCredentials().getAccessKeySecret();

            redisUtil.saveForValueWithExpire(RedisKeyPrefixConstants.OSSTOKEN,
                    securityToken,
                    ossProperties.getStsExpireTime(),
                    TimeUnit.SECONDS);
            redisUtil.saveForValueWithExpire(RedisKeyPrefixConstants.OSSACCESSKEYID,
                    accessKeyId,
                    ossProperties.getStsExpireTime(),
                    TimeUnit.SECONDS);
            redisUtil.saveForValueWithExpire(RedisKeyPrefixConstants.OSSACCESSKEYSECRET,
                    accessKeySecret,
                    ossProperties.getStsExpireTime(),
                    TimeUnit.SECONDS);
        } catch (ClientException e) {
            // todo 抛出获取sts临时访问令牌的异常
            System.out.println("Failed:");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        }
    }

    /**
     * 获取oss客户端实例
     * @return
     */
    public OSS getOssClient() {
        String ossToken = "";
        String accessId = "";
        String accessSecret = "";
        ossToken = redisUtil.getValue(RedisKeyPrefixConstants.OSSTOKEN, new String());
        accessId = redisUtil.getValue(RedisKeyPrefixConstants.OSSACCESSKEYID, new String());
        accessSecret = redisUtil.getValue(RedisKeyPrefixConstants.OSSACCESSKEYSECRET, new String());
        if (StringUtils.isBlank(ossToken) || StringUtils.isBlank(accessId) || StringUtils.isBlank(accessSecret)) {
            getOssToken();
            ossToken = redisUtil.getValue(RedisKeyPrefixConstants.OSSTOKEN, new String());
            accessId = redisUtil.getValue(RedisKeyPrefixConstants.OSSACCESSKEYID, new String());
            accessSecret = redisUtil.getValue(RedisKeyPrefixConstants.OSSACCESSKEYSECRET, new String());
        }
        OSS client = new OSSClientBuilder().build(ossProperties.getEndpoint(),
                accessId,
                accessSecret,
                ossToken
        );
        return client;
    }

    /**
     * 上传文件
     * @param stream 文件输入流
     * @param info 文件信息
     */
    public void putObject(InputStream stream, FileInfo info) throws IOException {
        OSS ossClient = getOssClient();
        // 设置对象元信息
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(info.getSize());
        objectMetadata.setContentType(info.getContentType());

        ossClient.putObject(ossProperties.getBucketName(), info.getFileKey(), stream, objectMetadata);
    }

    /**
     * 获取有时效的访问链接
     * @param fileKey oss上的文件名
     */
    public String getHasExpireUrl(String fileKey) {
        OSS ossClient = getOssClient();
        // 链接过期时间和STS临时账号过期时间相同
        // url过期时间和STS临时账号过期时间,两者取最小时间
        // 例如您的STS临时账号的有效时长设置为1200秒、签名URL设置为3600秒时,当有效时长超过1200秒后,您无法使用此STS临时账号生成的签名URL上传文件
        Date expiration = new Date(System.currentTimeMillis() + ossProperties.getUrlExpireTime() * 1000);
        URL url = ossClient.generatePresignedUrl(ossProperties.getBucketName(), fileKey, expiration);
        return url.toString();
    }

    /**
     * 获取没有时效的访问链接
     * @param fileKey oss上的文件名
     */
    public String getNoExpireUrl(String fileKey) {
        OSS ossClient = getOssClient();
        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(ossProperties.getBucketName(), fileKey, HttpMethod.GET);
        URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
        return url.toString();
    }

    /**
     * 删除某个文件
     * @param fileKey oss上的文件名
     */
    public void removeObject(String fileKey) {
        OSS ossClient = getOssClient();
        ossClient.deleteObject(ossProperties.getBucketName(), fileKey);
    }

    /**
     * 获取某个文件
     * @param fileKey oss上的文件名
     * @return
     */
    public InputStream getObject(String fileKey) {
        OSS ossClient = getOssClient();
        OSSObject object = ossClient.getObject(ossProperties.getBucketName(), fileKey);
        return object.getObjectContent();
    }

}

文件格式白名单及分类

一个常量类:

/**
 * @author 29443
 * @version 1.0
 * @date 2022/4/25
 * 确定要上传的文件的目录,也可作上传白名单
 */
public class MediaConstants {

    public static List<String> IMG_SUFFIXS = Arrays.asList("jpg","png","jpeg");
    public static List<String> VIDEO_SUFFIXS = Arrays.asList("mp4","avi","rmvb","mov");
    public static List<String> RADIO_SUFFIXS = Arrays.asList("mp3","wma","wav","mpeg-4","cd","m4a");
}

判断分类(一个工具类):

/**
 * @author 29443
 * @version 1.0
 * @date 2022/4/25
 */
public class FileUtil {

    /**
     * 获取文件后缀
     * @param fileName
     * @return
     */
    public static String getSuffix(String fileName) {
        String suffix = fileName.substring(fileName.lastIndexOf('.') + 1);
        return suffix;
    }

    /**
     * 获取该文件上传到oss哪个目录
     * @param suffix 文件后缀
     * @return
     */
    public static String getFileType(String suffix) {
        String fileType = "";
        if (MediaConstants.IMG_SUFFIXS.contains(suffix)) {
            fileType = FileTypeEnum.IMAGE.getType();
        }
        else if (MediaConstants.VIDEO_SUFFIXS.contains(suffix)) {
            fileType = FileTypeEnum.VIDEO.getType();
        }
        else if (MediaConstants.RADIO_SUFFIXS.contains(suffix)) {
            fileType = FileTypeEnum.RADIO.getType();
        }
        if (StringUtils.isBlank(fileType)) {
            throw new FileFormatNotSupport("文件格式" + suffix + "不支持", HttpStatusConstants.ERROR);
        }
        return fileType;
    }

    /**
     * 获取文件的信息
     * @param file
     * @return
     */
    public static FileInfo getFileInfo(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        String random = UUID.randomUUID().toString();
        String suffix = getSuffix(originalFilename);
        String fileType = getFileType(suffix);
        String fileKey = fileType + "/" + random;

        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileKey(fileKey);
        fileInfo.setContentType(file.getContentType());
        fileInfo.setSize(file.getSize());

        return fileInfo;
    }

}

FileInfo类:(用于将文件信息存入数据库)

@Data
@TableName("sys_file")
@ApiModel(value = "文件对象", description = "文件对象")
public class FileInfo {

    @TableId(value = "id", type = IdType.AUTO)
    private String id;

    @ApiModelProperty("oss文件名")
    @TableField("file_key")
    private String fileKey;

    @ApiModelProperty("文件格式")
    @TableField("content_type")
    private String contentType;

    @ApiModelProperty("文件大小")
    @TableField("size")
    private Long size;

    @ApiModelProperty("文件原始名")
    @TableField("original_filename")
    private String originalFilename;

    @ApiModelProperty("创建时间")
    @TableField(value = "gmt_create", fill = FieldFill.INSERT)
    private LocalDateTime gmtCreate;

    @ApiModelProperty("更新时间")
    @TableField(value = "gmt_update", fill = FieldFill.UPDATE)
    private LocalDateTime gmtUpdate;

    @TableField("is_deleted")
    private Integer isDeleted;

}
service层调用OssTemplate完成文件操作

这里就是controller调用service的操作。

我这里就放一个上传文件的demo吧:

Controller:

/**
 * 多文件上传
 * @param files
 * @return
 */
@PostMapping("/upload")
public ResponseData uploads(@RequestPart("files") @NotEmpty List<MultipartFile> files) {
    return ossFileService.putObjects(files);
}

Service:

@Override
@Transactional(rollbackFor = Exception.class)
public ResponseData putObjects(List<MultipartFile> fileList) {
    int successCount = 0;
    int fileNumber = fileList.size();
    List<String> urls = new ArrayList();
    for (MultipartFile file : fileList) {
        FileInfo fileInfo = FileUtil.getFileInfo(file);
        try {
            ossTemplate.putObject(file.getInputStream(), fileInfo);
            fileMapper.insert(fileInfo);
            urls.add(ossTemplate.getHasExpireUrl(fileInfo.getFileKey()));
            successCount++;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    String msg = String.format("上传文件总数:'{}',成功'{}'个,失败'{}'个",
                               fileNumber,
                               successCount,
                               fileNumber-successCount);
    return ResponseData.success(msg, urls);
}

至此,完毕。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了我的架构师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值