华为云OBS的官方文档(链接:https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0901.html#section1)中关于上传文件的内容,只提供了使用JAVA获取临时上传链接,并使用JAVA创建请求上传纯文本的方法。想要把这部分内容应用到 SpringBoot + Vue + ElementUI/Element-Plus 中,还差很多东西。
文章目录
- 0 前提条件
- 1 OBS 桶创建和配置
- 1.1 华为云OBS桶的创建
- 1.2 配置桶允许跨域请求
- 1.3 获取桶信息
- 2 SpringBoot 后端配置
- 2.1 依赖
- 2.2 application.properties 配置
- 2.3 工具类
- 2.4 Controller
- 3 Vue 前端配置
- 3.1 Vue 组件
- 3.2 upload API
- 3.3 request.js
0 前提条件
请先确保SpringBoot、Vue、ElementUI/Element-Plus、axios 等工具安装和配置正确
笔者使用环境:SpringBoot 3.1.0, Vue 3, Element-Plus
SpringBoot 2.7 和 Vue 2 按理不会有很大区别,如有需要请自行调整代码
1 OBS 桶创建和配置
1.1 华为云OBS桶的创建
可参考如下配置
1.2 配置桶允许跨域请求
可参考官方文档:https://support.huaweicloud.com/sdk-browserjs-devg-obs/obs_24_0201.html
其中允许的来源设置为 * 即允许所有跨域请求,也可按如下设置,仅允许当前本地前端访问,其中 8080 为 Vue 前端端口:
http://localhost:8080
http://127.0.0.1:8080
补充头域 可留空
1.3 获取桶信息
后边需要用到的信息有:bucketName、accessKeyId、securitAccessKey、endPoint
bucketName: 本文1.1中创建桶时自定义的桶名称;
accessKeyId 和 securitAccessKey: 参考官方文档https://support.huaweicloud.com/usermanual-ca/zh-cn_topic_0046606340.html;
endPoint:参考下图
2 SpringBoot 后端配置
2.1 依赖
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java</artifactId> <!-- 华为云依赖 -->
<version>3.22.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <!-- log日志 -->
<optional>true</optional>
</dependency>
2.2 application.properties 配置
application.properties 添加如下配置,值为本文1.3获取的桶信息
huaweicloud.obs.accessKey=
huaweicloud.obs.securityKey=
huaweicloud.obs.endPoint=
huaweicloud.obs.bucketName=
huaweicloud.obs.path =
2.3 工具类
在 com.gabriel.docsharing.utils
创建如下工具类:
package com.gabriel.docsharing.utils;
import com.obs.services.ObsClient;
import com.obs.services.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class HuaweiOBS {
@Value("${huaweicloud.obs.accessKey}")
private String ak;
@Value("${huaweicloud.obs.securityKey}")
private String sk;
@Value("${huaweicloud.obs.bucketName}")
private String bucketName;
@Value("${huaweicloud.obs.endPoint}")
private String endpoint;
// 文件目录
private final String prifix = "/test";
/**
* 获取上传地址
*
* @param fileName 文件名称
* @param fileType 文件路径
* @return
*/
public String getUploadUrl(String fileName, FileType fileType) {
try {
// 创建ObsClient实例
ObsClient obsClient = new ObsClient(ak, sk, endpoint);
// URL有效期,3600秒
long expireSeconds = 3600L;
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/octet-stream");
String objectName = fileType.getType().concat("/").concat(fileName);
TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.PUT, expireSeconds);
request.setBucketName(bucketName);
request.setObjectKey(objectName);
request.setHeaders(headers);
TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
return response.getSignedUrl();
} catch (Exception e) {
log.error("获取上传地址异常:{}", e.getMessage(), e);
}
return null;
}
public enum FileType {
TEST("test", "测试"),
PDF("pdf","PDF文件");
private String type;
private String desc;
FileType(String type, String desc) {
this.type = type;
this.desc = desc;
}
public String getType() {
return type;
}
public String getDesc() {
return desc;
}
}
}
2.4 Controller
在 com.gabriel.docsharing.controller
创建如下 Controller:
package com.gabriel.docsharing.controller;
import com.gabriel.docsharing.utils.HuaweiOBS;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 前端控制器
*
* @author Gabriel
* @since 2023-06-08
*/
@Log
@RestController
@RequestMapping("/doc")
public class DocController {
@Autowired
HuaweiOBS huaweiOBS;
@RequestMapping(value = "/getUploadUrl", method = RequestMethod.GET)
public String getUploadUrl(String filename){
String url = huaweiOBS.getUploadUrl(filename, HuaweiOBS.FileType.TEST);
log.info("get upload url, filename: "+ filename + " result: " + url);
return url;
}
}
3 Vue 前端配置
3.1 Vue 组件
创建 Upload.vue 文件(请自行设置路由),内容如下:
<template>
<el-upload class="upload" ref="upload" drag
:http-request="uploadAction"
:limit="1"
:auto-upload="false"
:on-change="fileChange"
:on-exceed="handleExceed">
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
<el-button @click="submitForm">上传</el-button>
</template>
<script>
import {genFileId} from "element-plus";
import {useUploadApi} from "@/api/upload";
export default {
name: "Upload",
data() {
return {
uploadUrl: ''
}
},
methods: {
fileChange(file) { // 上传文件发生变化时,根据新文件获取上传链接
if (!this.checkDoc(file)) {
this.$refs.upload.clearFiles();
} else {
useUploadApi().getUploadUrl(file.name).then((res) => {
this.uploadUrl = res;
});
}
},
handleExceed(files) { // 上传第二个文件时,覆盖第一个文件
if (this.checkDoc(files[0])) {
this.$refs.upload.clearFiles()
let file = files[0]
file.uid = genFileId()
this.$refs.upload.handleStart(file)
}
},
checkDoc(file) {
// 文件大小和格式检查
// let index = file.name.lastIndexOf(".");
// let extension = file.name.substr(index + 1);
// let extensionList = ["jpeg"];
// const isLt2M = file.size / 1024 / 1024 < 1;
// if (!isLt2M) {
// ElMessage.error("文件不可超出1M");
// return false;
// } else if (extensionList.indexOf(extension) < 0) {
// ElMessage.error("当前文件格式不支持");
// return false;
// } else {
// return true;
// }
return true;
},
submitForm() { // 提交上传
this.$refs.upload.submit();
},
uploadAction(param){ // 提交时的自定义上传配置
useUploadApi().uploadFile(this.uploadUrl, param.file).then(res=>{
alert("上传完成,请在检查中查看返回状态")
})
},
},
}
</script>
3.2 upload API
创建 api/upload/index.js 文件,内容如下:
import request from '@/utils/request';
/**
* 上传文件api接口集合
* @method signIn 用户登录
* @method signOut 用户退出登录
*/
export function useUploadApi() {
return {
getUploadUrl: (filename) => {
return request({
url: '/api/doc/getUploadUrl?filename=' + filename,
method: 'get'
});
},
uploadFile: (url, file) => {
return request({
url: url,
method: 'put',
headers:{'Content-Type': 'application/octet-stream'},
data: file
});
}
};
}
3.3 request.js
创建 utils/request.js 文件,内容如下:
import axios from 'axios';
// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 50000,
});
export default service;