This tutorial shows a step by step solution to Angular file upload Spring Boot backend and store it on file system. We will cover a file upload from a basic input and also from a drag-drop area.
Table of contents
Server side
This section covers the Spring Boot server implementation
Spring Boot Controller
Our Spring Boot application exposes a single endpoint to upload files. Below it’s content :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.roufid.tutorials.controller; import com.roufid.tutorials.service.FileService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @RestController public class FileController { private final FileService fileService; @Autowired public FileController(FileService fileService) { this.fileService = fileService; } @PostMapping(value = "/api/files") @ResponseStatus(HttpStatus.OK) public void handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException { fileService.storeFile(file); } } |
- @RestController is used to make the Java Class handle HTTP requests. @RestController is a shortcut of the combination of @Controller along with @ResponseBody.
- The controller handles one POST HTTP request. The file is sent a request parameter named “file” of type MultipartFile
The controller is as simple as you see. Let’s see now the FileService.
Spring Component FileService
We extracted the logic of storing the file a Spring Component FileService. Below it’s content :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.roufid.tutorials.service; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @Component public class FileService { private static final String FILE_DIRECTORY = "/var/files"; public void storeFile(MultipartFile file) throws IOException { Path filePath = Paths.get(FILE_DIRECTORY + "/" + file.getOriginalFilename()); Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); } } |
That’s it for server side. Let’s see now the front end implementation.
Client side with Angular
Angular CLI is used to create the Angular application along with ng2-file-upload module to handle file upload from client side.
Angular Module
First, add the FileUploadModule to app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import {FileUploadModule} from 'ng2-file-upload'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, FileUploadModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
Angular component
Our main component contains a input of type “file” and a drag-and-drop area :
- app.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<h1>Roufid File upload tutorial</h1> <div> <input #fileInput type="file" ng2FileSelect [uploader]="uploader"/> <div class="drop-box" ng2FileDrop [ngClass]="{'dragover': isDropOver}" [uploader]="uploader" (fileOver)="fileOverAnother($event)" (click)="fileClicked()"> <span class="drag-in-title">Import or drag file here</span> <span class="drag-over-title">Drop the file</span> </div> </div> <router-outlet></router-outlet> |
A CSS is added to make the look and feel pretty
- app.component.scss
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
.drop-box { cursor: pointer; background: #F8F8F8; border: 5px dashed #DDD; text-align: center; padding: 40px; } .drag-over-title { display: none; } .drop-box.dragover { opacity: 0.6; } .drop-box.dragover .drag-over-title { display: block; } .drop-box.dragover .drag-in-title { display: none; } input[type='file'] { display: none; } |
- app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import {FileUploader} from 'ng2-file-upload'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { @ViewChild('fileInput') fileInput: ElementRef; uploader: FileUploader; isDropOver: boolean; ngOnInit(): void { const headers = [{name: 'Accept', value: 'application/json'}]; this.uploader = new FileUploader({url: 'api/files', autoUpload: true, headers: headers}); this.uploader.onCompleteAll = () => alert('File uploaded'); } fileOverAnother(e: any): void { this.isDropOver = e; } fileClicked() { this.fileInput.nativeElement.click(); } } |
The tutorial source code is available on Github. Download the source