Spring Boot React JS File Upload 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 upload functionality. The tutorial will cover setting up the project, creating a Spring Boot REST API for file upload, 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-upload
    • Name: spring-boot-react-file-upload
    • Description: Full Stack Application with Spring Boot and React for File Upload
    • Package Name: com.example.springbootreactfileupload
    • 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-upload
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── springbootreactfileupload
│   │   │               ├── SpringBootReactFileUploadApplication.java
│   │   │               ├── controller
│   │   │               └── service
│   ├── main
│   │   └── resources
│   │       ├── application.properties
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── springbootreactfileupload
│                       └── SpringBootReactFileUploadApplicationTests.java
└── pom.xml

Step 2: Creating the Backend

2.1 Create the File Upload Service

This service will handle storing the uploaded files on the server.

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

package com.example.springbootreactfileupload.service;

import org.springframework.stereotype.Service;
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.util.UUID;

@Service
public class FileStorageService {

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

    public FileStorageService() {
        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception ex) {
            throw new RuntimeException("Could not create the directory where the uploaded files will be stored.", ex);
        }
    }

    public String storeFile(MultipartFile file) {
        // Normalize file name
        String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();

        try {
            // Copy file to the target location (Replacing existing file with the same name)
            Path targetLocation = this.fileStorageLocation.resolve(fileName);
            Files.copy(file.getInputStream(), targetLocation);

            return fileName;
        } catch (IOException ex) {
            throw new RuntimeException("Could not store file " + fileName + ". Please try again!", ex);
        }
    }
}

Explanation:

  • Path Initialization: The fileStorageLocation is initialized to the "uploads" directory in the project root. This is where the files will be stored.
  • Directory Creation: In the constructor, we create the "uploads" directory if it doesn't exist.
  • File Storage Method: The storeFile method stores the uploaded file with a unique name by appending a UUID to avoid conflicts. It then saves the file in the fileStorageLocation directory.

2.2 Create the File Upload Controller

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

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

package com.example.springbootreactfileupload.controller;

import com.example.springbootreactfileupload.service.FileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

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

    private final FileStorageService fileStorageService;

    @Autowired
    public FileUploadController(FileStorageService fileStorageService) {
        this.fileStorageService = fileStorageService;
    }

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        String fileName = fileStorageService.storeFile(file);
        return ResponseEntity.ok("File uploaded successfully: " + fileName);
    }
}

Explanation:

  • File Upload Endpoint: The /upload endpoint handles POST requests to upload files. It receives a MultipartFile and stores it using the FileStorageService.
  • Response: It returns a success message with the stored file name.

2.3 Update application.properties

Ensure the application.properties file is set up correctly to handle file uploads:

# 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 upload functionality.

3.4.1 Create FileUploadService.js

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

import axios from 'axios';

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

class FileUploadService {
    uploadFile(file) {
        const formData = new FormData();
        formData.append("file", file);

        return axios.post(`${API_BASE_URL}/upload`, formData, {
            headers: {
                "Content-Type": "multipart/form-data",
            },
        });
    }
}

export default new FileUploadService();

Explanation:

  • API Base URL: The base URL for the API endpoints.
  • uploadFile Method: This method takes a file as input, creates a FormData object, and sends a POST request to the backend API to upload the file.

3.4.2 Create FileUploadComponent.js

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

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

const FileUploadComponent = () => {
    const [selectedFile, setSelectedFile] = useState(null);
    const [message, setMessage] = useState('');

    const handleFileChange = (e) => {
        setSelectedFile(e.target.files[0]);
    };

    const handleFileUpload = async (e) => {
        e.preventDefault();
        try {
            const response = await FileUploadService.uploadFile(selectedFile);
            setMessage(response.data);
        } catch (error) {
            setMessage('File upload 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 Upload</div>
                        <div className="card-body">
                            {message && <div className="alert alert-info">{message}</div>}
                            <form onSubmit={handleFileUpload}>
                                <div className="form-group">
                                    <label>Choose file</label>
                                    <input
                                        type="file"
                                        className="form-control"
                                        onChange={handleFileChange}
                                    />
                                </div>
                                <button

 type="submit" className="btn btn-primary mt-3">Upload</button>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default FileUploadComponent;

Explanation:

  • File Selection: The handleFileChange method sets the selected file to the component's state when a file is chosen.
  • File Upload: The handleFileUpload method sends the selected file to the backend API using FileUploadService and handles the response or error messages.
  • UI: The component renders a form with a file input and a submit button. It displays messages based on the file upload result.

3.4.3 Create App.js

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

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

const App = () => {
    return (
        <div className="container">
            <FileUploadComponent />
        </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 SpringBootReactFileUploadApplication class in the src/main/java/com/example/springbootreactfileupload 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 upload 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 upload functionality and created a simple file upload form with React. This setup provides a solid foundation for developing more complex full-stack applications with file upload capabilities.

Comments