CODE WITH SIBIN

Solving Real Problems with Real Code


Spring Boot + Vue.js File Upload, Download, List, and Delete Example

This guide will walk you through creating a full-stack application with Spring Boot backend and Vue.js frontend for file management operations.

Backend (Spring Boot)

1. Create Spring Boot Project

Use Spring Initializr (https://start.spring.io/) with these dependencies:

  • Spring Web
  • Spring Data JPA
  • H2 Database (or your preferred database)

2. File Entity

@Entity
public class FileEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String fileName;
    private String fileType;
    
    @Lob
    private byte[] data;
    
    // Constructors, getters, and setters
}

3. File Repository

public interface FileRepository extends JpaRepository<FileEntity, Long> {
}

4. File Service

@Service
public class FileStorageService {
    
    @Autowired
    private FileRepository fileRepository;
    
    public FileEntity store(MultipartFile file) throws IOException {
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());
        FileEntity fileEntity = new FileEntity();
        fileEntity.setFileName(fileName);
        fileEntity.setFileType(file.getContentType());
        fileEntity.setData(file.getBytes());
        
        return fileRepository.save(fileEntity);
    }
    
    public FileEntity getFile(Long id) {
        return fileRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("File not found with id " + id));
    }
    
    public List<FileEntity> getAllFiles() {
        return fileRepository.findAll();
    }
    
    public void deleteFile(Long id) {
        fileRepository.deleteById(id);
    }
}

5. File Controller

@RestController
@RequestMapping("/api/files")
@CrossOrigin(origins = "http://localhost:8081") // Vue.js default port
public class FileController {
    
    @Autowired
    private FileStorageService storageService;
    
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        try {
            storageService.store(file);
            return ResponseEntity.ok("File uploaded successfully: " + file.getOriginalFilename());
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED)
                    .body("Could not upload the file: " + file.getOriginalFilename() + "!");
        }
    }
    
    @GetMapping
    public ResponseEntity<List<FileEntity>> getListFiles() {
        List<FileEntity> files = storageService.getAllFiles();
        return ResponseEntity.ok(files);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<byte[]> getFile(@PathVariable Long id) {
        FileEntity fileEntity = storageService.getFile(id);
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, 
                        "attachment; filename=\"" + fileEntity.getFileName() + "\"")
                .body(fileEntity.getData());
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<String> deleteFile(@PathVariable Long id) {
        try {
            storageService.deleteFile(id);
            return ResponseEntity.ok("File deleted successfully!");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED)
                    .body("Could not delete the file!");
        }
    }
}

Frontend (Vue.js)

1. Create Vue.js Project

vue create file-upload-frontend
cd file-upload-frontend
npm install axios vue-axios

2. File Service (src/services/FileService.js)

import axios from 'axios';

const API_URL = 'http://localhost:8080/api/files';

class FileService {
    upload(file) {
        let formData = new FormData();
        formData.append("file", file);
        
        return axios.post(API_URL + "/upload", formData, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        });
    }
    
    getFiles() {
        return axios.get(API_URL);
    }
    
    downloadFile(id) {
        return axios.get(API_URL + `/${id}`, { responseType: 'blob' });
    }
    
    deleteFile(id) {
        return axios.delete(API_URL + `/${id}`);
    }
}

export default new FileService();

3. File List Component (src/components/FileList.vue)

<template>
  <div>
    <h2>File List</h2>
    <table class="table">
      <thead>
        <tr>
          <th>File Name</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="file in files" :key="file.id">
          <td>{{ file.fileName }}</td>
          <td>
            <button @click="downloadFile(file.id)" class="btn btn-primary">Download</button>
            <button @click="deleteFile(file.id)" class="btn btn-danger">Delete</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script>
import FileService from '../services/FileService';

export default {
  name: 'FileList',
  data() {
    return {
      files: []
    };
  },
  methods: {
    getFiles() {
      FileService.getFiles().then(response => {
        this.files = response.data;
      });
    },
    downloadFile(id) {
      FileService.downloadFile(id).then(response => {
        const url = window.URL.createObjectURL(new Blob([response.data]));
        const link = document.createElement('a');
        link.href = url;
        link.setAttribute('download', this.files.find(f => f.id === id).fileName);
        document.body.appendChild(link);
        link.click();
      });
    },
    deleteFile(id) {
      if (confirm('Are you sure you want to delete this file?')) {
        FileService.deleteFile(id).then(() => {
          this.getFiles();
        });
      }
    }
  },
  mounted() {
    this.getFiles();
  }
};
</script>

4. File Upload Component (src/components/FileUpload.vue)

<template>
  <div>
    <h2>Upload File</h2>
    <div>
      <input type="file" ref="file" @change="handleFileUpload" />
      <button @click="submitFile" class="btn btn-success">Upload</button>
    </div>
    <div v-if="message" class="alert alert-info mt-3">{{ message }}</div>
  </div>
</template>

<script>
import FileService from '../services/FileService';

export default {
  name: 'FileUpload',
  data() {
    return {
      file: null,
      message: ''
    };
  },
  methods: {
    handleFileUpload() {
      this.file = this.$refs.file.files[0];
    },
    submitFile() {
      if (!this.file) {
        this.message = 'Please select a file first!';
        return;
      }
      
      FileService.upload(this.file)
        .then(() => {
          this.message = 'File uploaded successfully!';
          this.$refs.file.value = '';
          this.$emit('file-uploaded');
        })
        .catch(() => {
          this.message = 'Failed to upload file!';
        });
    }
  }
};
</script>

5. App Component (src/App.vue)

<template>
  <div id="app" class="container mt-5">
    <h1>File Management System</h1>
    <FileUpload @file-uploaded="refreshList" />
    <FileList ref="fileList" />
  </div>
</template>

<script>
import FileUpload from './components/FileUpload.vue';
import FileList from './components/FileList.vue';

export default {
  name: 'App',
  components: {
    FileUpload,
    FileList
  },
  methods: {
    refreshList() {
      this.$refs.fileList.getFiles();
    }
  }
};
</script>

<style>
.container {
  max-width: 800px;
}
</style>

Running the Application

  1. Start the Spring Boot application
  2. In another terminal, start the Vue.js application:
npm run serve

Key Features

  1. File Upload: Select a file and upload it to the server
  2. File List: View all uploaded files in a table
  3. File Download: Download any file from the server
  4. File Delete: Remove files from the server

Leave a Reply

Your email address will not be published. Required fields are marked *