【OBS】SpringBoot + Vue + el-upload 通过临时 URL 上传文件到 OBS

华为云OBS的官方文档(链接:https://support.huaweicloud.com/sdk-java-devg-obs/obs_21_0901.html#section1)中关于上传文件的内容,只提供了使用JAVA获取临时上传链接,并使用JAVA创建请求上传纯文本的方法。想要把这部分内容应用到 SpringBoot + Vue + ElementUI/Element-Plus 中,还差很多东西。

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;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叼辣条闯天涯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值