RustFs前端直接上传文件(springboot+vue3)

发布时间:2026-01-05 11:03:11
修改时间:2026-01-06 01:27:14
总阅读数:18
今日阅读数:0
昨日阅读数:8
字数:6217

后端

因为RustFs兼容s3,所以可以直接使用s3的方式来实现上传地址的签名

具体可以参考官网:https://docs.rustfs.com.cn/developer/sdk/java.html#五、java-高级功能示例

添加依赖

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.27</version>
</dependency>

注入s3配置

S3Config.java

package com.example.java_web_test1.s3.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;

import java.net.URI;

@Configuration
public class S3Config {

    @Value("${endpoint:http://127.0.0.1:9000}")
    private String endpoint;
    @Value("${accessKeyId:rustfsadmin}")
    private String accessKeyId;
    @Value("${secretAccessKey:rustfsadmin}")
    private String secretAccessKey;

    @Bean
    public S3Client buildS3Client() {
        return S3Client.builder()
                .endpointOverride(URI.create(endpoint)) // RustFS 地址
                .region(Region.US_EAST_1) // 可写死,RustFS 不校验 region
                .credentialsProvider(
                        StaticCredentialsProvider.create(
                                AwsBasicCredentials.create(accessKeyId, secretAccessKey)
                        )
                )
                .forcePathStyle(true) // 关键配置!RustFS 需启用 Path-Style
                .build();

    }

    @Bean
    public S3Presigner buildS3Presigner() {
        return S3Presigner.builder()
                .endpointOverride(URI.create(endpoint))
                .region(Region.US_EAST_1)
                .credentialsProvider(
                        StaticCredentialsProvider.create(
                                AwsBasicCredentials.create(accessKeyId, secretAccessKey)
                        )
                )
                .build();
    }


}

S3Controller.java

package com.example.java_web_test1.s3.controller;

import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedPutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;

import java.time.Duration;
import java.util.UUID;

@RestController
@RequestMapping("/s3")
public class S3Controller {

    @Resource
    private S3Presigner presigner;

    @GetMapping("/presignedUrl")
    public String getPresignedUrl(){
        String key = UUID.randomUUID().toString();
        PutObjectRequest putRequest = PutObjectRequest.builder()
                .bucket("test1")
                .key(key)
                .build();


        PresignedPutObjectRequest presignedPut = presigner.presignPutObject(
                PutObjectPresignRequest.builder()
                        .putObjectRequest(putRequest)
                        .signatureDuration(Duration.ofMinutes(10))
                        .build()
        );

        return presignedPut.url().toString();

    }

}

前端

request.ts

import axios from 'axios'

const instance = axios.create({
    baseURL:"http://localhost:8080"
});

export default instance

fileUtils.ts


import request from "./request.ts";
import type {AxiosProgressEvent} from "axios";

/**
 * 获取一个经过签名的文件上传地址
 */
export function generatePresignedUrlApi() {
    return request({
        url: '/s3/presignedUrl',
        method: 'get',
    })
}

/**
 * 文件上传
 * @param file 文件
 * @param progressEvent 上传进度回调
 */
export function fileUploadApi(file: Blob, progressEvent: (progressEvent: AxiosProgressEvent) => void) {
    return new Promise((resolve, reject) => {
        generatePresignedUrlApi().then(res => {
            const url = res.data as string
            request({
                url: url,
                method: 'put',
                headers: {
                    "Content-Type": "application/octet-stream"
                },
                data: file,
                onUploadProgress: progressEvent,
            }).then(() => {
                // 返回去掉签名的url地址,通常为公共读的情况下,改地址可直接访问到文件
                resolve(url.split("?")[0])
            }).catch(reject)
        })
    })


}

FileUpload.vue


<script setup lang="ts">

import {ref} from "vue";
import {fileUploadApi} from '../utils/fileUtils.ts'
import {Plus} from "@element-plus/icons";
import type {UploadFile, UploadProgressEvent, UploadRequestOptions} from 'element-plus';


const fileList = ref([])

/**
 * 自定义文件上传处理
 * @param option
 */
const handleHttpReq = (option: UploadRequestOptions) => {

  fileUploadApi(option.file, e => {

    // 设置上传进度
    option.onProgress({
      percent: e.progress as number * 100
    } as UploadProgressEvent)

  }).then(url => {

    // 设置上传进度
    option.onProgress({
      percent: 100
    } as UploadProgressEvent)

    // 调用上传成功回调
    option.onSuccess(url)
  })

}

/**
 * 文件上传成功处理
 * 把自定义上传返回的url设置到文件的url字段上
 * @param response 文件上传成功的响应
 * @param uploadFile 上传的文件对象
 */
const handleSuccess = (response: string, uploadFile: UploadFile) => {
  uploadFile.url = response
}

</script>

<template>
  <div>
    <h2>文件上传</h2>
    <el-upload
        v-model:file-list="fileList"
        list-type="picture-card"
        :http-request="handleHttpReq"
        :on-success="handleSuccess"
        multiple
    >
      <el-icon>
        <Plus/>
      </el-icon>
    </el-upload>
  </div>
</template>

<style scoped>

</style>

文件公共读取配置:https://blog.qcoder.cn/blogDetail/136

点赞图标 0