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.