栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

阿里云OSS文件上传下载,拿来即用,建议收藏

Java 更新时间:发布时间: 百科书网 趣学号
什么是OSS

我们可以理解为就是一个资源服务器,在这之前我也尝试过Nginx当静态资源服务器,但效果比较一般,为什么选择阿里云OSS,只是因为最近刚好公司用到了,所以就接入了,还有其他的比如七牛云,腾讯云等等。

创建 Bucket

Bucket 就是存储空间,我们的文件放在那里。具体操作如下:

1、点击进入阿里云OSS,在 Bucket 列表创建自己的存储空间。

2、填写空间名,选择地域节点等操作。

我们的存储空间创建好了,下一步就是集成到我们的项目当中。

项目集成

在阿里云的官方文档中提供了不同语言SDK示例,可自行参考。

场景

在操作之前,先讲一讲我使用的场景。

在我负责的模块需要提供一个上传文件的服务,从消息队列中去读取数据,然后把数据转为 excel 文件在上传到 oss 中去,并返回一个文件的路径。当然,不只是上传 excel ,任何文件都可以。

maven 依赖

首先是 oss 的依赖,我用的是官方文档中提供的版本:


	com.aliyun.oss
	aliyun-sdk-oss
	3.10.2

因为涉及到 excel 的生成,我直接使用开源的 easypoi,对于 poi 操作有一大堆开源的,如果不是需要定制开发,我一般都是用开源的,还有阿里的 easyexcel 也是不错的。


	cn.afterturn
	easypoi-base
	4.1.0


	cn.afterturn
	easypoi-web
	4.1.0


	cn.afterturn
	easypoi-annotation
	4.1.0

还用到了一个工具类Hutool,Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率。你想要的他都有。


	cn.hutool
	hutool-all
	5.7.13

工具类

1、根据官方提供的文档封装的工具类。

再此之前你需要获得这几项配置:

  • endpoint,地域节点
  • accessKeyId,秘钥Id
  • accessKeySecret,秘钥
  • bucketName,存储空间名称
  • url,Bucket域名(存储空间名称和地域节点的组合)
import cn.hutool.core.date.DateUtil;
import com.fanryes.vanadium.cloud.exception.OssFileException;
import org.apache.commons.lang3.StringUtils;

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


public class AliyunOssApiClient {
    
    private String endpoint = "你的endpoint";
    
    private String accessKeyId = "你的accessKeyId";
    
    private String accessKeySecret = "你的accessKeySecret";
    
    private String url = "你的Bucket 域名";
    
    private String bucketName = "你的Bucket名称";

	
    private OssApi ossApi;

    
    public AliyunOssApiClient init() {
        ossApi = new OssApi(this.endpoint, this.accessKeyId, this.accessKeySecret);
        this.url = url;
        this.bucketName = bucketName;
        return this;
    }

    
    public String uploadFileExpired(InputStream is, String pathPrefix, String suffix) {
        String prefix = pathPrefix.endsWith("/") ? pathPrefix : pathPrefix + "/";
        String fileName = prefix + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + suffix;
        this.check();
        try {
            return ossApi.uploadFileExpired(is, fileName, bucketName);
        } catch (Exception e) {
            throw new OssFileException("文件上传失败:" + e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    
    public String uploadFile(InputStream is, String pathPrefix, String suffix) {
        String prefix = pathPrefix.endsWith("/") ? pathPrefix : pathPrefix + "/";
        String fileName = prefix + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + suffix;
        this.check();
        try {
            return ossApi.uploadFile(is, fileName, bucketName, endpoint);
        } catch (Exception e) {
            throw new OssFileException("文件上传失败:" + e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    
    public void downloadLocalFile(String fileName, String path) {
        this.check();
        try {
            ossApi.downloadLocalFile(fileName, path, bucketName);
        } catch (Exception e) {
            throw new OssFileException("文件下载失败:" + e.getMessage());
        }
    }


    
    public boolean removeFile(String path) {
        this.check();
        if (StringUtils.isEmpty(path)) {
            throw new OssFileException("删除文件失败:文件key为空");
        }

        try {
            this.ossApi.deleteFile(path, bucketName);
            return true;
        } catch (Exception e) {
            throw new OssFileException(e.getMessage());
        }
    }

    
    public void check() {
        if (null == ossApi) {
            throw new OssFileException("尚未配置阿里云OSS,文件上传功能暂时不可用!");
        }
    }
}

2、由于我这里还有其他操作,所以把它的操作和实际业务操作分开了,单独提供了一个Api。

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.ListObjectsRequest;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.ObjectPermission;
import com.aliyun.oss.model.StorageClass;
import com.fanryes.vanadium.cloud.domain.ObjectsRequest;
import com.fanryes.vanadium.cloud.exception.OssFileException;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.List;


public class OssApi {
    private OSSClient client;

    public OssApi(OSSClient client) {
        this.client = client;
    }

    public OssApi(String endpoint, String accessKeyId, String accessKeySecret) {
        this.client = new OSSClient(endpoint, accessKeyId, accessKeySecret);
    }

    
    public String authFile(String fileName, String bucketName, long expirationTime) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法授权访问文件的URL!Bucket不存在:" + bucketName);
            }
            if (!this.client.doesObjectExist(bucketName, fileName)) {
                throw new OssFileException("[阿里云OSS] 文件授权失败!文件不存在:" + bucketName + "/" + fileName);
            }
            // 设置URL过期时间为1小时
            Date expiration = new Date(new Date().getTime() + expirationTime * 1000);
            // 生成URL
            return this.client.generatePresignedUrl(bucketName, fileName, expiration).toString();
        } finally {
            this.shutdown();
        }
    }

    
    public boolean isExistFile(String fileName, String bucketName) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] Bucket不存在:" + bucketName);
            }
            return this.client.doesObjectExist(bucketName, fileName);
        } finally {
            this.shutdown();
        }
    }

    
    public ObjectPermission getFileAcl(String fileName, String bucketName) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法获取文件的访问权限!Bucket不存在:" + bucketName);
            }
            if (!this.client.doesObjectExist(bucketName, fileName)) {
                throw new OssFileException("[阿里云OSS] 无法获取文件的访问权限!文件不存在:" + bucketName + "/" + fileName);
            }
            return this.client.getObjectAcl(bucketName, fileName).getPermission();
        } finally {
            this.shutdown();
        }
    }

    
    public List listFile(String bucketName, ObjectsRequest request) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法获取文件列表!Bucket不存在:" + bucketName);
            }
            ListObjectsRequest listRequest = new ListObjectsRequest(bucketName);
            if (null != request) {
                listRequest.withDelimiter(request.getDelimiter())
                        .withEncodingType(request.getEncodingType())
                        .withMarker(request.getMarker())
                        .withMaxKeys(request.getMaxKeys())
                        .withPrefix(request.getPrefix());
            }
            // 列举Object
            ObjectListing objectListing = this.client.listObjects(listRequest);
            return objectListing.getObjectSummaries();
        } finally {
            this.shutdown();
        }
    }

    
    public void setFileAcl(String fileName, String bucketName, CannedAccessControlList acl) {
        try {
            boolean exists = this.client.doesBucketExist(bucketName);
            if (!exists) {
                throw new OssFileException("[阿里云OSS] 无法修改文件的访问权限!Bucket不存在:" + bucketName);
            }
            if (!this.client.doesObjectExist(bucketName, fileName)) {
                throw new OssFileException("[阿里云OSS] 无法修改文件的访问权限!文件不存在:" + bucketName + "/" + fileName);
            }
            this.client.setObjectAcl(bucketName, fileName, acl);
        } finally {
            this.shutdown();
        }
    }

    
    public void deleteFile(String fileName, String bucketName) {
        try {
            boolean exists = this.client.doesBucketExist(bucketName);
            if (!exists) {
                throw new OssFileException("[阿里云OSS] 文件删除失败!Bucket不存在:" + bucketName);
            }
            if (!this.client.doesObjectExist(bucketName, fileName)) {
                throw new OssFileException("[阿里云OSS] 文件删除失败!文件不存在:" + bucketName + "/" + fileName);
            }
            this.client.deleteObject(bucketName, fileName);
        } finally {
            this.shutdown();
        }
    }

    
    public void createBucket(String bucketName) {
        try {
            boolean exists = this.client.doesBucketExist(bucketName);
            if (exists) {
                throw new OssFileException("[阿里云OSS] Bucket创建失败!Bucket名称[" + bucketName + "]已被使用!");
            }
            // -- 创建指定类型的Bucket,请使用Java SDK 2.6.0及以上版本。
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            // 设置bucket权限为公共读,默认是私有读写
            createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            // 设置bucket存储类型为低频访问类型,默认是标准类型
            createBucketRequest.setStorageClass(StorageClass.IA);
            this.client.createBucket(createBucketRequest);
        } finally {
            this.shutdown();
        }
    }


    
    public void createFolder(String folder, String bucketName) throws OssFileException {
        try {
            if (null == bucketName) {
                throw new OssFileException("[阿里云OSS] 尚未指定Bucket!");
            }

            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法创建目录!Bucket不存在:" + bucketName);
            }
            folder = folder.endsWith("/") ? folder : folder + "/";
            this.client.putObject(bucketName, folder, new ByteArrayInputStream(new byte[0]));
        } finally {
            this.shutdown();
        }
    }

    
    public String uploadFileExpired(InputStream inputStream, String fileName, String bucketName) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法上传文件!Bucket不存在:" + bucketName);
            }
            //上传文件
            this.client.putObject(bucketName, fileName, inputStream);
            //给文件授权,包含过期时间
            return this.authFile(fileName, bucketName, 1000);
        } finally {
            this.shutdown();
        }
    }

    
    public String uploadFile(InputStream inputStream, String fileName, String bucketName, String endpoint) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法上传文件!Bucket不存在:" + bucketName);
            }
            //上传文件
            this.client.putObject(bucketName, fileName, inputStream);
            return "https://" + bucketName + "." + endpoint + "/" + fileName;
        } finally {
            this.shutdown();
        }
    }

    
    public void downloadLocalFile(String fileName, String path, String bucketName) {
        try {
            if (!this.client.doesBucketExist(bucketName)) {
                throw new OssFileException("[阿里云OSS] 无法上传文件!Bucket不存在:" + bucketName);
            }
            // 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
            // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            this.client.getObject(new GetObjectRequest(bucketName, fileName), new File(path));
        } finally {
            this.shutdown();
        }
    }

    private void shutdown() {
        this.client.shutdown();
    }
}

3、由于我们自定义了Api,所以提供一个自定义的异常。

public class OssFileException extends RuntimeException {
    public OssFileException(String message) {
        super(message);
    }

    public OssFileException(String message, Throwable cause) {
        super(message, cause);
    }
}

4、因为需要把业务数据转为一个excel,但实际上我们在把数据转为 Workbook 的时候只需要获取到流就行了,所以需要把生成的 excel 转为流。

public class ExcelUtils {

    
    public static InputStream workbookConvertorStream(Workbook workbook) {
        InputStream in = null;
        try {
            //临时缓冲区
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            //创建临时文件
            workbook.write(out);
            byte[] bookByteAry = out.toByteArray();
            in = new ByteArrayInputStream(bookByteAry);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return in;
    }
}
测试

这里准备一个虚假数据来测试。

实体类:

import cn.afterturn.easypoi.excel.annotation.Excel;

import java.io.Serializable;
import java.util.Date;

public class StudentEntity implements Serializable {
    
    private String id;
    
    @Excel(name = "学生姓名", height = 20, width = 30, isimportField = "true_st")
    private String name;
    
    @Excel(name = "学生性别", replace = {"男_1", "女_2"}, suffix = "生", isimportField = "true_st")
    private int sex;

    @Excel(name = "出生日期", databaseFormat = "yyyyMMddHHmmss", format = "yyyy-MM-dd", isimportField = "true_st", width = 20)
    private Date birthday;

    @Excel(name = "进校日期", databaseFormat = "yyyyMMddHHmmss", format = "yyyy-MM-dd")
    private Date registrationDate;

    public StudentEntity() {
    }

    public StudentEntity(String id, String name, int sex, Date birthday, Date registrationDate) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.registrationDate = registrationDate;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Date getRegistrationDate() {
        return registrationDate;
    }

    public void setRegistrationDate(Date registrationDate) {
        this.registrationDate = registrationDate;
    }
}

测试类:

public class TeatClient {

    public static void main(String[] args) {
        //模拟数据
        List list = new ArrayList<>();
        list.add(new StudentEntity("1", "张三", 18, new Date(), new Date()));
        list.add(new StudentEntity("2", "李四", 19, new Date(), new Date()));
        list.add(new StudentEntity("3", "王五", 20, new Date(), new Date()));
        //HSSF_.xls, XSSF_.xlsx;
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生", "学生", "HSSF"), StudentEntity.class, list);
        InputStream inputStream = ExcelUtils.workbookConvertorStream(workbook);
        AliyunOssApiClient client = new AliyunOssApiClient().init();
        String url = client.uploadFile(inputStream, SocialInsuranceAction.REGISTRATION.name().toLowerCase(), ".xls");
        System.out.println(url);
    }
}

测试结果:

返回一个文件连接,并且在阿里云控制台也能看到生成的文件。

https://wyh1995.oss-cn-hangzhou.aliyuncs.com/registration/20210926193659754.xls

注意事项

在实际操作过程中,你可以按照自己需求去实现自己的工具类,主要参考OssApi这个类,这里讲讲提供的uploadFileExpired和uploadFile方法,其他的可自行查看,都有注释。

1、uploadFileExpired返回的是一个有过期时间的连接,并且是有权限才能访问的,在控制台详情可以看到:

其主要是通过OSSClient的授权方法实现的:

public String authFile(String fileName, String bucketName, long expirationTime) {
    try {
        if (!this.client.doesBucketExist(bucketName)) {
            throw new OssApiException("[阿里云OSS] 无法授权访问文件的URL!Bucket不存在:" + bucketName);
        }
        if (!this.client.doesObjectExist(bucketName, fileName)) {
            throw new OssApiException("[阿里云OSS] 文件授权失败!文件不存在:" + bucketName + "/" + fileName);
        }
        // 设置URL过期时间为1小时
        Date expiration = new Date(new Date().getTime() + expirationTime * 1000);
        // 生成URL
        return this.client.generatePresignedUrl(bucketName, fileName, expiration).toString();
    } finally {
        this.shutdown();
    }
}

2、uploadFile返回的是没有过期时间的连接,并且是开放权限的,任何人都可以访问,前提是你需要开启 Bucket权限:

如果你在没有开启的情况下调用该方法,结果可能就是这样:

还有一个需要注意的是,上面每个方法执行完成之后都是把OSSClient给关闭了,即调用了OssClient.shutdown(),相当于连接关闭,所以你不能连续的执行不同方法,除非你在shutdown之前,不然会出现以下情况。

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/273600.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号