项目场景:
一、当我们再做微服务项目的时候,之前上传的文件都是存到本地,当我们服务多了之后,一个机器将不够用,因此我们需要部署到多个机器,如果一个服务挂了恰好也是刚刚上传的文件的服务,当网关去找这个服务的时候找不到,因此会负载均衡找到别的服务,但是那个服务却没有我们所上传的文件,所以我们需要一个云存储,这里我们选择阿里的OSS对象存储服务。
1、首先需要去阿里云开通OSS对象存储服务,开通后是这样的
2、建立一个bucket(存储对象的容器,上边的jdmall-upload就是建立的一个bucket)点进所建立的bucket之后进入上传文件的地方,当然肯定不是在这上边上传,我们需要结合前端页面使用elementUi来上传然后与后端联调完成上传文件
3、使用ElementUi的图片缩略图的upload组件
这里主要注意action属性,点击上传后会走这个url还有下边几个回调函数,上传之前、上传成功、上传失败这几个回调函数,这里就不介绍了直接上代码。
<template>
<div>
<el-upload
action="http://jdmall-upload.oss-cn-beijing.aliyuncs.com"
:data="dataObj"
list-type="picture"
:multiple="false" :show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
</el-upload>
<!-- 点击图片可看大图-->
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="fileList[0].url" alt="">
</el-dialog>
</div>
</template>
<script>
import {policy} from './policy'
import { getUUID } from '@/utils'
export default {
name: 'singleUpload',
props: {
value: String
},
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) {
}
}
},
data () {
return {
dataObj: {
policy: '',
signature: '',
key: '',
ossaccessKeyId: '',
dir: '',
host: ''
// callback:'',
},
dialogVisible: false
}
},
methods: {
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) => {
console.log('文件名:', file)
policy().then(response => {
_self.dataObj.policy = response.data.policy
_self.dataObj.signature = response.data.signature
_self.dataObj.ossaccessKeyId = response.data.accessid
// eslint-disable-next-line no-template-curly-in-string
_self.dataObj.key = response.data.dir + getUUID() + '_' + file.name
_self.dataObj.dir = response.data.dir
_self.dataObj.host = response.data.host
console.log('响应的数据。。。', _self.dataObj)
resolve(true)
})
})
},
handleUploadSuccess (res, file) {
console.log('上传成功...')
this.showFileList = true
this.fileList.pop()
// eslint-disable-next-line no-template-curly-in-string,standard/object-curly-even-spacing
this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key})
this.emitInput(this.fileList[0].url)
}
}
}
</script>
<style>
</style>
这里主要 介绍几个参数:
:on-preview=“handlePreview”:指的是上传之后的文件列表里得东西
:file-list=“fileList”:是缩略图,具体格式请查看官方
action: 是上传的地址
:data=“dataObj” 上传成功之后数据存到这里是个对象
二、至于上传的地址为什么是这个样子的具体我们看后端:
1、首先我们应导入OSS相应的依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>aliyun-oss-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.4.5</version>
</dependency>
我建议是最好导入这俩个依赖,反正aliyun-oss-spring-boot-starter这个是必须导入的,下边那个依赖依据自己情况,我没导的时候反正报错。
2、我们需要去配置OSS,配置上传的地址呀,账号密码啥的,一般 微服务都会配置到nacos配置中心
access-key: 就是账号
secret-key: 就是密码
endpoint: 是地域节点,就是上传到哪里
至于怎么创建oss的access-key和secret-key,自己去百度搜索吧。
最好在创建AccessKey的时候把跨域勾上,然后设置一些权限
设置完跨域后,,新建AccessKey:
新建AccessKey:
进入AccessKey界面创建完毕后:
设置权限策略:
3、这样全部配置完了之后开始编写签名对象,签名对象就是将我们在nacos配置中心里配置的accessKey全部封装起来,然后传给前端,浏览器在进行解析,直接上代码:
(1) 我们引入了相应的oss依赖之后,直接注入
@Autowired
OSS ossClient;
我们使用阿里提供这个对象来编写oss签名
(2) 通过@Value 注解来拿取nacos配置中心中的信息,最终封装起来返回给前端
代码详情参考:Web端上传,服务签名直传并设置回调
@RestController
//制作oss签名方法,再返回给前端
@RequestMapping("thirdService")
public class OssController {
@Value("${alibaba.cloud.oss.endpoint}")
private String endpoint;
@Value("${alibaba.cloud.oss.bucket}")
private String bucket;
@Value("${alibaba.cloud.access-key}")
private String accessId;
@Autowired
OSS ossClient;
//生成签名对象,包含oss账号密码返回给浏览器,浏览器 通过这个对象上传到oss
@RequestMapping("/oss/qianM")
public R qianming(){
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
// 填写Bucket名称,例如examplebucket。
// String bucket = "jdmall-upload";
// 填写Host名称,格式为https://bucketname.endpoint。
//https://jdmall-upload.oss-cn-beijing.aliyuncs.com/testImage.jpg
String host = "https://"+ bucket + "." + endpoint;
// 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
// String callbackUrl = "https://192.168.0.0:8888";
// 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
//以日期的方式作为前缀
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format+"/";
Map<String, String> respMap=null;
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
// PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
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("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap<String, String>();
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));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
}
return R.ok("上传成功").put("data",respMap);
}
}
三、回到前端
<el-upload
action="buket地址"
:data="dataObj"
list-type="picture"
:multiple="false" :show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
</el-upload>
这段代码的action属性就指的是,我们bucket对象存储容器的地址:
上传之前我们调用这个函数,上传之前就发送上传的请求:
**:before-upload=“beforeUpload”,**我们使用了promise对象,为了更方便快速的响应。
beforeUpload (file) {
let _self = this
return new Promise((resolve, reject) => {
console.log('文件名:', file)
policy().then(response => {
_self.dataObj.policy = response.data.policy
_self.dataObj.signature = response.data.signature
_self.dataObj.ossaccessKeyId = response.data.accessid
// eslint-disable-next-line no-template-curly-in-string
_self.dataObj.key = response.data.dir + getUUID() + '_' + file.name
_self.dataObj.dir = response.data.dir
_self.dataObj.host = response.data.host
console.log('响应的数据。。。', _self.dataObj)
resolve(true)
})
})
我们看一下上传之后的响应数据:
这就是我们后端封装的oss签名对象,返回给前端的数据,我就不把数据展开看了。
以下是上传成功之后的回调:
handleUploadSuccess (res, file) {
console.log('上传成功...')
this.showFileList = true
this.fileList.pop()
// eslint-disable-next-line no-template-curly-in-string,standard/object-curly-even-spacing
this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key})
this.emitInput(this.fileList[0].url)
}
}
前边beforeUpload这个回调已经将数据返回存到了dataObj,因此我们直接拿来用放到fileList里边,做缩略图。
最后讲一下OSS里URL的组成:
Bucket域名+后端自己封装的dir + getUUID() + ‘_’ + file.name
这是bucket上传成功之后的图片的url:
后端自己封装的dir,以日期格式作为文件夹
最终返回给前端
之前上传成功后的文件:
小弟新手,纯属记录自己代码日常,以防忘记,大佬勿喷!!