Uploading file with other form fields in Angular 2

2019-02-07 11:14发布

问题:

I am trying to upload file and other form field contents from my Angular 2 front end to Spring back end. But somehow I am not able to do it. Here is my code:

app.component.ts

fileChange(e){
    this.fileList = e.target.files;
  }

uploadPdf(){
    if(this.fileList.length>0){
      let file: File = this.fileList[0];
      let formData:FormData = new FormData();

      formData.append('uploadFile', file, file.name);
      formData.append('info',this.model);

      console.log(file.size);

      let headers = new Headers();
      headers.append('Accept', 'application/json');
      let options = new RequestOptions({ headers: headers });
      this.http.post(this.url,formData, options)
        /*.map((res: Response) => res.json())*/
        .catch(error => Observable.throw(error))
        .subscribe(
          data =>{
            this.data = data;
            console.log(this.data);
          }
          ,
          error => console.log(error)
        )
    }
  }

app.cmoponent.html

<h1 class="text-center">
  PDF Viewer and Uploader Example
</h1>
<div class="text-center">
  <form enctype="multipart/form-data">
    <div class="form-group">
      <label for="name">Name: </label>
      <input type="text" id="name" class="form-control" name="name" [(ngModel)]="model.name">
    </div>
    <div class="form-group">
      <label for="email">Email: </label>
      <input type="email" id="email" class="form-control" name="email" [(ngModel)]="model.email">
    </div>
    <div class="form-group">
      <label for="pdfInput">Select File: </label>
      <input type="file" id="pdfInput" class="form-control" name="pdfInput" (change)="fileChange($event)">
    </div>
    <div class="form-group">
      <button type="button" class="btn btn-success" (click)="uploadPdf()">Upload File!</button><span>   </span>
      <button type="button" class="btn btn-success" (click)="printData()">Print to Console!</button>
    </div>
  </form>
</div>

model.ts

export class Model{

  name: string;
  email: string;

}

Now in Backend:

ExampleModel.java

public class ExampleModel {

private String name;
private String email;
//Getters and Setters

MainController.java

@RequestMapping(value = "/file",method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> addUser(@RequestParam("uploadFile") MultipartFile file, @RequestParam("info") ExampleModel model){}

So, how to get that info labeled data in the spring controller? Above I have shown my attempt which is wrong so, what is the correct approach to get other form fields data?

How the Controller method with annotations should be defined or is there other way to send data(both file + form fields) from Angular 2?

回答1:

You need to use @RequestPart instead of @RequestParam and set consumes attribute:

@RequestMapping(value = "/file",method = RequestMethod.POST, consumes = "multipart/form-data")
@ResponseBody
public ResponseEntity<String> addUser(@RequestPart("uploadFile") MultipartFile file, @RequestPart("info") ExampleModel model){}

You also need to adjust your FormData object:

formData.append('uploadFile', file, file.name);
formData.append('info', new Blob([JSON.stringify(this.model)],
        {
            type: "application/json"
        }));


回答2:

i'm tryning to use formData to send both myobject and a file form angular 2 to spring mvc deploed on websphere:

ao.component.ts is:

let input=new FormData();
    input.append('appelOffre', new Blob([JSON.stringify(appelOffre)],
        {
            type: "application/json"
        }));
    input.append('compteRendu',file);

    this._aoService.uploadAppelOffre(input)
    .subscribe(
      data => console.log('success'),
      error => console.log(error)
  );

service is:

uploadAppelOffre(input : FormData):  Observable<number>{

  const headers = new Headers();
  const cpHeaders = new Headers({ 'Content-Type': 'application/json' });
  const options = new RequestOptions({ headers: cpHeaders });
  return this.http.post(this.uploadUrl, input, options)
  .map(this.extractData)
  .catch(error => Observable.throw(error))

}

ang my spring service is:

@RequestMapping(value="uploadfile", method=RequestMethod.POST, consumes={"multipart/form-data"} )
    @ResponseBody
    public ResponseEntity<Void> addFile(@RequestPart("compteRendu") MultipartFile file, @RequestPart("appelOffre") AppelOffre ao){

        if(!file.isEmpty()){
            System.out.println("accepted: "+file.getOriginalFilename());
            File convFile = new File( file.getOriginalFilename());
            try {
                file.transferTo(convFile);
                ao.setLien_alfresco_cr(convFile.getAbsolutePath());
               // service.addAppelOffre(ao);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return new ResponseEntity<Void>(HttpStatus.CREATED);

    }

Now using tomcat and mysql it works fine , but once deploed on web sphere i get the problem: [03/01/18 10:21:50:148 GMT] 0000008c srt W com.ibm.ws.webcontainer.srt.SRTServletResponse setHeader SRVE8094W: AVERTISSEMENT : Impossible de définir l'en-tête. La réponse a déjà été validée.

and in console: POST http://localhost:4200/gtaows/services/uploadfile 415 (Unsupported Media Type)

thx,



回答3:

Here is my solution :

It is very important to leave the Content-Type empty. If you set the 'Content-Type' to 'multipart/form-data' the upload will not work !

upload.component.html

<input type="file" (change)="fileChange($event)" name="file" />

upload.component.ts

  fileChange(event): void {
        const fileList: FileList = event.target.files;
        if (fileList.length > 0) {
            const file = fileList[0];

            const formData = new FormData();
            formData.append('file', file, file.name);

            const headers = new Headers();
            // It is very important to leave the Content-Type empty
            // do not use headers.append('Content-Type', 'multipart/form-data');
            headers.append('Authorization', 'Bearer ' + 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9....');
            const options = new RequestOptions({headers: headers});

            this.http.post('https://api.mysite.com/uploadfile', formData, options)
                 .map(res => res.json())
                 .catch(error => Observable.throw(error))
                 .subscribe(
                     data => console.log('success'),
                     error => console.log(error)
                 );
        }
    }