在 Angular 2 和 Spring MVC 中上传带有其他表单字段的文件

Posted

技术标签:

【中文标题】在 Angular 2 和 Spring MVC 中上传带有其他表单字段的文件【英文标题】:Uploading file with other form fields in Angular 2 and Spring MVC 【发布时间】:2017-08-21 05:33:23 【问题描述】:

我正在尝试从我的 Angular 2 前端上传文件和其他表单字段内容到 Spring 后端。但不知何故,我无法做到。这是我的代码:

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;


现在在后端:

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)

那么,如何在 spring 控制器中获取 info 标记的数据?上面我已经展示了我的尝试是错误的,那么获取其他表单字段数据的正确方法是什么?

应该如何定义带有注释的Controller方法,或者是否有其他方式从Angular 2发送数据(文件+表单字段)?

【问题讨论】:

这有什么问题? @RomanC 我无法在我的 spring 控制器中获取数据。我可以使用 RequestParam 单独获取带有 RequestParam 的文件和其他表单字段,但是如何单独获取整个模型和文件或将它们全部获取? 它适用于我,但我需要从 POST 请求中删除“选项”,如下所示:this.http.post(this.url,formData) 【参考方案1】:

你需要使用@RequestPart而不是@RequestParam并设置consumes属性:

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

您还需要调整您的FormData 对象:

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

【讨论】:

尝试并收到此错误:- HTTP 状态 400 - 所需的请求部分“信息”不存在 成功了...谢谢,您知道我是否可以将所有这些(文件+数据)一起发送吗?而不是单独追加? @Dishank 不客气。我不认为你可以一起发送它们,FormData 中必须有两个单独的对象,一个用于文件,另一个用于 JSON 对象。 @StefanSvrkota 我尝试了这种方法来解决与此非常相似的问题。但它没有用。我将@RequestParam 更改为@RequestPart。但我仍然收到Required request part 'file' is not present" 错误。你能看看下面的问题吗? ***.com/questions/44139831/…. 它对我有用,但我需要从 POST 请求中删除“选项”,如下所示:this.http.post(this.url,formData)【参考方案2】:

这是我的解决方案:

Content-Type 留空非常重要。如果您将“Content-Type”设置为“multipart/form-data”,则上传将不起作用!

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)
                 );
        
    

【讨论】:

【参考方案3】:

我正在尝试使用 formData 将 myobject 和 angular 2 格式的文件发送到 websphere 上部署的 spring mvc:

ao.component.ts 是:

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)
  );

服务是:

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))

我的春季服务是:

@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);

    

现在使用 tomcat 和 mysql 可以正常工作,但是一旦在 web sphere 上部署,我就会遇到问题:[03/01/18 10:21:50:148 GMT] 0000008c srt W com.ibm.ws.webcontainer.srt .SRTServletResponse setHeader SRVE8094W: AVERTISSEMENT : 无法确定。 La réponse a déjà été validée。

在控制台中: POST http://localhost:4200/gtaows/services/uploadfile 415(不支持的媒体类型)

谢谢,

【讨论】:

在您的服务中删除 Content-type 后尝试。据我所知,在处理文件上传时,您需要将其保留为空。 删除内容类型时出现错误“错误 400: SRVE0295E: “错误请求”

以上是关于在 Angular 2 和 Spring MVC 中上传带有其他表单字段的文件的主要内容,如果未能解决你的问题,请参考以下文章

带有angular2的spring mvc(rest)导致302暂时移动

来自 angular-ui-router 和 spring mvc 的请求映射

Spring 5 MVC Angular 5 App投掷404错误

从现有数据库生成 Angular 5 和 Spring mvc CRUD 应用程序 [关闭]

Angular 6 - Spring MVC :: Options preflight request throws 500 internal Server Error

Spring Security + Angular JS + Spring MVC Rest