需求背景

目前公司内部项目所支持的文件云存储方式还是公司内部项目组提供的方案,但在时间的考验之下,弊端显现,尤其是灾备切换过程中需要切换访问地址,这种操作不方便,更可能因为中间过程的失误导致资源不可用,而且这种操作也会带来资源可用的延时,仔细斟酌发现这种操作似乎并不合逻辑。

在众多项目组的千呼万唤之下,阿里云的OSS存储方案进入了我们的视线,依托公共云环境,屏蔽项目本身切换状态可能带来的资源不可用的问题,将资源存储与访问独立出来,极大的与企业自有项目解耦,同时降低企业自身项目运行状态对公共资源访问的影响。

项目接入

Captain的本项目基于JDK1.8,采用SpringBoot框架开发。

前期准备

从阿里云平台获取到endpoint、accessKeyId、accessKeySecret相关配置信息,因为只有在这些信息的支持下,才能展开后续功能的开发。

创建bucket(存储命名空间、平台唯一才行),可以在阿里云操作台建立,也可以通过代码生成。

Maven依赖

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

属性配置

可以将和环境相关的固定配置类信息放置于properties文件中:

# aliyun oss
aliyun.oss.endpoint="http://oss-cn-hangzhou.aliyuncs.com"
aliyun.oss.keyid=<yourAccessKeyId>
aliyun.oss.keysecret=<yourAccessKeySecret>
aliyun.oss.bucketname=<yourBucketName> # aliyun filehost based on dev/test/prod(tha/idn)
aliyun.oss.filehost=dev

编写工具类

 /**
* @Project: captain-supply-chain
* @PackageName: com.captain.supply-chain.common.file
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @DateTime: 2019/5/10 18:12.
* @Description: Upload file to Aliyun OSS.
*/
@Slf4j
@Component
public class AliyunOssService { /**
* 斜杠
*/
private final String FLAG_SLANTING_ROD = "/";
/**
* http://
*/
private final String FLAG_HTTP = "http://";
/**
* https://
*/
private final String FLAG_HTTPS = "https://";
/**
* 空字符串
*/
private final String FLAG_EMPTY_STRING = "";
/**
* 点号
*/
private final String FLAG_DOT = ".";
/**
* 横杠
*/
private final String FLAG_CROSSBAR = "-"; /**
* 缺省的最大上传文件大小:20M
*/
private final int DEFAULT_MAXIMUM_FILE_SIZE = 20; /**
* endpoint
*/
@Value("${aliyun.oss.endpoint}")
private String endpoint; /**
* access key id
*/
@Value("${aliyun.oss.keyid}")
private String accessKeyId; /**
* access key secret
*/
@Value("${aliyun.oss.keysecret}")
private String accessKeySecret; /**
* bucket name (namespace)
*/
@Value("${aliyun.oss.bucketname}")
private String bucketName; /**
* file host (dev/test/prod)
*/
@Value("${aliyun.oss.filehost}")
private String fileHost; @Autowired
protected GetSetCacheService getSetCacheService; /**
* 以文件流的方式上传文件
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param fileName 文件名称
* @param filePath 文件路径
* @param inputStream 文件输入流
* @return
*/
public String uploadFile(String fileName, String filePath, InputStream inputStream) {
return coreUpload(fileName, filePath, inputStream);
} /**
* 核心上传功能
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param fileName 文件名
* @param filePath 文件路径
* @param inputStream 文件输入流
* @return
*/
private String coreUpload(String fileName, String filePath, InputStream inputStream) {
log.info("Start to upload file....");
if(StringUtils.isEmpty(fileName) || inputStream == null) {
log.error("Filename Or inputStream is lack when upload file.");
return null;
}
if(StringUtils.isEmpty(filePath)) {
log.warn("File path is lack when upload file but we automatically generated");
String dateCategory = DateUtil.getFormatDate(new Date(), "yyyyMMdd");
filePath = FLAG_SLANTING_ROD.concat(dateCategory).concat(FLAG_SLANTING_ROD);
}
String fileUrl;
OSSClient ossClient = null;
try{ // If the upload file size exceeds the limit
long maxSizeAllowed = getMaximumFileSizeAllowed();
if(Long.valueOf(inputStream.available()) > maxSizeAllowed) {
log.error("Uploaded file is too big.");
return null;
} // Create OSS instance
ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); // Create bucket if not exists
if (!ossClient.doesBucketExist(bucketName)) {
log.info("Bucket '{}' is not exists and create it now.", bucketName);
ossClient.createBucket(bucketName);
CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
ossClient.createBucket(createBucketRequest);
} /*********************************/
// List the bucket in my account
//listBuckets(ossClient);
/*********************************/ // File path format
if(!filePath.startsWith(FLAG_SLANTING_ROD)) {
filePath = FLAG_SLANTING_ROD.concat(filePath);
}
if(!filePath.endsWith(FLAG_SLANTING_ROD)) {
filePath = filePath.concat(FLAG_SLANTING_ROD);
} // File url
StringBuilder buffer = new StringBuilder();
buffer.append(fileHost).append(filePath).append(fileName);
fileUrl = buffer.toString();
log.info("After format the file url is {}", fileUrl); // Upload file and set ACL
PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, fileUrl, inputStream));
ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
if(result != null) {
log.info("Upload result:{}", result.getETag());
log.info("Upload file {} successfully.", fileName);
}
fileUrl = getHostUrl().concat(fileUrl);
log.info("Call path is {}", fileUrl); /***********************************/
// List objects in your bucket
//listObjects(ossClient);
/***********************************/ }catch (Exception e){
log.error("Upload file failed.", e);
fileUrl = null;
}finally {
if(ossClient != null) {
ossClient.shutdown();
}
}
return fileUrl;
} /**
* 列出buckets下的所有文件
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param ossClient
*/
private void listObjects(OSSClient ossClient) {
System.out.println("Listing objects");
ObjectListing objectListing = ossClient.listObjects(bucketName);
for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
System.out.println(" - " + objectSummary.getKey() + " " +
"(size = " + objectSummary.getSize() + ")");
}
System.out.println();
} /**
* 列出当前用户下的所有bucket
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param ossClient
*/
private void listBuckets(OSSClient ossClient) {
System.out.println("Listing buckets");
ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
listBucketsRequest.setMaxKeys(500);
for (Bucket bucket : ossClient.listBuckets()) {
System.out.println(" - " + bucket.getName());
}
System.out.println();
} /**
* 以文件的形式上传文件
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param fileName
* @param filePath
* @param file
* @return
*/
public String uploadFile(String fileName, String filePath, File file) {
if(file == null) {
log.warn("File is lack when upload.");
return null;
}
if(StringUtils.isEmpty(fileName)) {
log.warn("File name is lack when upload file but we automatically generated");
String uuidFileName = UUID.randomUUID().toString().replace(FLAG_CROSSBAR, FLAG_EMPTY_STRING);
String fname = file.getName();
String suffix = fname.substring(fname.lastIndexOf(FLAG_DOT), fname.length());
fileName = uuidFileName.concat(suffix);
}
InputStream inputStream = null;
String fileUrl = null;
try{
inputStream = new FileInputStream(file);
fileUrl = uploadFile(fileName, filePath, inputStream);
}catch (Exception e){
log.error("Upload file error.", e);
}finally {
IOUtils.safeClose(inputStream);
}
return fileUrl;
} /**
* 获取访问的base地址
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @return
*/
private String getHostUrl() {
String hostUrl = null;
if(this.endpoint.startsWith(FLAG_HTTP)) {
hostUrl = FLAG_HTTP.concat(this.bucketName).concat(FLAG_DOT)
.concat(this.endpoint.replace(FLAG_HTTP, FLAG_EMPTY_STRING)).concat(FLAG_SLANTING_ROD);
} else if (this.endpoint.startsWith(FLAG_HTTPS)) {
return FLAG_HTTPS.concat(this.bucketName).concat(FLAG_DOT)
.concat(this.endpoint.replace(FLAG_HTTPS, FLAG_EMPTY_STRING)).concat(FLAG_SLANTING_ROD);
}
return hostUrl;
} /**
* 获取最大允许上传文件的大小
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @return
*/
private long getMaximumFileSizeAllowed() {
// 缓存单位是M
String maxConfigVal = getSetCacheService.getConfigValue("upload_maximum_file_size");
if(StringUtils.isEmpty(maxConfigVal)) {
return DEFAULT_MAXIMUM_FILE_SIZE * 1024L * 1024L;
}else {
return Long.valueOf(maxConfigVal.trim()) * 1024L * 1024L;
}
} /**
* 删除文件
* @Author: Captain&D
* @cnblogs: https://www.cnblogs.com/captainad
* @param fileUrl 文件访问的全路径
*/
public void deleteFile(String fileUrl) {
log.info("Start to delete file from OSS.{}", fileUrl);
if(StringUtils.isEmpty(fileUrl)
|| (!fileUrl.startsWith(FLAG_HTTP)
&& !fileUrl.startsWith(FLAG_HTTPS))) {
log.error("Delete file failed because the invalid file address. -> {}", fileUrl);
return;
}
OSSClient ossClient = null;
try{
/**
* http:// bucketname dev/test/pic/abc.jpg = key
* http:// captainad.oss-ap-southeast-1.aliyuncs.com/dev/test/pic/abc.jpg
*/
String key = fileUrl.replace(getHostUrl(), FLAG_EMPTY_STRING);
if(log.isDebugEnabled()) {
log.debug("Delete file key is {}", key);
}
ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
ossClient.deleteObject(bucketName, key);
}catch (Exception e){
log.error("Delete file error.", e);
} finally {
if(ossClient != null) {
ossClient.shutdown();
}
}
} }

参考资料

1、https://help.aliyun.com/document_detail/32008.html

Java项目接入阿里云OSS存储的更多相关文章

  1. php将图片存储在阿里云oss存储上

    创建两个方法 1.上传方法 use OSS\OssClient; use think\Config; use OSS\Core\OssException; /** * 存储文件 * * @param ...

  2. 备份MySQL数据库并上传到阿里云OSS存储

    1. 环境配置 要将本地文件上传到阿里云oss中, 必须使用阿里云提供的工具 ossutil, 有32位,也有64位的, Linux和Windows都有.具体可以到阿里云官网下载 官网及文档: htt ...

  3. 前端(react)上传到阿里云OSS存储 实例

    需求背景 由于现有的后台管理系统,上传的视频越来越大,加上上传视频较慢,后端小哥提出直接从前端上传视频或者其他文件到阿里云OSS存储. 阿里云OSS 阿里云OSS文档介绍,这里不做过多赘述 安装 原本 ...

  4. java开发之阿里云对象存储OSS和云数据库Memcache的使用

    web开发中标配:aliyun ECS(阿里云服务器),aliyun RDS(阿里云数据库),aliyun OSS(阿里云对象存储),aliyun Memcache(阿里云缓存数据库). 今天就介绍下 ...

  5. Springboot项目之阿里云OSS快速入门

    阿里云oss 阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云对外提供的海量.安全.低成本.高可靠的云存储服务.您可以通过本文档提供的简单的REST接口,在任何 ...

  6. 谷粒 | 10 | 阿里云OSS存储对象服务

    阿里云OSS对象存储服务 准备工作 1.在service模块新建子模块service_oss 2.引入pom.xml文件中引入oss服务依赖 <dependencies> <!--a ...

  7. Laravel 使用阿里云 oss 存储对象

    一.下载安装 composer require jacobcyl/ali-oss-storage 二.注册服务提供者 在config/app.php的providers下添加: //阿里云OSS对象存 ...

  8. 阿里云OSS存储开发(一)

    Step 1. 初始化一个OSSClient OSSClient是与OSS服务交互的客户端,SDK的OSS操作都是通过OSSClient完成的. 下面代码新建了一个OSSClient: using A ...

  9. 阿里云OSS存储

    1.accessKeyId 与 accessKeySecret 是由系统分配给用户的,称为ID对,用于标识用户,为访问OSS做签名验证. 2.Bucket是OSS上的命名空间,相当于数据的容器,可以存 ...

随机推荐

  1. 修改SO

    1.如果在jni中定义的是int型的数据,比如: JNIEXPORT jint JNICALL Java_com_ggndktest1_JniGg_getCoin (JNIEnv * env, job ...

  2. Spring 事务管理高级应用难点剖析: 第 1 部分

    Spring 的事务管理是被使用得最多的功能之一,虽然 Spring 事务管理已经帮助程序员将要做的事情减到了最小.但在实际开发中,如果使用不当,依然会造成数据连接泄漏等问题.本系列以实际应用中所碰到 ...

  3. [HAOI 2012] Road

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2750 [算法] 考虑计算每个点对每条边的贡献 对于每个点首先运行SPFA或Dijks ...

  4. C++之remove和remove_if

    一.Remove()函数 remove(beg,end,const T& value) //移除区间{beg,end)中每一个“与value相等”的元素: remove只是通过迭代器的指针向前 ...

  5. CSS:CSS cursor 属性

    ylbtech-CSS:CSS cursor 属性 1.返回顶部 1. 实例 一些不同的光标: span.crosshair {cursor:crosshair;} span.help {cursor ...

  6. 使用基于Caffe的MobileNet分类踩坑备忘录

    首先要帮Caffe甩个锅:Caffe对图像处理进行了很高明的封装,以protobuffer形式组织的搭积木式的网络构建也很灵活方便,这里的坑都是自己腿不好,走路不稳崴进去的. 1. Caffe的一个i ...

  7. 1.11-1.12 Sqoop导入数据时两种增量方式导入及direct

    一.增量数据的导入 1.两种方式 ## query 有一个唯一标识符,通常这个表都有一个字段,类似于插入时间createtime where createtime => 201509240000 ...

  8. UVa 1660 Cable TV Network (最大流,最小割)

    题意:求一个无向图的点连通度. 析:把每个点拆成两个,然后中间连接一个容量为1的边,然后固定一个源点,枚举每个汇点,最小割. 代码如下: #pragma comment(linker, "/ ...

  9. JS 表单自动提交

    一.前言 在做项目中,将有些容易忘记的代码进行汇总. 二.案例 表单提交,如一个页面的搜索. 表单的代码 <form class="search-form" id=" ...

  10. Cookie和Session(3)

    关于Cookie和Session Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力. 1)cookie 是一种发送到客户浏 ...