Spring Boot + Angular: File Upload & Download Example

Hello everyone, today we will learn how to upload and download file with Spring Boot and Angular. You can download the source code from our GitHub repository.

Backend Project Directory:


Frontend Project Directory:



We will build two projects: 

1. Backend:  springboot-fileupload-filedownload
2. Frontend: angular-file-upload



Project 1: springboot-file-upload-download

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<!-- lookup parent from repository -->
</parent>
<groupId>com.knowledgefactory</groupId>
<artifactId>springboot-file-upload-download</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-file-upload-download</name>

<properties>
<java.version>17</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- spring mvc, rest -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<description>springboot-file-upload-download</description>
</project>



UploadDownloadService.java

@Service
public class UploadDownloadService {
private static final String path = "/home/user/Desktop/files";

public List<String> uploadFile(MultipartFile file)
throws Exception {

// Save file on system
if (!file.getOriginalFilename().isEmpty()) {

BufferedOutputStream outputStream =
new BufferedOutputStream(
new FileOutputStream(new File(path,
file.getOriginalFilename())));

outputStream.write(file.getBytes());
outputStream.flush();
outputStream.close();

} else {
throw new Exception();
}

List<String> list = new ArrayList<String>();
File files = new File(path);
String[] fileList = files.list();
for (String name : fileList) {
list.add(name);
}

return list;

}

public List<String> getListofFiles() throws Exception {

List<String> list = new ArrayList<String>();
File files = new File(path);
String[] fileList = ((File) files).list();
for (String name : fileList) {
list.add(name);
}

return list;

}
}



FileController.java

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
public class FileController {

private static final String path = "/home/user/Desktop/files/";

@Autowired
UploadDownloadService service;

@PostMapping("/upload")
public ResponseEntity<List<String>> fileUpload
(@RequestParam("file") MultipartFile file)
throws Exception {

return new ResponseEntity<>(service.uploadFile(file),
HttpStatus.OK);

}

@GetMapping(path = "/download/{name}")
public ResponseEntity<Resource> download
(@PathVariable("name") String name) throws IOException {

File file = new File(path + name);
Path path = Paths.get(file.getAbsolutePath());
ByteArrayResource resource =
new ByteArrayResource(Files.readAllBytes(path));

return ResponseEntity.ok().headers(this.headers(name))
.contentLength(file.length())
.contentType(MediaType
.parseMediaType("application/octet-stream"))
.body(resource);
}

@GetMapping("/files")
public ResponseEntity<List<String>> getListOfFiles()
throws Exception {

return new ResponseEntity<>(service.getListofFiles(),
HttpStatus.OK);

}

private HttpHeaders headers(String name) {

HttpHeaders header = new HttpHeaders();
header.add(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + name);
header.add("Cache-Control",
"no-cache, no-store, must-revalidate");
header.add("Pragma", "no-cache");
header.add("Expires", "0");
return header;

}
}



application.properties

spring.servlet.multipart.enabled=true
# Threshold after which files are written to disk.
spring.servlet.multipart.file-size-threshold=2KB
# Max file size.
spring.servlet.multipart.max-file-size=200MB
# Max Request Size
spring.servlet.multipart.max-request-size=215MB



Spring Boot Driver

@SpringBootApplication
public class Application {

public static void main(String[] args) {

SpringApplication
.run(Application.class, args);
}
}




Project 2: angular-file-upload

package.json

{
"name": "angular-file-upload",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.0.0",
"@angular/common": "~13.0.0",
"@angular/compiler": "~13.0.0",
"@angular/core": "~13.0.0",
"@angular/forms": "~13.0.0",
"@angular/platform-browser": "~13.0.0",
"@angular/platform-browser-dynamic": "~13.0.0",
"@angular/router": "~13.0.0",
"rxjs": "~7.4.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.3.9",
"@angular/cli": "~13.0.2",
"@angular/compiler-cli": "~13.0.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~3.10.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.4.3"
}
}


file-upload.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class FileUploadService {
private baseUrl = 'http://localhost:8080';

constructor(private http: HttpClient) { }

upload(file: File): Observable<HttpEvent<any>> {
const formData: FormData = new FormData();

formData.append('file', file);

const req = new HttpRequest('POST', `${this.baseUrl}/upload`, formData, {
reportProgress: true,
responseType: 'json'
});

return this.http.request(req);
}

getFiles(): Observable<any> {
return this.http.get(`${this.baseUrl}/files`);
}
}


app.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular 13 File Upload';
}



app.component.html

<nav class="navbar navbar-dark bg-dark">
<div class="btn-group mx-auto">
<h2 class="text-white">Spring Boot + Angular:
File Upload & Download example</h2>
</div>
</nav>
<br><br>
<div class="container" >
<app-file-upload></app-file-upload>
</div>



file-upload.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpEventType, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { FileUploadService } from 'src/app/services/file-upload.service';

@Component({
selector: 'app-file-upload',
templateUrl: './file-upload.component.html',
styleUrls: ['./file-upload.component.css']
})
export class FileUploadComponent implements OnInit {

selectedFiles?: FileList;
currentFile?: File;
progress = 0;
message = '';

fileInfos?: Observable<any>;

constructor(private uploadService: FileUploadService) { }

ngOnInit(): void {
this.fileInfos = this.uploadService.getFiles();
}

selectFile(event: any): void {
this.selectedFiles = event.target.files;
}

upload(): void {
this.progress = 0;

if (this.selectedFiles) {
const file: File | null = this.selectedFiles.item(0);

if (file) {
this.currentFile = file;

this.uploadService.upload(this.currentFile).subscribe({
next: (event: any) => {
if (event.type === HttpEventType.UploadProgress) {
this.progress = Math.round(100 * event.loaded / event.total);
} else if (event instanceof HttpResponse) {
this.message = event.body.message;
this.fileInfos = this.uploadService.getFiles();
}
},
error: (err: any) => {
console.log(err);
this.progress = 0;

if (err.error && err.error.message) {
this.message = err.error.message;
} else {
this.message = 'Could not upload the file!';
}

this.currentFile = undefined;
}
});
}

this.selectedFiles = undefined;
}
}

}



file-upload.component.html

<div class="row">
<div class="col-8">
<label class="btn btn-default p-0">
<input type="file" (change)="selectFile($event)" />
</label>
</div>

<div class="col-4">
<button class="btn btn-success btn-sm" [disabled]="!selectedFiles" (click)="upload()">
Upload
</button>
</div>
</div>

<div *ngIf="currentFile" class="progress my-3">
<div
class="progress-bar progress-bar-info"
role="progressbar"
attr.aria-valuenow="{{ progress }}"
aria-valuemin="0"
aria-valuemax="100"
[ngStyle]="{ width: progress + '%' }"
>
{{ progress }}%
</div>
</div>

<div *ngIf="message" class="alert alert-secondary" role="alert">{{ message }}</div>

<div class="card mt-3">
<div class="card-header">Download the file</div>
<ul
class="list-group list-group-flush"
*ngFor="let file of fileInfos | async"
>
<li class="list-group-item">
<a href="http://localhost:8080/download/{{ file }}">{{ file }}</a>
</li>
</ul>
</div>



index.html

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SprinBootAngularFileUpload</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4.6.0/dist/css/bootstrap.min.css" />
</head>
<body>
<app-root></app-root>
</body>
</html>


Download the complete source code - click here    

Local Setup and Run the application

Step1: Download or clone the source code from GitHub to a local machine - Click here


Backend


Step 2: mvn clean install


Step 3: Run the Spring Boot application - mvn spring-boot:run


Frontend


Step 4: npm install


Step 5: ng serve --port 8082

From the browser call the endpoint http://localhost:8082/

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete