What is the process of uploading a file to my Spring Boot-based WebService using an Angular 5 client?

I've put in a lot of effort to solve my issue, but unfortunately, I haven't had any success yet.

Currently, I am working with an Angular 5 client and I need to send a file over to my SpringBoot web service so that I can process it on the server side.

This is what my template looks like:

<div class="dropdown-content">
                        <label (click)="openDialog()">Upload from xls</label>
                        <label>Save to xls</label>
                        <label>Link 3</label>
                        <input type="file" class="inputFile" style="display:none" (change)="handleFileInput($event.target.files)">
</div>

I want users to be able to select a file by clicking on the "Upload from xls" label:

openDialog() {
    let myInputFile = <HTMLElement>document.querySelector('.inputFile');
    myInputFile.click();
  }

  //This method is called after choosing a file
  handleFileInput(files: FileList) {
    var file = this.fileToUpload = files.item(0);
    this.uploadFileService.pushFileToStorage(file);
  }

Afterwards, we call this.uploadFileService.pushFileToStorage(file);

@Injectable()
export class UploadFileService {

    constructor(private http: Http, private globals: Globals, private httpClient: HttpClient) { }

    pushFileToStorage(file) {

    let headers = new Headers();
    let options = new RequestOptions({ headers: headers }); // Create header

    let formData = new FormData();
    formData.append('file', file); // Append file to formdata
    console.log(file);

    const req = this.httpClient.post('http://localhost:' + this.globals.tomcatPort + '/utils/saveFromFile', JSON.stringify(formData));

    req.subscribe((data) => {

        console.log(data); // Sucess response
    }, (err: HttpErrorResponse) => {

        // Error response
        if (err.error instanceof Error) {
            //client side error
            console.log('An error occured: ', err.error.message);
        }
        else {
            console.log('Backend returned code', err.status, 'body was ', err.error);
        }
    })

On the WebService side, my StorageController currently looks like this for testing purposes:

    @RestController
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
@RequestMapping("/utils")
public class StorageController {

    @PostMapping(value = "/saveFromFile", consumes = "multipart/form-data", produces = MediaType.APPLICATION_JSON_VALUE)
    public void saveFromFile(@RequestParam("file") MultipartFile multipartFile) {
        System.out.println(multipartFile);
    }

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipart = new CommonsMultipartResolver();
        multipart.setMaxUploadSize(3 * 1024 * 1024);
        return multipart;
    }

    @Bean
    @Order(0)
    public MultipartFilter multipartFilter() {
        MultipartFilter multipartFilter = new MultipartFilter();
        multipartFilter.setMultipartResolverBeanName("multipartReso‌​lver");
        return multipartFilter;
    }
}

Unfortunately, I'm facing the following error:

Failed to load http://localhost:8180/utils/saveFromFile: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.

The CORS issue only arises when trying to send a file.

Thank you in advance! Mateusz

Answer №1

To utilize the UploadFileService, it is necessary to import the following:

import {HttpClient, HttpHeaders} from '@angular/common/http'

When making a POST service call and wanting to include an Authorization header with a specific token, you can achieve this by setting the header in a general manner. Additional headers can also be appended as needed.

 const req = this.httpClient.post('http://localhost:' + 
 this.globals.tomcatPort + '/utils/saveFromFile', JSON.stringify(formData), 
 {headers: new HttpHeaders().set('Authorization', 'Basic jfghghjbhjb')});

If inline headers are not preferred, a separate object can be created for them as shown below:

const headers = new HttpHeaders().set('Authorization', 'Basic jfghghjbhjb')

This object can then be utilized like so:

const req = this.httpClient.post('http://localhost:' + 
     this.globals.tomcatPort + '/utils/saveFromFile', JSON.stringify(formData), 
     {headers: headers});

Answer №2

After much trial and error, I was able to find a simple solution to my problem:

Here is the Angular template code:

<div class="dropdown-content">
                        <label (click)="openDialog()">Upload from xls</label>
                        <label>Save to xls</label>
                        <label>Link 3</label>
                        <input type="file" class="inputFile" style="display:none" (change)="handleFileInput($event)">
                    </div>

In the Angular component:

openDialog() {
    let myInputFile = <HTMLElement>document.querySelector('.inputFile');
    myInputFile.click();
  }

  //This method is called after choosing a file
  handleFileInput(event) {
    var file = this.fileToUpload = <File>event.target.files[0];
    this.uploadFileService.pushFileToStorage(file);
  }

Within the Angular Service:

pushFileToStorage(file) {
        const fd = new FormData();
        fd.append('file', file, file.name);
        this.httpClient.post('http://localhost:' + this.globals.tomcatPort + '/utils/saveFromFile', fd)
            .subscribe(res => {
                this.dataStorageService.getDictionaryItems();
            })
    }

And in the WebService within my Controller:

@PostMapping(value = "/saveFromFile", consumes = "multipart/form-data", produces = MediaType.APPLICATION_JSON_VALUE)
    public void saveFromFile(@RequestParam("file") MultipartFile file) throws IOException {
        File convFile = new File(file.getOriginalFilename());
        convFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(convFile);
        fos.write(file.getBytes());
        fos.close();

        storageService.saveWordsFromFile(convFile);

    }

That's it - everything is now working smoothly!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

leveraging NPM packages within a Modular TypeScript project

In my current project, the frontend is written in namespaced typescript and I am unable to convert all files from namespaced approach to export/import ES6 syntax. Despite this limitation, the existing code works well. As long as I encapsulate new modules ...

Issue encountered when importing a font in TypeScript due to an error in the link tag's crossorigin

How do I troubleshoot a TypeScript error when importing a custom font, such as a Google font? <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> Below is the specific error message: Type 'boolean' is ...

How exactly does the 'this' type in TypeScript determine its own type inferences?

When working with TypeScript, I wanted to use the this keyword to type certain properties of my class. However, I encountered a problem that I couldn't figure out how to solve. What I was trying to achieve is something like this: export class Animal{ ...

Angular 4 prohibits certain special characters and the number zero

Currently, I am a beginner in Angular 4 and I am working on learning how to search for data from a text box. However, whenever I input special characters like "%" in my code, it triggers an error leading to a crash in my application. Is there any effectiv ...

The data source retrieved through the "get" API method is missing from the mat-table

Recently, I've started working with angularCLI and I'm facing an issue in creating a table where the dataSource is fetched from a fake API. Let me share my component class: import { Component, OnInit } from '@angular/core'; import { Fo ...

Enhance your PowerBI dashboards with the ChatGPT Custom Visual!

I am currently working on developing a custom visual for Power BI using TypeScript. This visual includes an input field for user prompts and another input field for ChatGPT answers. The main goal is to allow users to ask questions about the data in their r ...

Presenting tailored information within a structured chart

Working on my angular project, I have a table filled with data retrieved from an API. The table includes a status column with three possible values: 1- Open, 2- Released, 3- Rejected. Current display implemented with the code snippet <td>{{working_pe ...

How can I activate div elements by clicking on a specific div using Angular 2?

I have created a custom component with search dropdown functionality for selecting dates. <div class="search-dropdown calender-dropdown "> <div class="search-dropdown-tabs-wrp"> <ul class="search-dropdown-tabs"> <li& ...

What causes the "This page isn't responding" error to pop up in Edge and Chrome browsers while attempting to perform consecutive tasks in a web application built with Angular 8?

Trouble with Page Loading Whenever this error occurs, I find myself unable to perform any activities on that page. The only solution is to close the tab and open a new one. My current code allows me to navigate through an array list (Next and Previous) us ...

What are some ways to enhance this TypeScript code using Functional Programming with the FP-TS library?

i am struggling to write some typescript code using fp-ts Below are the tasks that i want the algorithm to carry out: Once a path is received from the command line, it should check if the given path exists search for all files in the directory and locat ...

Ways to incorporate conditional checks prior to running class methods

Seeking input on handling async data retrieval elegantly. When initializing a class with asynchronous data, I have been following this approach: class SomeClass { // Disabling strictPropertyInitialization private someProperty: SomeType public asy ...

Queries with MongoDB RegEx fail to return any matches if the search string contains parentheses

When trying to implement case-insensitivity using regex, it seems to work well for plain strings. However, if special characters like parenthesis are involved in the search query for the name, the database returns no results. For example, a search for "Pu ...

I'm having trouble with one of my filter pipes not displaying any results. Can anyone help me troub

I have recently included a new filter for DL, but it seems that the results are not showing up as expected. Any ideas on what changes I should implement? <div class="form-group float-left mr-4"> <strong>DL</strong> <br /> ...

Container that has the ability to store objects conforming to specific interfaces

If you were to envision having three different types of objects, they might look something like this: interface X { testX: someType; } interface Y { testY: someOtherType[]; } interface Z { testZ1: string; testZ2: number; } Now imagine a master o ...

Optimal method for populating table filter values from query string in Typescript while handling asynchronous calls

Using Typescript for Angular, I am dealing with a table that has filters in the form of drop downs. The data for each filter is retrieved asynchronously from the backend. My challenge is to load the data for all filters while setting default values based o ...

Activating the microphone device on the MediaStream results in an echo of one's own voice

I am in the process of creating an Angular application that enables two users to have a video call using the Openvidu calling solution. As part of this application, I have implemented a feature that allows users to switch between different cameras or micr ...

Utilizing ngModel with a Pipe

When attempting to apply a date pipe on an Input element, the following code was initially used: <div class="section"> <h6 style="font-weight:bold">From Date</h6> <input [(ngModel)]="Schedule.FromDate | date:'fullDate' ...

Challenges faced when using an array of objects interface in Typescript

I have initialized an array named state in my component's componentDidMount lifecycle hook as shown below: state{ array:[{a:0,b:0},{a:1,b:1},{a:2,b:2}] } However, whenever I try to access it, I encounter the following error message: Prop ...

Encountering Canvas errors while utilizing TypeScript in the most recent version of VS Code

Currently, I'm working on TypeScript Canvas code for my application and encountering an error message that says: The type 'CanvasRenderingContext2D' does not have the property 'wrapText'.ts(2339) This error is triggered by this li ...

Unable to narrow down the truthiness within nested functions: TypeScript issue

When analyzing the code in the shared playground (Playground Link), the compiler is showing an error indicating that Object is possibly 'null'. Could there be any scenario where the refresh function could be called, leading to a situation where ...