需求背景

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

在众多项目组的千呼万唤之下,阿里云的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. HDU5919 Sequence2

    传送门 这道题是主席树好题啊-- 题目大意:给定一个序列,每次给定一段区间,区间内所有不同的数第一次出现的位置排成一个序列,求这个序列的中位数. 其实求中位数并不是很难,只要我们能把这个序列中不同的数 ...

  2. 洛谷P4009汽车加油行驶问题——网络流24题(最短路)

    题目:https://www.luogu.org/problemnew/show/P4009 网络流24题中不是网络流的最短路题: 把每个点拆成各个油量上的点,根据要求连边即可: 注意:点数最大为10 ...

  3. MVC错误:查询的结果不能枚举多次

    应用程序中的服务器错误. 查询的结果不能枚举多次. 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: S ...

  4. bzoj3676

    后缀自动机+manacher 听说本质不同的回文串只有O(n)个 那么用manacher求出所有回文串,然后在sam上查找出现了几次就行了 sam的性质又忘了... manacher也忘了... #i ...

  5. 注销ie中的ActiveX插件

    最新在C#下开发ActiveX控件,遇到一个问题,就是在调试的时候,ActiveX就已经注册在了调试目录下,这样即使安装这个插件,也无法注册到ActiveX的安装目录下.为了解决这个问题,需要注销下调 ...

  6. office2007下载地址

    thunder://QUFodHRwOi8vNDYuZHVvdGUub3JnOjgwODAvb2ZmaWNlMjAwN3Byby56aXBaWg==thunder://QUFodHRwOi8vNTEu ...

  7. silverlight RadGridView 动态添加数据列

    public void BindFaultGridInfo(IList<HealthStatusApp.Web.Models.FaultMajorModel> list) { rg_Fau ...

  8. dubbo 自定义过滤器,打印接口调用信息

    dubbo提供了web filter类似的com.alibaba.dubbo.rpc.Filter,这样,我们可以在dubbo提供的服务提供方和消费方都可以自定义过滤 器,从而可以获得方法调用的时间或 ...

  9. 运用Eclipse的Working Set,界面清爽多了

    使用Eclipse的Working Set,界面清爽多了 想必大家的Eclipse里也会有这么多得工程...... 每次工作使用到的项目肯定不会太多...... 每次从这么大数量的工程当中找到自己要使 ...

  10. Numbers Exchange

    题意: Eugeny有n张卡片,他希望和Nikolay交换一些卡片使得他拥有的奇数数字和偶数数字的卡片数目一样,且所有数字都不同. Nikolay有m张卡片,分别写着1到m.问最少交换几次,能够满足要 ...