持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
背景
图片和文件存储是每个项目必备的需求,早些年公司使用的是自建的FastDFS分布式进行存储,但是最近几年云技术发展迅速,出现很多云存储的技术方案,本文将详细讲解如何使用云存储存储文件。
简介
云存储是一种网上在线存储的模式,即把数据存放在通常由第三方托管的多台虚拟服务器,而非专属的服务器上。常见的云存储有阿里OSS、腾讯的COS、百度的CFS、Minio等。
优势
- 持久性:云服务器服务可用性不低于99.995%,能够持久提供服务。
- 安全:提供企业级多层次安全防护,包括服务端加密、客户端加密、防盗链、通过Bucket Policy 限制IP黑白名单访问、细粒度权限管控、日志审计、WORM特性等。多用户资源隔离机制,支持异 地容灾机制。
- 成本:可通过多线BGP接入运营商骨干网线路,带宽资源充足,上行流量免费。 无需运维人员与托管费用,0成本运维。
- 智能存储:提供多种数据处理能力,如图片处理、视频截帧、文档预览、图片场景识别。
本文将以阿里云的OSS为例,来讲解云存储。
阿里云OSS云存储实现方案
阿里云OSS文件存储实现方案可以分为两种方案:
- 后端上传
- 前端直连OSS,上传文件
后端上传
后端上传的业务流程
说明:用户将文件上传到应用服务器,应用服务器在将文件上传到OSS
具体实现
pom文件引入相关jar包
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.5.1</version>
</dependency>
属性配置
新建oss.properties文件,文件内容如下:
oss.accessKeyId=##
oss.accessKeySecret##
oss.bucket=##
oss.endpoint=##
oss.bucketImageUrl=##
//属性实体类
@Component
@ConfigurationProperties(prefix = "oss")
@PropertySource("classpath:oss.properties")
public class OssProperties
{
private String accessKeyId;
private String accessKeySecret;
private String bucket;
private String endpoint;
private String bucketImageUrl;
private String fileMaxSize;
//
}
说明:填写阿里云OSS配置相关信息,关于相关的属性说明请查看阿里云文档。
工具类
// 获取ossclient连接工具类
public class OssFactory
{
private OssProperties ossProperties;
private static OssFactory ossFactory;
private OssFactory()
{
ossProperties = BeanManager.getBean(OssProperties.class);
}
public synchronized static OssFactory getInstance ()
{
if(ossFactory==null)
{
ossFactory = new OssFactory();
}
return ossFactory;
}
public OSSClient getClient()
{
ClientConfiguration conf = new ClientConfiguration();
conf.setSupportCname(true);
OSSClient client = new OSSClient(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(),
ossProperties.getAccessKeySecret(), conf);
return client;
}
public String getFileUrl(String ossPath)
{
StringBuffer sb = new StringBuffer();
sb.append("http://");
sb.append(ossProperties.getBucket());
sb.append(".");
sb.append(ossProperties.getEndpoint());
sb.append("/");
sb.append(ossPath);
return sb.toString();
}
public void closeClient(OSSClient client)
{
if (client != null)
{
client.shutdown();
}
}
}
//操作文件上传的工具类
public class OssUtils
{
public static Logger logger = LoggerFactory.getLogger(OssUtils.class);
public static String putFile(String ossBucket,String ossFileName,String filePath)
{
logger.info("Put oss file. ossBucket:" + ossBucket + " ,ossFileName:" + ossFileName);
OSSClient ossClient =null;
try
{
ossClient = OssFactory.getInstance().getClient();
File uploadFile = new File(filePath);
InputStream ins =new FileInputStream(uploadFile);
ossClient.putObject(ossBucket, ossFileName, ins);
return OssFactory.getInstance().getFileUrl(ossFileName);
}
catch(Exception e)
{
logger.error("Put file to oss error. filePath:" + filePath + " ,ossBucket:" + ossBucket+" ,"
+ "ossFileName:"+ossFileName, e);
return "";
}
finally
{
if(ossClient!=null)
{
ossClient.shutdown();
}
}
}
}
测试示例类
@RestController
@RequestMapping("/oss")
public class OssController
{
private Logger logger =LoggerFactory.getLogger(OssController.class);
@Autowired
private OssProperties ossProperties;
@RequestMapping("/upload")
public String upload() throws IOException
{
String ossFileName = "zmp"+ File.separatorChar + "dish"+File.separatorChar+"testdish.jpg";
OssUtils.putFile(ossProperties.getBucket(), ossFileName, "E:\\upload\\test.jpg");
String ossFilePath = OssFactory.getInstance().getFileUrl(ossFileName);
logger.info("uploadDishImg ossFilePath:" + ossFilePath);
return ossFilePath;
}
}
方案存在的缺点
-
首先文件传入到应用服务器,在由应用服务器上传到OSS,经过了两道传输,会导致传输时间增长。
-
消耗了应用服务器的带宽流量,如果上传的文件数量比较多,会大量占用应用服务器流量导致应用服务器性能下降。
-
消耗了应用服务器的带宽流量,会产生一定的费用,增加了额外的成本。
-
此方案需要特别注意:应用服务器与OSS连级一定要配置OSS的地址为内网地址,否则会产生额外流量。
解决办法
采用前端直连OSS上传文件,关于这种方案下一章将进行讲解。
总结
本文讲解了文件存储采用云存储的解决方案,如有问题,请随时反馈。