Spring Boot React JS File Download Example

In this tutorial, we will create a full-stack application using Spring Boot 3 for the backend and React 18 (using functional components and hooks) for the frontend. We will implement a file download functionality. The tutorial will cover setting up the project, creating a Spring Boot REST API for file download, and building a React application for the same. We will also use Bootstrap for styling.

Prerequisites

Before we start, ensure you have the following:

  • Java Development Kit (JDK) installed
  • Apache Maven installed
  • Node.js and npm installed
  • An IDE (such as IntelliJ IDEA, Eclipse, or VS Code) installed

Step 1: Setting Up the Spring Boot Project

1.1 Create a Spring Boot Project

  1. Open Spring Initializr:

  2. Configure Project Metadata:

    • Project: Maven Project
    • Language: Java
    • Spring Boot: Select the latest version of Spring Boot 3
    • Group: com.example
    • Artifact: spring-boot-react-file-download
    • Name: spring-boot-react-file-download
    • Description: Full Stack Application with Spring Boot and React for File Download
    • Package Name: com.example.springbootreactfiledownload
    • Packaging: Jar
    • Java Version: 17 (or your preferred version)
    • Click Next.
  3. Select Dependencies:

    • On the Dependencies screen, select the dependencies you need:
      • Spring Web
      • Spring Boot DevTools
    • Click Next.
  4. Generate the Project:

    • Click Generate to download the project zip file.
    • Extract the zip file to your desired location.
  5. Open the Project in Your IDE:

    • Open your IDE and import the project as a Maven project.

1.2 Project Structure

After importing the project, you will see the following structure in your IDE:

spring-boot-react-file-download
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── springbootreactfiledownload
│   │   │               ├── SpringBootReactFileDownloadApplication.java
│   │   │               ├── controller
│   │   │               └── service
│   ├── main
│   │   └── resources
│   │       ├── application.properties
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── springbootreactfiledownload
│                       └── SpringBootReactFileDownloadApplicationTests.java
└── pom.xml

Step 2: Creating the Backend

2.1 Create the File Download Service

This service will handle retrieving the files from the server.

In the service package, create a new Java class named FileDownloadService:

package com.example.springbootreactfiledownload.service;

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class FileDownloadService {

    private final Path fileStorageLocation = Paths.get("uploads").toAbsolutePath().normalize();

    public Resource loadFileAsResource(String fileName) {
        try {
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if (resource.exists()) {
                return resource;
            } else {
                throw new RuntimeException("File not found " + fileName);
            }
        } catch (Exception ex) {
            throw new RuntimeException("File not found " + fileName, ex);
        }
    }
}

Explanation:

  • Path Initialization: The fileStorageLocation is initialized to the "uploads" directory in the project root. This is where the files will be stored.
  • Load File Method: The loadFileAsResource method loads a file as a resource by its name. If the file exists, it returns the resource; otherwise, it throws an exception.

2.2 Create the File Download Controller

This controller will expose the REST API endpoint to handle file downloads.

In the controller package, create a new Java class named FileDownloadController:

package com.example.springbootreactfiledownload.controller;

import com.example.springbootreactfiledownload.service.FileDownloadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/files")
public class FileDownloadController {

    private final FileDownloadService fileDownloadService;

    @Autowired
    public FileDownloadController(FileDownloadService fileDownloadService) {
        this.fileDownloadService = fileDownloadService;
    }

    @GetMapping("/download/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
        Resource resource = fileDownloadService.loadFileAsResource(fileName);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }
}

Explanation:

  • File Download Endpoint: The /download/{fileName} endpoint handles GET requests to download files. It receives the file name as a path variable and loads the file as a resource using the FileDownloadService.
  • Response: It returns the file as an attachment in the response.

2.3 Update application.properties

Ensure the application.properties file is set up correctly:

# File upload properties
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB

Step 3: Creating the Frontend with React

3.1 Set Up React Project

  1. Open a terminal and navigate to your workspace directory.

  2. Create a new React project using Create React App:

    npx create-react-app react-frontend
    
  3. Navigate to the project directory:

    cd react-frontend
    

3.2 Install Axios

Install Axios to make HTTP requests:

npm install axios

3.3 Install Bootstrap

Install Bootstrap for styling:

npm install bootstrap

3.4 Create Components

Create the necessary components for the file download functionality.

3.4.1 Create FileDownloadService.js

Create a new file FileDownloadService.js in the src directory to handle API requests:

import axios from 'axios';

const API_BASE_URL = "http://localhost:8080/api/files";

class FileDownloadService {
    downloadFile(fileName) {
        return axios.get(`${API_BASE_URL}/download/${fileName}`, {
            responseType: 'blob',
        });
    }
}

export default new FileDownloadService();

Explanation:

  • API Base URL: The base URL for the API endpoints.
  • downloadFile Method: This method takes a file name as input and sends a GET request to the backend API to download the file.

3.4.2 Create FileDownloadComponent.js

Create a new file FileDownloadComponent.js in the src/components directory:

import React, { useState } from 'react';
import FileDownloadService from '../FileDownloadService';
import 'bootstrap/dist/css/bootstrap.min.css';

const FileDownloadComponent = () => {
    const [fileName, setFileName] = useState('');
    const [message, setMessage] = useState('');

    const handleFileChange = (e) => {
        setFileName(e.target.value);
    };

    const handleFileDownload = async (e) => {
        e.preventDefault();
        try {
            const response = await FileDownloadService.downloadFile(fileName);
            const url = window.URL.createObjectURL(new Blob([response.data]));
            const link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', fileName);
            document.body.appendChild(link);
            link.click();
            setMessage('File downloaded successfully!');
        } catch (error) {
            setMessage('File download failed!');
        }
    };

    return (
        <div className="container mt-5">
            <div className="row justify-content-center">
                <div className="col-md-6">
                    <div className="card">
                        <div className="card-header">File Download</div>
                        <div className="card-body">
                            {message && <div className="alert alert-info">{message}</div>}
                            <form onSubmit={handleFileDownload}>
                                <div className="form-group">
                                    <label>Enter file name</label>
                                    <input
                                        type="text"
                                        className="form-control"
                                        value={fileName}
                                        onChange={handleFileChange}
                                    />
                                </div>
                                <button type="submit" className="btn btn-primary mt-3

">Download</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default FileDownloadComponent;

Explanation:

  • File Name Input: The handleFileChange method sets the file name to the component's state when a file name is entered.
  • File Download: The handleFileDownload method sends the file name to the backend API using FileDownloadService and handles the response or error messages. If the download is successful, it creates a link to download the file and triggers a click event to download it.
  • UI: The component renders a form with an input for the file name and a submit button. It displays messages based on the file download result.

3.4.3 Create App.js

Modify the App.js file to include the file download component:

import React from 'react';
import FileDownloadComponent from './components/FileDownloadComponent';
import 'bootstrap/dist/css/bootstrap.min.css';

const App = () => {
    return (
        <div className="container">
            <FileDownloadComponent />
        </div>
    );
};

export default App;

3.4.4 Update index.js

Ensure the index.js file is set up correctly:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';

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

Step 4: Running the Application

4.1 Run the Spring Boot Application

  1. Open the SpringBootReactFileDownloadApplication class in the src/main/java/com/example/springbootreactfiledownload directory.
  2. Click the green Run button in your IDE or use the terminal to run the application:
    ./mvnw spring-boot:run
    

4.2 Run the React Application

  1. Open a terminal and navigate to the react-frontend directory.

  2. Start the React application:

    npm start
    
  3. Open your web browser and navigate to http://localhost:3000.

You can now use the file download functionality provided by the React frontend and Spring Boot backend.

Conclusion

In this tutorial, we created a full-stack application using Spring Boot for the backend and React (with functional components and hooks) for the frontend. We implemented a file download functionality and created a simple file download form with React. This setup provides a solid foundation for developing more complex full-stack applications with file download capabilities.

Comments