一. 需求背景
小白: 辉哥,我想在项目中实现图片上传,不知道有没有好用的第三方文件上传技术呢?
辉哥:那多了去了,阿里、腾讯、百度、七牛云等都有文件上传技术,你从中随便挑一个,辉哥这就给你安排。
小白:阿里也有文件上传?!!!要不辉哥就给我安排阿里的实现方案吧。
辉哥:小子,你眼光不错哦。我这正好就有阿里OSS的图片处理文档,你拿去学习吧。
二. OSS简介
1. 快速了解
OSS(Object Storage Service)对象存储服务是一种海量、安全、低成本、高可靠的云存储服务,可以提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。有多种存储类型可供选择,全面优化存储成本,非常适合存储非结构化的数据,例如视频、图形、日志、文本文件以及各种App应用、多终端同步软件、网盘下载站的文件等。
2. 存储类型
OSS支持的具体存储类型较多,我们可以参考如下链接:https://oss.console.aliyun. com/overview
2.1 标准存储(Standard)
该方案提供高可靠、高可用、高性能的对象存储服务,能够支持频繁的数据访问,适用于各种社交、分享类的图片、音视频应用、大型网站、大数据分析等业务场景。OSS还提供了标准存储-本地冗余(LRS)和标准存储-同城冗余(ZRS)两种数据冗余存储方式。
标准存储-本地冗余(LRS):采用数据冗余存储机制,将每个对象的不同冗余存储在同一个可用区内多个设施的多个设备上,确保硬件失效时的数据持久性和可用性。
标准存储-同城冗余(ZRS):采用多可用区(AZ)机制,将用户的数据分散存放在同一地域(Region)的3个可用区。当某个可用区不可用时,仍然能够保障数据的正常访问。
2.2 低频访问(Infrequent Access)
该方案提供了高持久性、较低存储成本的对象存储服务,有最低存储时间(30天)和最小计量单位(64 KB)要求。支持数据实时访问,访问数据时会产生数据取回费用,适用于较低访问频率(平均每月访问频率1到2次)的业务场景。提供低频访问-本地冗余(LRS)和低频访问-同城冗余(ZRS)两种数据冗余存储方式。
低频访问-本地冗余(LRS):采用数据冗余存储机制,将每个对象的不同冗余存储在同一个可用区内多个设施的多个设备上,确保硬件失效时的数据持久性和可用性。
低频访问-同城冗余(ZRS):采用多可用区(AZ)机制,将用户的数据分散存放在同一地域(Region)的3个可用区。当某个可用区不可用时,仍然能够保障数据的正常访问。
2.3 归档存储(Archive)
该方案提供了高持久性、极低存储成本的对象存储服务。有最低存储时间(60天)和最小计量单位(64 KB)要求。数据需解冻(约1分钟)后访问,解冻会产生数据取回费用。适用于数据长期保存的业务场景,例如档案数据、医疗影像、科学资料、影视素材等。
2.4 冷归档存储(Cold Archive)
该方案提供了高持久性的对象存储服务,存储费用在四种存储类型中最低。有最低存储时间(180天)和最小计量单位(64 KB)要求。数据需解冻后访问,解冻时间根据数据大小和选择的解冻模式决定,解冻会产生数据取回费用。
适用于需要超长时间存放的极冷数据,例如因合规要求需要长期留存的数据、大数据及人工智能领域长期积累的原始数据、影视行业长期留存的媒体资源、在线教育行业的归档视频等业务场景。
给大家介绍了以上这些存储类型之后,接下来辉哥就带各位看看OSS到底该如何使用,本案例采用标准存储进行实现。
三. 快速使用
1. 开通服务
在使用OSS之前,我们要先购买OSS服务,毕竟这些第三方公司都不是做慈善的,怎么可能让我们免费使用这些吊炸天的技术呢?我们就掏点money,为让马爸爸成为首富贡献自己的绵薄之力吧。
在学习阶段,我们购买OSS时,可以选择按量计费的方案,当然也可以直接买一个半年包或者一年包!这些在学习时进行测试就已经足够了。我们可以看到,40GB存储包也就9块钱,便宜啊,买买买!
阿里云购买地址也给大家准备好啦:https://common-buy.aliyun.com/spm=5176.7933691.1309819..68b22a66FQKm7f&commodityCode=ossbag&request

2. 创建存储空间
购买了OSS服务之后,接下来需要创建自己的存储空间,创建过程如下图所示:

3. 上传测试
接下来我们可以先通过手动方式测试一下上传功能是否好使。

四. 代码实现
当然,我们在开发时不可能采用手动上传的方式实现文件上传,肯定是要利用代码进行实现的,接下来辉哥就给大家说说用代码该怎么实现文件上传。
1. 添加依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
2. 创建AccessKey
OSS为了提高安全性,要求每个用户都必须创建AccessKey,作为访问令牌,所以请按下图所示创建获取自己的AccessKey。

AccessKey简称AK,指的是访问身份验证中用到的AccessKeyId和AccessKeySecret。

大家要保存好自己的AK,不要随意泄露给别人哦。
3. 定义3个常量值
我们可以随便定义一个接口类,在其中定义如下3个常量值,用于存储自己的AK等信息。
public static final String endpoint = “所选服务器的地址 ,可以上传一张图片看看”;
public static final String accessKeyId = "xxxxx";
public static final String accessKeySecret = "xxxxx";
4. 文件上传下载文档
对于文件上传下载的具体实现过程,我们可以参考如下官方文档。
https://help.aliyun.com/document_detail/84781.html
5. 上传功能
为了方便实现图片上传,辉哥定义了一个上传图片的方法,该方法可以定义在工具类中。
/**
* @param objectName 有没有二级目录 如果有 目录1/目录2/文件名
* @param content byte[ 图片的字节数组
* @return
* @throws Exception
*/
public static String uploadImage(
String objectName,
byte[] content) throws Exception {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建上传文件的元信息,可以通过文件元信息设置HTTP header(设置了才能通过返回的链接直接访问)。
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType("image/jpg");
// 文件上传
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content), objectMetadata);
// 设置URL过期时间为1小时。
Date expiration = new Date(System.currentTimeMillis() + 60*60 * 1000);
//返回url地址
String url = ossClient.generatePresignedUrl(bucketName, objectName, expiration).toString();
//关闭OSSClient。
ossClient.shutdown();
return url;
}
6. 下载功能
为了方便实现图片下载,辉哥又定义了一个下载图片的方法,该方法也可以定义在工具类中。
/**
* @param objectName
* @param localFile
* @throws Exception
*/
public static void downFile(
String objectName,
String localFile) throws Exception {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(localFile));
// 关闭OSSClient。
ossClient.shutdown();
}
7. 删除功能
最后,我们再搞一个文件删除功能,代码如下:
/**
* @param objectName
*/
public static void deleteFile(
String objectName) {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
ossClient.deleteObject(bucketName, objectName);
// 关闭OSSClient。
ossClient.shutdown();
}
五. 结语
我们在开发中会接触到很多的第三方文件服务器,在学习时首先要下载对应的sdk,并查看官方文档,根据官方文档的要求一步步进行实现即可。其实越是第三方的技术,使用起来越简单,因为如果第三方的功能使用起来太复杂,就会减少大家的使用兴趣,从而阻碍了该产品的推广。
现在你知道阿里OSS怎么使用了吗?如果你还有什么问题,可以在评论区给我留言或私信哦。
*威哥Java学习交流Q群:691533824
加群备注:CSDN推荐
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden