大家好,我是 码赛客1024 ,今天我们一起来学习阿里云的对象存储服务OSS。
阿里云对象存储OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存储服务,提供99.9999999999%(12个9)的数据持久性,99.995%的数据可用性。多种存储类型供选择,全面优化存储成本。
简单理解就是一个云储存服务器,可以把我们的文件存储到阿里云的服务器中。
先完成阿里云账号注册,地址 https://www.aliyun.com/,完成实名制认证。
阿里云为了其API的访问安全考虑,设置了AccessKey的安全方案,AccessKey是我们访问阿里云 API 的密钥,具有该账户完全的权限,请您妥善保管。
我们待会要访问OSS服务,所以先把AccessKey创建好,方便后边使用。
设置方式:
① 进入账号中心,点击自己的头像,在下拉菜单中点击AccessKey管理,进入设置界面。

选择继续使用 AccessKey

② 生成AccessKey,可以看到起包含:AccessKey ID 和 AccessKey Secret 两部分。
这里注意:一旦点击确定,AccessKey的Secret就会隐藏起来,想查看的话,要通过验证码校验后才能查看,所以建议先复制一份,方便后期使用。

在产品中找到 对象存储OSS 服务,并开通

开通后,点击 “管理控制台” 进入OSS的页面

pom.xml依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/>
</parent>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--aliyun oss依赖-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.0</version>
</dependency>
</dependencies>
创建页面:resources/static/upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.2.1/jquery.form.min.js"></script>
</head>
<body>
<form id="fileForm" action="/upload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="file"> <br>
<input type="button" value="上传" id="sub">
</form>
<script>
$(function (){
$("#sub").click(function (){
$("#fileForm").ajaxSubmit({
success:function (data){
if(data.code == 2000){
let img = $("<img src="+data.url+" style='width:200px'>");
$("body").append(img);
}else if(data.code == 5000){
alert("文件上传失败,请联系管理员!");
}
}
});
});
});
</script>
</body>
</html>
@RestController
public class FileController {
@Autowired
private IFileService fileService;
/**
* 上传文件
* @param file 文件
* @return
*/
@RequestMapping("/upload")
public Map<String,Object> uploadFile(MultipartFile file){
//调用业务层实现上传
String url = fileService.uploadFile(file);
Map<String,Object> map = new HashMap<>();
if (url==null){
map.put("code",5000);
map.put("msg","上传失败");
return map;
}
map.put("code",2000);
map.put("msg","上传成功");
map.put("url",url);
return map;
}
}
① 业务层接口
public interface IFileService {
String uploadFile(MultipartFile file);
}
② 业务层实现类
@Service
public class FileServiceImpl implements IFileService {
@Override
public String uploadFile(MultipartFile file) {
//在这里使用阿里云oss完成文件上传
return null;
}
}
application.yml
spring:
servlet:
multipart:
enabled: true
max-file-size: 5MB # 上传文件单个限制
Bucket翻译为水桶。官方解释:存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。
也就是:在OSS中,基于不同的业务需求,可以将不同的文件存储在不同的Bucket中(存储空间),以此做到文件的分类保存。即:Bucket就是存储空间。
① 新建Bucket

② 填写信息创建Bucket

创建完毕后,在列表中就可以看到自己创建的Bucket。

③ 在 “概览” 中可以看到新创建的Bucket信息
其中 Bucket域名 需要注意,在文件上传成功后,访问文件的路径就是:https://Bucket的域名/文件路径,我这里就是:https://msk1024.oss-cn-chengdu.aliyuncs.com/文件路径

① 查看Java API 文档

但是,这样打开,他的文档是以小窗口的形式展示,不方便查询,建议在文档中心查看API,文档中心地址:https://help.aliyun.com/,进入后依次找到:存储 -> 对象存储OSS 即可。
② 查看SDK上传示例
SDK示例 -> Java -> 上传文件 -> 简单上传 -> 上传文件流 。
官方示例如下:
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.FileInputStream;
import java.io.InputStream;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "D:\\localpath\\examplefile.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建PutObject请求。
ossClient.putObject(bucketName, objectName, inputStream);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
③ 将上传代码整合到我们的业务层实现中
@Service
public class FileServiceImpl implements IFileService {
//上传文件
@Override
public String uploadFile(MultipartFile file) {
//地域节点地址(一定记得要和自己创建存储空间时选择的地域地址一致)
String endpoint = "oss-cn-chengdu.aliyuncs.com";
//存储空间名
String bucketName = "msk1024";
//自己的秘钥id
String accessKeyId = "msk1024msk1024msk1024";
//自己的秘钥值
String accessKeySecret = "msk1024msk1024msk1024msk1024";
//执行上传
return alibabaSSO(file,endpoint,bucketName,accessKeyId,accessKeySecret);
}
/**
* 文件上传
* @param file 文件
* @param endpoint 地域对应的服务器地址,例如:成都 -> https:oss-cn-chengdu.aliyuncs.com
* @param bucketName 存储空间名字
* @param accessKeyId 秘钥id
* @param accessKeySecret 密码值
* @return 返回文件的url
*/
private String alibabaSSO(MultipartFile file,String endpoint,String bucketName,String accessKeyId,String accessKeySecret){
//【1.设置文件在bucket中存储的路径格式为: 年/月/日/文件名】
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd/");
String filePath = format.format(new Date());
//重命名文件
String filename = UUID.randomUUID().toString().replaceAll("-","")+file.getOriginalFilename();
//完整路径中不能包含Bucket名称,例如:2022/10/27/sgfhiasndas8dasndask.png
String objectName = filePath+filename;
//【2.创建OSSClient实例】
OSS ossClient = new OSSClientBuilder().build("https://"+endpoint, accessKeyId, accessKeySecret);
try {
//【3.创建PutObject请求,执行上传】
ossClient.putObject(bucketName, objectName, file.getInputStream());
//【4.上传成功后,拼接好文件的url并返回】
//格式为: https://存储空间名.地域地址/文件路径
//我这里就是:https://msk1024.oss-cn-chengdu.aliyuncs.com/2022/10/27/sgfhiasndas8dasndask.png
String url = "https://"+bucketName+"."+endpoint+"/"+objectName;
return url;
}catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} catch (IOException e){
System.out.println("IOException:" + e.getMessage());
}finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return null;
}
}
上传了3张图片
① OSS中查看上传的文件,单击文件后边的 “详情” 按钮可以查看文件详细信息

② 浏览器中效果如下
响应消息:
{
code: 2000
msg: "上传成功"
url: "https://msk1024.oss-cn-chengdu.aliyuncs.com/2022/10/27/65ac690f9d4b45f396270be6bae252252.png"
}
页面效果:

完结撒花。
原创不易,一健三联哦,感谢。
总的来说,我对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变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在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
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。