Minio+Vue+Springboot:网页文件上传-对象文件存储实战

一、场景分析

技术架构

  1. 前端:Vue + Axios
  2. 后端:Spring Boot
  3. 存储:MinIO对象存储

实现步骤

1. Spring Boot配置

在application.yml中添加MinIO配置:

yaml 复制代码
minio:
  url: http://localhost:9000
  access-key: your-access-key
  secret-key: your-secret-key
  bucket-name: mybucket
  secure: false

2. 文件上传实现

前端核心代码:

html 复制代码
<template>
  <div>
    <input type="file" @change="handleFileUpload">
    <button @click="uploadFile">上传</button>
    <div v-if="progress > 0">进度:{{progress}}%</div>
  </div>
</template>

3. 后端处理逻辑

使用MinIO Java Client实现文件存储:

  • 自动创建存储桶
  • 支持多种文件类型
  • 返回可访问URL

最佳实践

  1. 文件命名使用UUID避免重复
  2. 限制上传文件大小
  3. 前端添加文件类型校验
  4. 后端配置CORS策略

二、前端代码(Vue实现)

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>文件上传</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
    <div id="app">
        <div>
            <input type="file" ref="fileInput" @change="onFileSelect">
            <button @click="upload">上传文件</button>
            <div v-if="uploadProgress > 0">
                上传进度:{{ uploadProgress }}%
            </div>
            <div v-if="fileUrl">
                文件地址:<a :href="fileUrl" target="_blank">{{ fileUrl }}</a>
            </div>
        </div>
    </div>

    <script>
        const { createApp } = Vue;
        
        createApp({
            data() {
                return {
                    selectedFile: null,
                    uploadProgress: 0,
                    fileUrl: ''
                };
            },
            methods: {
                onFileSelect(event) {
                    this.selectedFile = event.target.files[0];
                },
                async upload() {
                    if (!this.selectedFile) return;
                    
                    const formData = new FormData();
                    formData.append('file', this.selectedFile);
                    
                    try {
                        const response = await axios.post('/api/upload', formData, {
                            headers: { 'Content-Type': 'multipart/form-data' },
                            onUploadProgress: (progressEvent) => {
                                this.uploadProgress = Math.round(
                                    (progressEvent.loaded * 100) / progressEvent.total
                                );
                            }
                        });
                        
                        this.fileUrl = response.data.url;
                        alert('上传成功!');
                    } catch (error) {
                        console.error('上传失败:', error);
                        alert('上传失败!');
                    }
                }
            }
        }).mount('#app');
    </script>
</body>
</html>

三、Spring Boot配置

application.yml配置示例:

yaml 复制代码
server:
  port: 8080

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

minio:
  url: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket-name: mybucket
  secure: false

四、后端Java代码

FileStorageController.java:

java 复制代码
@RestController
@RequestMapping("/api")
public class FileStorageController {

    @Autowired
    private FileStorageService fileStorageService;

    @PostMapping("/upload")
    public ResponseEntity<Map<String, String>> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            String url = fileStorageService.uploadFile(file);
            return ResponseEntity.ok().body(Collections.singletonMap("url", url));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Collections.singletonMap("error", e.getMessage()));
        }
    }
}

FileStorageService.java:

java 复制代码
@Service
public class FileStorageService {

    @Value("${minio.url}")
    private String minioUrl;
    
    @Value("${minio.access-key}")
    private String accessKey;
    
    @Value("${minio.secret-key}")
    private String secretKey;
    
    @Value("${minio.bucket-name}")
    private String bucketName;

    private MinioClient minioClient;

    @PostConstruct
    public void init() throws Exception {
        minioClient = MinioClient.builder()
                .endpoint(minioUrl)
                .credentials(accessKey, secretKey)
                .build();
                
        createBucketIfNotExists();
    }

    private void createBucketIfNotExists() throws Exception {
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder()
                .bucket(bucketName)
                .build());
        if (!found) {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        }
    }

    public String uploadFile(MultipartFile file) throws Exception {
        String fileName = UUID.randomUUID() + "-" + file.getOriginalFilename();
        
        minioClient.putObject(PutObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .stream(file.getInputStream(), file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
                
        return minioUrl + "/" + bucketName + "/" + fileName;
    }
}

五、系统要求

  1. 添加MinIO Java客户端依赖(pom.xml):
xml 复制代码
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.6</version>
</dependency>
  1. 启动MinIO服务:
bash 复制代码
minio server /data --console-address ":9001"

该方案实现了:

  1. 前端文件上传进度显示
  2. 自动生成唯一文件名
  3. 支持多种文件类型
  4. 返回可直接访问的URL
  5. 完善的异常处理机制

建议根据实际需求添加:

  1. 文件类型白名单校验
  2. 文件大小限制
  3. 用户身份验证
  4. 文件管理功能(删除、列表等)
相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发3 天前
软件工程SOLID 五大设计原则
后端·软件工程