Vue 3 and Spring Boot with MinIO for File Upload Integration

Begin by seting up a new Vue 3 project using the Vue CLI:

npm install -g @vue/cli
vue create file-upload-app
cd file-upload-app

Install Axios to handle HTTP requests:

npm install axios

Create a reusable file upload component in src/components/FileUploader.vue:

<template>
  <div class="upload-container">
    <input 
      type="file" 
      ref="fileInput" 
      @change="onFileSelected" 
      style="display: none" 
    />
    <button @click="openFilePicker">Select File</button>
    <button @click="uploadSelectedFile" :disabled="!selectedFile">Upload</button>
    <p v-if="uploadStatus">{{ uploadStatus }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  name: 'FileUploader',
  data() {
    return {
      selectedFile: null,
      uploadStatus: ''
    };
  },
  methods: {
    openFilePicker() {
      this.$refs.fileInput.click();
    },
    onFileSelected(event) {
      this.selectedFile = event.target.files[0];
      this.uploadStatus = '';
    },
    async uploadSelectedFile() {
      if (!this.selectedFile) return;

      const formData = new FormData();
      formData.append('document', this.selectedFile);

      try {
        const response = await axios.post('http://localhost:8080/api/upload', formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        });
        this.uploadStatus = 'Success: ' + response.data.message;
        this.selectedFile = null;
        this.$refs.fileInput.value = '';
      } catch (error) {
        this.uploadStatus = 'Error: ' + (error.response?.data?.message || 'Unknown error');
      }
    }
  }
};
</script>

<style scoped>
.upload-container {
  padding: 20px;
  max-width: 400px;
  margin: 0 auto;
}
button {
  margin: 5px;
  padding: 8px 16px;
}
</style>

Backend: Spring Boot Configuration

Add the required dependencies to your pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>8.5.19</version>
    </dependency>
</dependencies>

Configure MinIO connection parameters in application.yml:

minio:
  endpoint: http://localhost:9000
  access-key: minioadmin
  secret-key: minioadmin
  bucket: file-storage-bucket

Create a configuration bean to initialize the MinIO client:

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MinioConfiguration {

    @Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String secretKey;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accessKey, secretKey)
                .build();
    }
}

Implement a REST controller to handle file uploads:

import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@RestController
@RequestMapping("/api/upload")
public class FileUploadController {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucket}")
    private String bucketName;

    @PostMapping
    public ResponseEntity<ResponseMessage> handleFileUpload(@RequestParam("document") MultipartFile file) {
        if (file.isEmpty()) {
            return ResponseEntity.badRequest().body(new ResponseMessage("File is empty"));
        }

        try {
            String objectName = UUID.randomUUID().toString() + "-" + file.getOriginalFilename();
            
            minioClient.putObject(
                PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build()
            );

            return ResponseEntity.ok(new ResponseMessage("File uploaded: " + objectName));
        } catch (Exception e) {
            return ResponseEntity.status(500).body(new ResponseMessage("Upload failed: " + e.getMessage()));
        }
    }

    // Simple response wrapper
    public static class ResponseMessage {
        private String message;

        public ResponseMessage(String message) {
            this.message = message;
        }

        public String getMessage() { return message; }
    }
}

Ensure MinIO is running locally (e.g., via Docker):

docker run -p 9000:9000 --name minio \
  -e "MINIO_ROOT_USER=minioadmin" \
  -e "MINIO_ROOT_PASSWORD=minioadmin" \
  minio/minio server /data

Start the Spring Boot application:

mvn spring-boot:run

Launch the Vue frontend:

npm run dev

Once both services are running, navigate to the Vue app and test the upload functionality. Files will be streamed directly from the browser to MinIO via the Spring Boot gateway.

Tags: vue3 SpringBoot MinIO FileUpload axios

Posted on Fri, 17 Jul 2026 17:08:12 +0000 by phphunger