OSS对象存储
阿里云提供针对各种存储资源(块、文件和对象)的低成本、高可靠、高可用的存储服务,涵盖数据备份、归档、容灾等场景。本文介绍阿里云各类存储服务及特性的适用场景、性能、安全、接口和费用模型等,帮助您选择最适合您业务场景和需求的云存储服务。
OSS适用于以下场景
静态网站内容和音视频的存储与分发
每个存储在OSS上的文件(Object)都有唯一的HTTP URL地址,用于内容分发。同时,OSS还可以作为内容分发网络(CDN)的源站。由于无需分区,OSS尤其适用于托管那些数据密集型、用户生产内容的网站,如图片和视频分享网站。各种终端设备、Web网站程序、移动应用可以直接向OSS写入或读取数据。OSS支持流式写入和文件写入两种方式。
静态网站托管
作为低成本、高可用、高扩展性的解决方案,OSS可用于存储静态HTML文件、图片、视频、JavaScript等类型的客户端脚本。
计算和分析的数据存储仓库
OSS的水平扩展性使您可以同时从多个计算节点访问数据而不受单个节点的限制。
数据备份和归档
OSS为重要数据的备份和归档提供高可用、可扩展、安全可靠的解决方案。您可以通过设置生命周期规则将存储在OSS上的冷数据自动转储为低频或者归档存储类型以节约存储成本。您还可以使用跨区域复制功能在不同地域的不同存储空间之间自动异步(近实时)复制数据,实现业务的跨区域容灾。
实现OSS对象存储的
pom.xml 引入依赖
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>3.10.2version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.9version>
dependency>
application 自定义配置信息
#application.yml配置
spring:
profiles:
active: dev
servlet:
multipart:
max-file-size: 40MB
max-request-size: 100MB
#application-dev.yml 配置
spring:
application:
name: tuan
alibaba:
cloud:
#阿里云相关服务配置,用的账号:id和密钥
aliyun:
secret-id: xxxx
secret-key: xxxx
oss:
#阿里bucket名称
bucket-name: tuanpress
#Endpoint(地域节点)
endpoint-url: https://oss-cn-beijing.aliyuncs.com
#我们添加的管理域名
access-domain: https://cdn.tuan.press/
接口
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* 阿里云的开放式存储服务API接口层
*/
public interface AliyunOSSService {
/**
* 往阿里云OSS上传一个文件,oss详情参阅:https://help.aliyun.com/product/31815.html?spm=a2c4g.11186623.6.540.e45263287O4vS6
*
* @param saveFolder 文件在oss上的路径,不传递时保存在默认的根路径下
* @param contentType 文件类型,如:image/jpg
* @param fileName 文件名称,如:a.jpg
* @param contentLength 文件字节大小
* @param input 输入流对象
* @return oss上保存的完整访问路径,如:http://domain/{copyrightEn}/{applicationName}/{profileActive}/{saveFolder}/imageName
*/
String upload(String saveFolder, String contentType, String fileName, long contentLength, InputStream input);
/**
* 有结尾类型,没有结尾默认jpg结尾
* @author DuanLinpeng
* @date 2021/01/16 21:27
* @param saveFolder 存储的地址路径
* @param fileMainName 文件名称
* @param multipartFile 文件流
* @return java.lang.String
*/
String upload(String saveFolder, String fileMainName, MultipartFile multipartFile);
/**
* 无结尾类型,直接上传
* @author DuanLinpeng
* @date 2021/01/16 21:31
* @param saveFolder 存储的地址路径
* @param fileName 文件名称
* @param multipartFile 文件流
* @return java.lang.String
*/
String upload4SpecialName(String saveFolder, String fileName, MultipartFile multipartFile);
/**
* 把base64字符串转换为流存到oss中
* @author DuanLinpeng
* @date 2021/01/16 21:28
* @param saveFolder 存储的地址路径
* @param fileName 文件名称
* @param base64ImgContent 图片转base64字符串
* @return java.lang.String 返回图片地址
*/
String uploadImgByBase64(String saveFolder, String fileName, String base64ImgContent);
/**
* 删除OSS中 fileUrl 的文件
* @author DuanLinpeng
* @date 2021/01/16 21:28
* @param fileUrl
* @return void
*/
void delete(String fileUrl);
}
接口实现
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.model.ObjectMetadata;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.multipart.MultipartFile;
import tuan.alibabaoss.oss.service.AliyunOSSService;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Service("aliyunOSSService")
public class AliyunOSSServiceImpl implements AliyunOSSService {
private final String ossBucketName;
private final String ossAccessDomainUrl;
private final OSSClient client;
private final String filePathPrefix;
public AliyunOSSServiceImpl(
@Value("${spring.application.name}") String applicationName,
@Value("${spring.profiles.active}") String profileActive,
@Value("${alibaba.cloud.oss.endpoint-url}") String ossEndpointUrl,
@Value("${alibaba.cloud.oss.bucket-name}") String ossBucketName,
@Value("${alibaba.cloud.aliyun.secret-id}") String accessKeyId,
@Value("${alibaba.cloud.aliyun.secret-key}") String accessKeySecret,
@Value("${alibaba.cloud.oss.access-domain}") String ossAccessDomainUrl) {
this.ossBucketName = ossBucketName;
this.ossAccessDomainUrl = ossAccessDomainUrl;
this.client = new OSSClient(ossEndpointUrl, CredentialsProviderFactory.newDefaultCredentialProvider(accessKeyId, accessKeySecret), new ClientConfiguration());
this.filePathPrefix = applicationName + "/" + profileActive;
}
/**
* 为了实现同一个cos满足多个运行环境,所以在上传时自动在用户文件名称前加上当前的环境值,用于区分不同环境的上传文件。
*
* @param fileName 用户文件名称
* @return 实际的cos上文件名称
*/
private String getRealFileName(String saveFolder, String fileName) {
return StringUtils.isNotEmpty(saveFolder) ? filePathPrefix + "/" + saveFolder + "/" + fileName : filePathPrefix + "/" + fileName;
}
@Override
public String upload(String saveFolder, String contentType, String fileName, long contentLength, InputStream input) {
if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(contentType) || contentLength <= 0 || null == input) {
return null;
}
ObjectMetadata objectMeta = new ObjectMetadata();
objectMeta.setContentLength(contentLength);
objectMeta.setContentType(contentType);
String filePath = getRealFileName(saveFolder, fileName);
try {
client.putObject(ossBucketName, filePath, input, objectMeta);
return ossAccessDomainUrl + filePath;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public String upload(String saveFolder, String fileMainName, MultipartFile multipartFile) {
if (null != multipartFile && !multipartFile.isEmpty()) {
try {
String filename = multipartFile.getOriginalFilename();
String extFileName;
if (StringUtils.isNotEmpty(filename)) {
extFileName = filename.substring(filename.lastIndexOf("."));
} else {
extFileName = ".jpg";
}
return upload(saveFolder, multipartFile.getContentType(), fileMainName + extFileName, multipartFile.getSize(), multipartFile.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String upload4SpecialName(String saveFolder, String fileName, MultipartFile multipartFile) {
if (null != multipartFile && !multipartFile.isEmpty()) {
try {
return upload(saveFolder, multipartFile.getContentType(), fileName, multipartFile.getSize(), multipartFile.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public String uploadImgByBase64(String saveFolder, String fileName, String base64ImgContent) {
if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(base64ImgContent)) {
return null;
}
try {
byte[] bytes = Base64Utils.decodeFromString(base64ImgContent);
return upload(saveFolder, "image/jpg",fileName, bytes.length, new ByteArrayInputStream(bytes));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public void delete(String fileUrl) {
if (StringUtils.isEmpty(fileUrl)) {
return;
}
try {
fileUrl = fileUrl.replaceFirst(ossAccessDomainUrl, "");
client.deleteObject(ossBucketName, fileUrl);
} catch (OSSException | ClientException e) {
e.printStackTrace();
}
}
}
oss存储测试
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;
import tuan.alibabaoss.oss.service.AliyunOSSService;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
/**
* OSS测试
* @author DuanLinpeng
* @date 2021/01/16 13:50
**/
@RestController
@RequestMapping("/oss")
public class OSSController {
@Autowired
private AliyunOSSService ossService;
/**
* 有结尾类型
* @author DuanLinpeng
* @date 2021/01/16 15:31
* @param multipartFile
* @return java.lang.String
*/
@PostMapping("uploadFiles")
public String uploadFiles(MultipartFile multipartFile){
//uuid 可以为你文件的唯一标识.结尾类型
//saveFolder 保存的路径
String uuid = UUID.randomUUID().toString();
String activityPhotoUrl = ossService.upload("text", uuid, multipartFile);
return activityPhotoUrl;
}
/**
* 无结尾类型
* @author DuanLinpeng
* @date 2021/01/16 15:31
* @param multipartFile
* @return java.lang.String
*/
@PostMapping("upload4SpecialName")
public String upload4SpecialName(MultipartFile multipartFile){
//uuid 可以为你文件的唯一标识(没有结尾)
//saveFolder 保存的路径(没有会自己创建)
String uuid = UUID.randomUUID().toString();
String activityPhotoUrl = ossService.upload4SpecialName("text", uuid, multipartFile);
return activityPhotoUrl;
}
/**
*
* @return
*/
@PostMapping("uploadImgByBase64")
public String uploadImgByBase64() {
//uuid 可以为你文件的唯一标识(没有结尾)
//saveFolder 保存的路径(没有会自己创建)
String base64Str = imageToBase64Str("H:\\PYTHON 爬虫\\I love pachong\\Top\\风景人物图片唯美伤感治愈系\\90f6ca062db15550d5cc0df14b90cefd.jpg");
String uuid = UUID.randomUUID().toString();
String activityPhotoUrl = ossService.uploadImgByBase64("text", uuid, base64Str);
return activityPhotoUrl;
}
/** 图片转base64字符串
* @param imgFile 图片路径
* @return base64字符串格式的图片
*/
private static String imageToBase64Str(String imgFile) {
InputStream inputStream = null;
byte[] data = null;
try {
inputStream = new FileInputStream(imgFile);
data = new byte[inputStream.available()];
//根据文件流字节大小初始化data字节数组大小
inputStream.read(data);
//将流读入data
inputStream.close();
//关闭流
} catch (IOException e) {
e.printStackTrace();
}
//将图片数组加密
return Base64Utils.encodeToString(data);
}
/**
* 删除图片 path 路径
* @param fileUrl
* @return
*/
@PostMapping("delete")
public String delete(String fileUrl){
ossService.delete(fileUrl);
return "Ok";
}
}
更多文档接口api参考官方文档:https://help.aliyun.com/document_detail/155822.html?spm=a2c4g.11186623.3.4.781f3ea7J34CQ6