Vue + Spring Boot: Document Batch Upload Design
🧩 Scenario
You are building a batch document upload feature with the following requirements:
- Each file has its own metadata:
originalFileName,title - The group of files shares metadata:
description,tags,categoryId,accessLevel - When submitted, Spring Boot backend stores group metadata to
upload_groupstable and each file todocumentstable, along with related tables likedocument_tags,document_categories
🖼️ Vue.js Frontend
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const files = ref([])
const fileMetadataList = ref([]) // [{ originalFileName, title }]
const groupMetadata = ref({
description: '',
tags: ['AI', 'Spring Boot'],
categoryId: 1,
accessLevel: 'PRIVATE'
})
const handleSubmit = async () => {
const formData = new FormData()
files.value.forEach((file) => {
formData.append('files', file)
})
const payload = {
documents: fileMetadataList.value,
...groupMetadata.value
}
formData.append('requestJson', new Blob([JSON.stringify(payload)], { type: 'application/json' }))
await axios.post('/api/documents/batch-upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
}
</script>
🧾 JSON structure sent as requestJson
{
"description": "Batch upload of AI reports",
"tags": ["AI", "Spring Boot"],
"categoryId": 1,
"accessLevel": "PRIVATE",
"documents": [
{ "originalFileName": "doc1.pdf", "title": "AI Summary Report" },
{ "originalFileName": "doc2.pdf", "title": "Spring Boot Best Practices" }
]
}
🎯 Spring Boot Backend
📦 DTOs
public class DocumentMetadata {
private String originalFileName;
private String title;
// Getters and setters
}
public class DocumentBatchUploadRequest {
private String description;
private List<String> tags;
private Long categoryId;
private String accessLevel;
private List<DocumentMetadata> documents;
// Getters and setters
}
🛠️ Controller
@PostMapping(value = "/batch-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> uploadDocuments(
@RequestPart("requestJson") DocumentBatchUploadRequest request,
@RequestPart("files") List<MultipartFile> files
) {
Long groupId = uploadGroupService.saveOrUpdate(
request.getDescription(),
request.getTags(),
request.getCategoryId(),
request.getAccessLevel()
);
for (int i = 0; i < files.size(); i++) {
MultipartFile file = files.get(i);
DocumentMetadata meta = request.getDocuments().get(i);
documentService.saveOrUpdate(
file,
meta.getOriginalFileName(),
meta.getTitle(),
groupId,
request.getTags(),
request.getCategoryId(),
request.getAccessLevel()
);
}
return ResponseEntity.ok("Batch upload successful");
}
🧱 Database Design Suggestions
- upload_groups: id, description, tags (JSON or tag join table), category_id, access_level
- documents: id, group_id (FK), title, file_path, original_file_name, category_id, access_level
- document_tags: document_id, tag
- document_categories: optional join table or FK in
documents
✅ Summary
- Vue: Collect file and metadata, send as
FormData - Spring Boot: Parse
@RequestPartJSON and file parts - Database: Save group first, then each document linked to group
📌 Optional Enhancements
- Progress bar UI with Axios upload progress
- Asynchronous processing using Kafka or ExecutorService
- Cloud file storage (S3, OSS, etc.)
- Comprehensive validation and error handling
