学相伴接入OSS后访问速度快了10倍
Posted 狂神说
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学相伴接入OSS后访问速度快了10倍相关的知识,希望对你有一定的参考价值。
问题场景
一个thymeleaf
项目,上传图片、视频是直接使用Java
代码保存到服务器上
于是服务器压力激增,网页静态资源变得卡顿
于是我们需要将图片、视频上传移植到阿里云OSS上
阿里云对象存储OSS(Object Storage Service)是阿里云提供的海量、安全、低成本、高持久的云存储服务。
一句话描述:它是一个很棒的存取文件的在线服务器
我们可以使用它进行客户端上传,文件不通过服务端也可以上传,这样减轻了我们服务端压力
我们需要一系列配置才可以对接完成,查阅阿里云OSS
官方文档发现:javascript客户端签名直传的方式最为简单,但这种方式是有弊端的,客户端通过JavaScript
把存取文件的认证信息写在代码里面有泄露的风险
因此我们采用服务端签名后直传的方式进行上传文件,我们待会儿介绍~
准备工作
登录阿里云官网
将鼠标移至产品,单击对象存储 OSS,打开 OSS 产品详情页面。
在 OSS 产品详情页,单击立即开通。
开通服务后,在 OSS 产品详情页单击管理控制台直接进入 OSS 管理控制台界面。
您也可以单击位于官网首页右上方菜单栏的控制台,进入阿里云管理控制台首页,然后单击左侧的对象存储 OSS 菜单进入 OSS 管理控制台界面。
根据官方文档提供步骤视频可以完成开通、创建Bucket
、进行授权、配置跨域等 我们到阿里云RAM
访问控制台来添加一个用户
填入用户账号信息、勾选编程访问后点击确定
然后我们点击复制,找个地方粘贴下来我们的AccessKey ID
以及AccessKey Secret
然后我们点击添加权限为该用户授权
开始对接
官方文档流程图片:图片介绍
这里可以这么理解:
假设小王接到老板的任务:将这堆货物放到仓库中去,但仓库大门的门禁需要门卡
所以上图中的类比
1:小王去保管室拿门卡
2:小王拿到门卡回来
3:小王搬运货物到仓库,存放货物
因此我们首先先做“保管室”的功能
后端代码实现
这里就是用我们的Java
代码在服务端实现:
引入alicloud-oss
的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
application.yml
,注意版本或者依赖不同,配置有可能改变,例如我最下面的Demo
使用的boot
的依赖(配置方式发生了变化,不过我们代码都还是一样的,只是注意@Value需要写对)
spring:
cloud:
alicloud:
access-key: <你的AccessKey>
secret-key: <你的SecretKey>
oss:
endpoint: <你的endpoint(可以在你的OSS控制台概览看到)>
bucket: <你的bucket(可以在你的OSS控制台概览看到)>
Controller
package com.ruben.simpleoss.controller;
import com.ruben.simpleoss.service.OssService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Map;
/**
* 上传Controller
*
* @author <achao1441470436@gmail.com>
* @since 2021/6/18 17:40
*/
@RestController
public class UploadController
@Resource
private OssService ossService;
/**
* oss上传文件
*
* @author <achao1441470436@gmail.com>
* @since 2021/6/17 10:07
*/
@GetMapping("oss")
public Map<String, Object> oss()
return ossService.getMark();
Service
package com.ruben.simpleoss.service;
import java.util.Map;
/**
* Oss服务层
*
* @author <achao1441470436@gmail.com>
* @since 2021/6/17 10:21
*/
public interface OssService
Map<String, Object> getMark();
ServiceImpl
package com.ruben.simpleoss.service.impl;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.ruben.simpleoss.service.OssService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @ClassName: UploadServiceImpl
* @Description: 获取OSS签证
* @Date: 2020/6/3 21:55
* *
* @author: achao<achao1441470436 @ gmail.com>
* @version: 1.0
* @since: JDK 1.8
*/
@Service
public class OssServiceImpl implements OssService
@Resource
OSS ossClient;
@Value("$spring.cloud.alicloud.oss.endpoint")
private String endpoint;
@Value("$spring.cloud.alicloud.oss.bucket")
private String bucket;
@Value("$spring.cloud.alicloud.access-key")
private String accessId;
/**
* 获取临时签证
*
* @return
*/
@Override
public Map<String, Object> getMark()
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
// String callbackUrl = "http://88.88.88.88:8888";
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try
long expireTime = 3000;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap<String, String>(8);
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));
// respMap.put("expire", formatISO8601Date(expiration));
catch (Exception e)
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
finally
ossClient.shutdown();
Map<String, Object> result = new HashMap<>(4);
result.put("data", respMap);
result.put("code", 20000);
return result;
然后我们运行访问一下,就像第一步小王去拿门卡了
可以看到拿到我们的临时凭证了,就像第二步小王拿着门卡回来了
然后我们现在要拿着这些凭证去上传文件,就像第三步小王要去存货物
按照PostObject
的文档测试一下
上传完成之后我们这里是没有回调的,因为我们这里没有配置callback
,如有需要,可以查看Callback
文档
上传完成之后我们可以在控制台看到我们上传的文件
然后如果我们在代码里使用文件的url
的话,就使用host
+/
+(key
替换掉$filename
占位符为文件名)即可
例如我的host
是https://will-deprecated.oss-cn-chengdu.aliyuncs.com
加上/
再加上key
为:2021-06-18/17585793-95b9-4dbd-8dfc-2302d6afa5df_$filename
替换掉文件名就是2021-06-18/17585793-95b9-4dbd-8dfc-2302d6afa5df_partnerhead.jpg
(其实我测试过了,不用$filename
占位符,直接使用文件名也可以上传成功)
最终https://will-deprecated.oss-cn-chengdu.aliyuncs.com/2021-06-18/17585793-95b9-4dbd-8dfc-2302d6afa5df_partnerhead.jpg
则是我们完整的文件路径
前端代码实现
使用html
+vue
主页面,引用组件的地方
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>OSS上传Demo</title>
<link href="/css/elementUI.css" rel="stylesheet">
<script src="/js/jquery-3.5.1.min.js"></script>
<script src="/js/vue.min.js"></script>
<script src="/js/elementUI.js"></script>
<script src="/js/singleUpload.js"></script>
</head>
<body>
<div id="myapp">
<single-upload ref="singleUpload" v-model="imageUrl"></single-upload>
文件url: imageUrl
</div>
<script>
new Vue(
el: '#myapp',
data:
imageUrl: ''
)
</script>
</body>
</html>
自己写的组件:
function policy()
return new Promise((resolve, reject) =>
$.ajax(
url: '/oss',
type: 'GET',
contentType: 'application/json; charset=UTF-8',
success: function (res)
if (res.code == 20000)
resolve(res)
else
reject(res)
,
error: function (res)
reject(res)
);
);
Vue.component('singleUpload',
props: ['value'],
template: ' <div class="single-upload">' +
' <el-upload' +
' :before-upload="beforeUpload"' +
' :data="dataObj"' +
' :file-list="fileList"' +
' :multiple="false"' +
' :on-preview="handlePreview"' +
' :on-remove="handleRemove"' +
' :on-success="handleUploadSuccess"' +
' :show-file-list="showFileList"' +
' action="dataObj.host"' +
' list-type="text"' +
' style="display: flex;"' +
' >' +
' <el-button size="small" type="primary">点击上传</el-button>' +
' </el-upload>' +
' <el-dialog :modal="false" :visible.sync="dialogVisible">' +
' <img width="100%;" v-if="isImg(fileList[0].url)" :src="fileList[0].url" alt="图片找不到了..."/>' +
' <video width="900px" controls autoplay muted v-if="isVideo(fileList[0].url)" :src="fileList[0].url" alt="视频找不到了..."/>' +
' </el-dialog>' +
' </div>',
data()
return
dataObj:
policy: "",
signature: "",
key: "",
ossaccessKeyId: "",
dir: "",
host: ""
// callback:'',
,
dialogVisible: false
;
,
computed:
imageUrl()
return this.value;
,
imageName()
if (this.value != null && this.value !== "")
return this.value.substr(this.value.lastIndexOf("/") + 1);
else
return null;
,
fileList()
return [
name: this.imageName,
url: this.imageUrl
];
,
showFileList:
get: function ()
return (
this.value !== null && this.value !== "" && this.value !== undefined
);
,
set: function (newValue)
,
methods:
isVideo()
let fileType = this.getFileType()
return ~['.mp4', '.avi'].indexOf(fileType)
,
isImg()
let fileType = this.getFileType()
return ~['.png', '.jpg', '.jpeg', '.gif'].indexOf(fileType)
,
getFileType()
let fileType = this.value.substring(this.value.lastIndexOf('.'))
return fileType
,
getUUID() //生成UUID
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c =>
return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
)
,
emitInput(val)
this.$emit("input", val);
,
handleRemove(file, fileList)
this.emitInput("");
,
handlePreview(file)
this.dialogVisible = true;
,
beforeUpload(file)
let _self = this;
return new Promise((resolve, reject) =>
policy()
.then(response =>
console.log(response)
_self.dataObj.policy = response.data.policy;
_self.dataObj.signature = response.data.signature;
_self.dataObj.ossaccessKeyId = response.data.accessid;
_self.dataObj.key = response.data.dir + this.getUUID() + "_$filename";
_self.dataObj.dir = response.data.dir;
_self.dataObj.host = response.data.host;
resolve(true);
)
.catch(err =>
reject(false);
);
);
,
handleUploadSuccess(res, file)
console.log("上传成功...");
this.showFileList = true;
this.fileList.pop();
this.fileList.push(
name: file.name,
url:
this.dataObj.host +
"/" +
this.dataObj.key.replace("$filename", file.name)
);
this.emitInput(this.fileList[0].url);
console.log(this.fileList[0]);
)
注意引入一些文件:
最终效果:
项目源码
本次案例完整项目代码:https://gitee.com/VampireAchao/simple-oss.git
这个项目基本能应对绝大部分场景,它那次请求签证接口是使用的jQuery
的ajax
如果您是纯vue
项目,可以看我以往这个项目https://gitee.com/VampireAchao/my-vue-app.git
小结
通过对这次的OSS
对接,复习了如何在html
页面中引入vue
、elementUI
、引入vue
自定义组件、进行第三方服务接入等...
大部分项目目前都接入了OSS,所以这是一个必须要掌握的技能!
文章编辑:学相伴阿超
KuangStudy首发:https://www.kuangstudy.com/bbs/1405846273780682753
看完记得点个赞和在看吧,这对我们很重要哦~
长按扫码关注平台最新动态
以上是关于学相伴接入OSS后访问速度快了10倍的主要内容,如果未能解决你的问题,请参考以下文章