0
votes

I have an HTML form like this to upload files from front-end to back-end and do some operations:

<button mat-raised-button color="primary" type="button" style='margin-right:20px' (click)="selectFile()">Select File To Upload</button> 
<input #fileUploadInput type="file" id="fileUpload" hidden name="avatar" (change)="fileChangeEvent($event)">
<button mat-raised-button color="primary" type="button" style='margin-right:20px' enctype="multipart/form-data" (click)="uploadFile()">Submit</button>
        
<br><br>
<a class="generate-full-width" style="color: darkred;" *ngIf="fileName"><strong>{{fileName}}</strong></a>

The component.ts is:

export class uploadFileDialog {

  constructor(
    public dialogRef: MatDialogRef<AddProductDialog>,
    private uploadService: UploadService,
    private builder: FormBuilder, public dialog: MatDialog,
    @Inject(MAT_DIALOG_DATA) public data) {
  }

  @ViewChild('fileUploadInput', {static: false})
  fileUploadVariable: ElementRef;
  fileName;
  currentFile: File;
  filesToUpload = [];

  resetFile(){
    this.fileUploadVariable.nativeElement.value = "";
  }

  
  selectFile(){
    this.resetFile();
    let el: HTMLElement = this.fileUploadVariable.nativeElement as HTMLElement;
    el.click();
  }

  fileChangeEvent(fileInput: any) {
    let file = fileInput.target.files[0]
    console.log(file)
    //console.log(file.data.toString());
    this.filesToUpload = [];
    this.filesToUpload.push(file);
    this.fileName = file['name'];
  }

  uploadFile(){
    this.currentFile = this.fileName;
    console.log(this.currentFile);
    this.uploadService.uploadFile(this.currentFile)
      .subscribe((data) => {
        
        console.log(data)
      },
      error => {
        console.log(error)
      });
  }
}

Service.ts is:

uploadFile(file: File): Observable<any> {

    let headers = new HttpHeaders({
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      //'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
      'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
    })

    let options = {headers:headers, observer: 'response'};

    const formData: FormData = new FormData();

    formData.append('file', file);

    //return this.http.post(this.url+'/fileUpload/upload', formData,options)
    const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
      reportProgress: true,
      responseType: 'json'
    });

    return this.http.request(req);
  }

The controller file at Java backend is:

@RestController
@CrossOrigin(origins = "*", allowedHeaders="*", exposedHeaders="Access-Control-Allow-Origin")
@RequestMapping("/fileUpload")

public class FileController {
    
    private final FileService fileService;
     
    @Autowired
    public FileController(FileService fileService) {
        this.fileService = fileService;
    }
 
    @PostMapping(value = "/upload")
    public void handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
        fileService.storeFile(file);
    }}

and the Service File at Java Backend is:

@Service
public class FileService {

    private static final String FILE_DIRECTORY = "D:\\temp";
     
    public void storeFile(MultipartFile file) throws IOException {
        Path filePath = Paths.get(FILE_DIRECTORY + "\" + file.getOriginalFilename());
 
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
    }
    
}

I am able to see the file name when uploading in the console. Also, in the body of the request, the formData is showing the xml file as content in the Networks tab. I Java console, I am getting the error:

2020-12-15 12:26:53.144  WARN 9688 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]

Error in front-end console:

HttpHeaderResponse {headers: HttpHeaders, status: 400, statusText: "OK", url: "http://localhost:8080/fileUpload/upload", ok: false, …}
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
ok: false
status: 400
statusText: "OK"
type: 2
url: "http://localhost:8080/fileUpload/upload"
__proto__: HttpResponseBase

What am I doing wrong?

1
I have struggled with similar issue on backend a while ago. I was using pure JS on front-end back then, but I remember that I fixed it by adding multipart support for dispatcher servlet. If you are using Spring MVC, try adding following multipart properties between servlet XML tags to web.xml: code <multipart-config> <max-file-size>10485760</max-file-size> <max-request-size>20971520</max-request-size> <file-size-threshold>5242880</file-size-threshold> </multipart-config> code If you are using Spring Boot define those values in application.properties - Przemek
@Przemek actually the file size is very low. So will this be needed in this case too? - Karan Saxena
With Spring Boot it is preconfigured I guess, since it has tomcat embedded, but I guess with pure Spring multipart support is not added by default. At least that solution worked in my case. - Przemek
If you can check, are the requests and other coding parts Ok to you? - Karan Saxena

1 Answers

1
votes

You are sending only file name but not actual file blob.

Try to do below changes,

component.ts :

  uploadFile() {
    this.currentFile = this.fileName;
    console.log(this.currentFile, this.filesToUpload[0]);
    this.uploadService.uploadFile(this.currentFile, this.filesToUpload[0])
      .subscribe((data) => {
        console.log(data)
      },
      error => {
        console.log(error)
   });
  }

service.ts

uploadFile(fileName: string, file: File): Observable<any> {

   let headers = new HttpHeaders({
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
   })

  let options = {headers:headers, observer: 'response'};

  const formData: FormData = new FormData();

  formData.append('fileName', fileName);
  formData.append('file', file);

  const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
    reportProgress: true,
    responseType: 'json'
  });

 return this.http.request(req);
}

Please refer this link to know more about formData