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. 文件管理功能(删除、列表等)
相关推荐
August_._5 分钟前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle
间彧21 分钟前
云原生,与云计算、云服务的区别与联系
后端
canonical_entropy1 小时前
最小信息表达:从误解到深层理解的五个关键点
后端·架构
郝开1 小时前
Spring Boot 2.7.18(最终 2.x 系列版本):版本概览;兼容性与支持;升级建议;脚手架工程搭建
java·spring boot·后端
天若有情6732 小时前
新闻通稿 | 软件产业迈入“智能重构”新纪元:自主进化、人机共生与责任挑战并存
服务器·前端·后端·重构·开发·资讯·新闻
清水3 小时前
Spring Boot企业级开发入门
java·spring boot·后端
星释3 小时前
Rust 练习册 :Proverb与字符串处理
开发语言·后端·rust
ZZHHWW4 小时前
RocketMQ vs Kafka01 - 存储架构深度对比
后端
依_旧4 小时前
MySQL下载安装配置(超级超级入门级)
java·后端
熊小猿5 小时前
RabbitMQ死信交换机与延迟队列:原理、实现与最佳实践
开发语言·后端·ruby