Spring Boot File Upload with Angular

This tutorial will teach us how to upload a file to the Serve-accessible static resources folder using REST APIs created in Spring Boot 3 and consuming those APIs using Angular.

1. Introduction

In this tutorial, we will create a simple FileUpload application with a simple UI created in Angular having one component with an upload button to upload the file to the server and verify that file has been uploaded successfully.

2. File Upload Controller

Let’s create a handler method in the Spring boot application that consumes the multipart POST requests and accepts the MutipartFile file as the parameter containing the file uploaded to the server.

Note that we need to enable the request from the cross-origin “http://localhost:4200” on which our Angular app will be hosted.

@RestController
@Slf4j
@CrossOrigin(origins = "http://localhost:4200")
public class FileUploadController {

  @PostMapping(value = "simple-form-upload-mvc", consumes = MULTIPART_FORM_DATA_VALUE)
  public ResponseEntity<Map<String, String>> handleFileUploadForm(@RequestPart("file") MultipartFile file) throws IOException {

    log.info("handling request parts: {}", file);

    try {
      
      File f = new ClassPathResource("").getFile();
      final Path path = Paths.get(f.getAbsolutePath() + File.separator + "static" + File.separator + "image");

      if (!Files.exists(path)) {
        Files.createDirectories(path);
      }

      Path filePath = path.resolve(file.getOriginalFilename());
      Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);

      String fileUri = ServletUriComponentsBuilder.fromCurrentContextPath()
          .path("/image/")
          .path(file.getOriginalFilename())
          .toUriString();

      var result = Map.of(
          "filename", file.getOriginalFilename(),
          "fileUri", fileUri
      );
      return ok().body(result);

    } catch (IOException e) {
      log.error(e.getMessage());
      return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}

In the given handler method, new ClassPathResource(…).getFile() gives us the folder location where resources directory should be located. We are checking if the ‘static/image’ folder exists at that location or not, and if not, then we are creating it.

Files.copy(…)’ is responsible for consuming the byte stream from the file as an argument and copying over the given location, and replacing if a file with the same name already exists. This code will upload the file to the target/classes/static/image/ as this location is server accessible.

3. Angular Application

To create an Angular app, Node.js and Angular-CLI must be installed on your system. Refer to Spring boot and angular application example to know more about installing and creating an angular app.

Create a new angular application using the below command.

ng new angular-app

? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS

3.1. File Upload Service

Angular Services contain functionality that can be reused across the various angular components. Generally, services are used to make HTTP requests.

In the following example, we create a FileUploadService using the ‘ng g s’ command.

$ ng g s services/file-upload

Edit the file-upload.service.ts and add uploadFile() method, which takes a file as input and calls the REST API to upload that file to the server. Feel free to add more form fields if necessary.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { FileDetails } from '../file-details.model';

@Injectable({
  providedIn: 'root'
})
export class FileUploadService {

  private baseUrl = "http://localhost:8080"
  constructor(private httpClient: HttpClient) { }

  upload(file: File): Observable<FileDetails> {

    const formData: FormData = new FormData();
    formData.append('file', file);
    return this.httpClient.post<FileDetails>(`${this.baseUrl}/simple-form-upload-mvc`, formData);
  }
}

Note that to use HttpClient service, we need to declare HttpClientModule inside imports in app.module.ts.

imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],

The following command generates the FileDetails model.

ng g class FileDetails --type=model
export class FileDetails {
    filename!: string;
    fileUri!: string;
}

3.2. Angular Component and View

Angular components are the building block of angular frameworks, consists HTML and CSS files to design the UI and a typescript class defining behavior for that component.

Create the UploadFileComponent using the following command.

ng g c upload-file

Edit the upload-file.component.html to specify the <input type=”file”> tag and a list of uploaded fileUri.

<div class="container d-flex justify-content-center">
    <div class="mt-5 row justify-content-center">

        <div class="col-10 mb-3">
            <label class="px-3">Select File: </label>
            <input type="file" (change)="selectFile($event)" />
        </div>

        <div class="col-2">
            <button class="btn btn-success btn-sm" (click)="uploadFile()">
                Upload
            </button>
        </div>
    </div>
</div>
<div class="container">
    <div class="mt-5 row justify-content-center">
        <div class="col-10 mb-3">
            <ul>
                <li *ngFor="let link of fileUris">
                    <a href="{{ link }}" target="_blank">{{ link }}</a>
                </li>
            </ul>
        </div>
    </div>
</div>

Edit the upload-file.component.ts to specify the uploadFile() function, which internally calls FileUploadService class’s upload() method responsible for uploading the file to the server.

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FileDetails } from '../file-details.model';
import { FileUploadService } from '../services/file-upload.service';

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

  file!: File;
  fileDetails!: FileDetails;
  fileUris: Array<string> = [];

  constructor(private fileUploadService: FileUploadService, private router: Router) { }

  ngOnInit(): void {
  }

  selectFile(event: any) {
    this.file = event.target.files.item(0);
  }

  uploadFile() {
    this.fileUploadService.upload(this.file).subscribe({
      next: (data) => {
        this.fileDetails = data;
        this.fileUris.push(this.fileDetails.fileUri);
        alert("File Uploaded Successfully")
      },
      error: (e) => {
        console.log(e);
      }
    });
  }

}

After a successful file upload uploadFile() function will add that fileUri to the Arraay<string> which we are using to show details of <li> element in the HTML file.

3.3. Routes

Configure the routes by editing the app-routing.module.ts file as below.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UploadFileComponent } from './upload-file/upload-file.component';

const routes: Routes = [
  { path: 'upload-file', component: UploadFileComponent },
  { path: '', redirectTo: 'upload-file', pathMatch: 'full' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

4. Demo

Run the spring boot app by running the App.java file located in the root folder and the angular app by typing the following command.

ng serve --o

We will get the UI loaded with a file input box. Select any file. We have selected spring.png. Click on the Upload button.

Once the file is uploaded, we will get an alert message.

After pressing the OK button a link to access that file will be displayed on the current page.

Using that link, we can access our file directly from the server.

5. Conclusion

This Spring boot and angular tutorial taught us how to create a REST API that handles the MultipartFile request to upload files and how to invoke such API from the Angular application.

Happy Learning!

Sourcecode on Github

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial