Spring Boot + ReactJS: File Upload & Download Example

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


Technologies Used:

Backend:

  • Spring Boot 2.7.0
  • Java 17

Frontend:

  • React 17.0.1
  • Axios 0.27.2
  • Bootstrap 4.4.1

User Interface:



Backend Project Directory:




Frontend Project Directory:




We will build two projects: 

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



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 = ((File) 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 KnowledgefactorydemoApplication {

public static void main(String[] args) {

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




Project 2: react-file-upload-download

package.json

{
"name": "react-file-upload-download",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"axios": "^0.27.2",
"bootstrap": "^4.4.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}



common.js

import axios from "axios";

export default axios.create({
baseURL: "http://localhost:8080",
headers: {
"Content-type": "application/json"
}
});



/services/file.service.js

import http from "../common";

class UploadFilesService {
upload(file, onUploadProgress) {
let formData = new FormData();

formData.append("file", file);

return http.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
onUploadProgress,
});
}

getFiles() {
return http.get("/files");
}

}

export default new UploadFilesService();



/components/file.component.js

import React, { Component } from "react";
import UploadService from "../services/file.service";

export default class UploadFiles extends Component {
constructor(props) {
super(props);
this.selectFile = this.selectFile.bind(this);
this.upload = this.upload.bind(this);

this.state = {
selectedFiles: undefined,
currentFile: undefined,
progress: 0,
message: "",
textValue: "Choose File",
fileInfos: [],
};
}

componentDidMount() {
UploadService.getFiles().then((response) => {
this.setState({
fileInfos: response.data,
});
});
}

selectFile(event) {
this.setState({
selectedFiles: event.target.files,
});
}


upload() {
let currentFile = this.state.selectedFiles[0];

this.setState({
progress: 0,
currentFile: currentFile,
});

UploadService.upload(currentFile, (event) => {
this.setState({
progress: Math.round((100 * event.loaded) / event.total),
});
})
.then((response) => {
this.setState({
message: response.data.message,
});
return UploadService.getFiles();
})
.then((files) => {
this.setState({
fileInfos: files.data
});
})
.catch(() => {
this.setState({
progress: 0,
message: "Failed to upload the file!",
currentFile: undefined,
});
});

this.setState({
selectedFiles: undefined,
});
}

render() {
const {
selectedFiles,
currentFile,
progress,
message,
fileInfos,
} = this.state;

return (
<div>
<div class="form-group">
<input class="form-control"
name="file" onChange={this.selectFile} type="file" />
</div>
<div class="form-group">
<button class="btn btn-dark"
disabled={!selectedFiles}
onClick={this.upload} type="submit">Upload</button>
</div>

{currentFile && (
<div className="progress">
<div
className="progress-bar bg-success"
role="progressbar"
aria-valuenow={progress}
aria-valuemin="0"
aria-valuemax="100"
style={{ width: progress + "%" }}
>
{progress}%
</div>
</div>
)}
<div className="alert alert-light" role="alert">
<p class="text-danger">{message}</p>
</div>

<div className="card">
<div class="btn-group mx-auto">
<h4 class="card-header ">Download the file
</h4>
</div>
<ul className="list-group">
{fileInfos &&
fileInfos.map((file) => (

<a href={`http://localhost:8080/download/${file}`}
class="list-group-item list-group-item-action ">
<li>{file}</li></a>

))}
</ul>
</div>
</div>
);
}
}



App.js

import React from "react";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";

import UploadFiles from "./components/file.component";

function App() {
return (

<div>
<nav class="navbar navbar-dark bg-dark">
<div class="btn-group mx-auto">
<h2 class="text-white">Spring Boot + React JS:
File Upload & Download example</h2>
</div>
</nav><br></br>
<div class="container">
<UploadFiles />
</div></div>
);
}

export default App;



index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

serviceWorker.unregister();



index.css

body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas,
'Courier New',
monospace;
}



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: npm start

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

Popular posts from this blog

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

Spring boot video streaming example-HTML5

Spring Boot + Mockito simple application with 100% code coverage

Spring Boot + OpenCSV Export Data to CSV Example

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Custom Exception Handling in Quarkus REST API

ReactJS, Spring Boot JWT Authentication Example

DataTable-Pagination example with Spring boot, jQuery and ajax

Spring Webflux File Download Example

Node JS mini projects with source code - free download